merge the last green changeset on m-c to fx-team

This commit is contained in:
Tim Taubert 2011-09-27 04:08:27 +02:00
commit 50195fe347
44 changed files with 1900 additions and 989 deletions

View File

@ -173,6 +173,12 @@ XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () {
} }
}); });
XPCOMUtils.defineLazyGetter(this, "InspectorUI", function() {
let tmp = {};
Cu.import("resource:///modules/inspector.jsm", tmp);
return new tmp.InspectorUI(window);
});
let gInitialPages = [ let gInitialPages = [
"about:blank", "about:blank",
"about:privatebrowsing", "about:privatebrowsing",
@ -180,7 +186,6 @@ let gInitialPages = [
]; ];
#include browser-fullZoom.js #include browser-fullZoom.js
#include ../../devtools/highlighter/inspector.js
#include browser-places.js #include browser-places.js
#include browser-tabPreviews.js #include browser-tabPreviews.js
#include browser-tabview.js #include browser-tabview.js
@ -1676,7 +1681,8 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
TabView.init(); TabView.init();
// Enable Inspector? // Enable Inspector?
if (InspectorUI.enabled) { let enabled = gPrefService.getBoolPref("devtools.inspector.enabled");
if (enabled) {
document.getElementById("menu_pageinspect").hidden = false; document.getElementById("menu_pageinspect").hidden = false;
document.getElementById("Tools:Inspect").removeAttribute("disabled"); document.getElementById("Tools:Inspect").removeAttribute("disabled");
#ifdef MENUBAR_CAN_AUTOHIDE #ifdef MENUBAR_CAN_AUTOHIDE
@ -1724,6 +1730,9 @@ function BrowserShutdown() {
if (!gStartupRan) if (!gStartupRan)
return; return;
if (!__lookupGetter__("InspectorUI"))
InspectorUI.destroy();
// First clean up services initialized in BrowserStartup (or those whose // First clean up services initialized in BrowserStartup (or those whose
// uninit methods don't depend on the services having been initialized). // uninit methods don't depend on the services having been initialized).
allTabs.uninit(); allTabs.uninit();

View File

@ -232,7 +232,6 @@
noautohide="true" noautohide="true"
titlebar="normal" titlebar="normal"
close="true" close="true"
onpopuphiding="InspectorUI.closeInspectorUI();"
label="&inspectPanelTitle.label;"> label="&inspectPanelTitle.label;">
<hbox id="tree-panel-resizer-box" align="end"> <hbox id="tree-panel-resizer-box" align="end">
<spacer flex="1" /> <spacer flex="1" />

View File

@ -125,6 +125,9 @@ InsideOutBoxView = {
* The box object containing the InsideOutBox. Required to add/remove * The box object containing the InsideOutBox. Required to add/remove
* children during box manipulation (toggling opened or closed). * children during box manipulation (toggling opened or closed).
*/ */
var EXPORTED_SYMBOLS = ["InsideOutBox"];
function InsideOutBox(aView, aBox) function InsideOutBox(aView, aBox)
{ {
this.view = aView; this.view = aView;
@ -450,7 +453,7 @@ InsideOutBox.prototype =
try { try {
this.box.removeChild(this.rootObjectBox); this.box.removeChild(this.rootObjectBox);
} catch (exc) { } catch (exc) {
InspectorUI._log("this.box.removeChild(this.rootObjectBox) FAILS " + this.view._log("this.box.removeChild(this.rootObjectBox) FAILS " +
this.box + " must not contain " + this.rootObjectBox); this.box + " must not contain " + this.rootObjectBox);
} }
} }
@ -643,4 +646,18 @@ InsideOutBox.prototype =
return node; return node;
}, },
/**
* Clean up our mess.
*/
destroy: function IOBox_destroy()
{
delete this.view;
delete this.box;
delete this.rootObject;
delete this.rootObjectBox;
delete this.selectedObjectBox;
delete this.highlightedObjectBox;
delete this.scrollIntoView;
}
}; };

View File

@ -45,7 +45,10 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk include $(DEPTH)/config/autoconf.mk
EXTRA_JS_MODULES = \ EXTRA_JS_MODULES = \
inspector.jsm \
domplate.jsm \ domplate.jsm \
InsideOutBox.jsm \
TreePanel.jsm \
$(NULL) $(NULL)
ifdef ENABLE_TESTS ifdef ENABLE_TESTS

View File

@ -0,0 +1,779 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* ***** 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 the Mozilla Tree Panel.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Rob Campbell <rcampbell@mozilla.com> (original author)
* Mihai Șucan <mihai.sucan@gmail.com>
* Julian Viereck <jviereck@mozilla.com>
* Paul Rouget <paul@mozilla.com>
* Kyle Simpson <getify@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 Cu = Components.utils;
Cu.import("resource:///modules/domplate.jsm");
Cu.import("resource:///modules/InsideOutBox.jsm");
Cu.import("resource:///modules/Services.jsm");
var EXPORTED_SYMBOLS = ["TreePanel"];
const INSPECTOR_URI = "chrome://browser/content/inspector.html";
/**
* TreePanel
* A container for the Inspector's HTML Tree Panel widget constructor function.
* @param aContext nsIDOMWindow (xulwindow)
* @param aIUI global InspectorUI object
*/
function TreePanel(aContext, aIUI) {
this._init(aContext, aIUI);
};
TreePanel.prototype = {
showTextNodesWithWhitespace: false,
id: "treepanel", // DO NOT LOCALIZE
openInDock: true,
/**
* The tree panel container element.
* @returns xul:panel|xul:vbox|null
* xul:panel is returned when the tree panel is not docked, or
* xul:vbox when when the tree panel is docked.
* null is returned when no container is available.
*/
get container()
{
if (this.openInDock) {
return this.document.getElementById("inspector-tree-box");
}
return this.document.getElementById("inspector-tree-panel");
},
/**
* Main TreePanel boot-strapping method. Initialize the TreePanel with the
* originating context and the InspectorUI global.
* @param aContext nsIDOMWindow (xulwindow)
* @param aIUI global InspectorUI object
*/
_init: function TP__init(aContext, aIUI)
{
this.IUI = aIUI;
this.window = aContext;
this.document = this.window.document;
domplateUtils.setDOM(this.window);
let isOpen = this.isOpen.bind(this);
this.registrationObject = {
id: this.id,
label: this.IUI.strings.GetStringFromName("htmlPanel.label"),
tooltiptext: this.IUI.strings.GetStringFromName("htmlPanel.tooltiptext"),
accesskey: this.IUI.strings.GetStringFromName("htmlPanel.accesskey"),
context: this,
get isOpen() isOpen(),
show: this.open,
hide: this.close,
onSelect: this.select,
panel: this.openInDock ? null : this.container,
unregister: this.destroy,
};
this.editingEvents = {};
if (!this.openInDock) {
this._boundClose = this.close.bind(this);
this.container.addEventListener("popuphiding", this._boundClose, false);
}
// Register the HTML panel with the highlighter
this.IUI.registerTool(this.registrationObject);
},
/**
* Initialization function for the TreePanel.
*/
initializeIFrame: function TP_initializeIFrame()
{
if (!this.initializingTreePanel || this.treeLoaded) {
return;
}
this.treeBrowserDocument = this.treeIFrame.contentDocument;
this.treePanelDiv = this.treeBrowserDocument.createElement("div");
this.treeBrowserDocument.body.appendChild(this.treePanelDiv);
this.treePanelDiv.ownerPanel = this;
this.ioBox = new InsideOutBox(this, this.treePanelDiv);
this.ioBox.createObjectBox(this.IUI.win.document.documentElement);
this.treeLoaded = true;
this.treeIFrame.addEventListener("click", this.onTreeClick.bind(this), false);
this.treeIFrame.addEventListener("dblclick", this.onTreeDblClick.bind(this), false);
delete this.initializingTreePanel;
Services.obs.notifyObservers(null,
this.IUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, null);
if (this.IUI.selection)
this.select(this.IUI.selection, true);
},
/**
* Open the inspector's tree panel and initialize it.
*/
open: function TP_open()
{
if (this.initializingTreePanel && !this.treeLoaded) {
return;
}
this.initializingTreePanel = true;
if (!this.openInDock)
this.container.hidden = false;
this.treeIFrame = this.document.getElementById("inspector-tree-iframe");
if (!this.treeIFrame) {
this.treeIFrame = this.document.createElement("iframe");
this.treeIFrame.setAttribute("id", "inspector-tree-iframe");
this.treeIFrame.flex = 1;
this.treeIFrame.setAttribute("type", "content");
}
if (this.openInDock) { // Create vbox
this.openDocked();
return;
}
let resizerBox = this.document.getElementById("tree-panel-resizer-box");
this.treeIFrame = this.container.insertBefore(this.treeIFrame, resizerBox);
let boundLoadedInitializeTreePanel = function loadedInitializeTreePanel()
{
this.treeIFrame.removeEventListener("load",
boundLoadedInitializeTreePanel, true);
this.initializeIFrame();
}.bind(this);
let boundTreePanelShown = function treePanelShown()
{
this.container.removeEventListener("popupshown",
boundTreePanelShown, false);
this.treeIFrame.addEventListener("load",
boundLoadedInitializeTreePanel, true);
let src = this.treeIFrame.getAttribute("src");
if (src != INSPECTOR_URI) {
this.treeIFrame.setAttribute("src", INSPECTOR_URI);
} else {
this.treeIFrame.contentWindow.location.reload();
}
}.bind(this);
this.container.addEventListener("popupshown", boundTreePanelShown, false);
const panelWidthRatio = 7 / 8;
const panelHeightRatio = 1 / 5;
let width = parseInt(this.IUI.win.outerWidth * panelWidthRatio);
let height = parseInt(this.IUI.win.outerHeight * panelHeightRatio);
let y = Math.min(this.document.defaultView.screen.availHeight - height,
this.IUI.win.innerHeight);
this.container.openPopup(this.browser, "overlap", 0, 0,
false, false);
this.container.moveTo(80, y);
this.container.sizeTo(width, height);
},
openDocked: function TP_openDocked()
{
let treeBox = null;
let toolbar = this.IUI.toolbar.nextSibling; // Addons bar, typically
let toolbarParent =
this.IUI.browser.ownerDocument.getElementById("browser-bottombox");
treeBox = this.document.createElement("vbox");
treeBox.id = "inspector-tree-box";
treeBox.state = "open"; // for the registerTools API.
treeBox.minHeight = 10;
treeBox.flex = 1;
toolbarParent.insertBefore(treeBox, toolbar);
this.createResizer();
treeBox.appendChild(this.treeIFrame);
let boundLoadedInitializeTreePanel = function loadedInitializeTreePanel()
{
this.treeIFrame.removeEventListener("load",
boundLoadedInitializeTreePanel, true);
this.initializeIFrame();
}.bind(this);
this.treeIFrame.addEventListener("load",
boundLoadedInitializeTreePanel, true);
let src = this.treeIFrame.getAttribute("src");
if (src != INSPECTOR_URI) {
this.treeIFrame.setAttribute("src", INSPECTOR_URI);
} else {
this.treeIFrame.contentWindow.location.reload();
}
},
/**
* Lame resizer on the toolbar.
*/
createResizer: function TP_createResizer()
{
let resizer = this.document.createElement("resizer");
resizer.id = "inspector-horizontal-splitter";
resizer.setAttribute("dir", "top");
resizer.flex = 1;
resizer.setAttribute("element", "inspector-tree-box");
resizer.height = 24;
this.IUI.toolbar.appendChild(resizer);
this.resizer = resizer;
},
/**
* Close the TreePanel.
*/
close: function TP_close()
{
if (this.openInDock) {
this.IUI.toolbar.removeChild(this.resizer);
let treeBox = this.container;
let treeBoxParent = treeBox.parentNode;
treeBoxParent.removeChild(treeBox);
} else {
this.container.hidePopup();
}
if (this.treePanelDiv) {
this.treePanelDiv.ownerPanel = null;
let parent = this.treePanelDiv.parentNode;
parent.removeChild(this.treePanelDiv);
delete this.treePanelDiv;
delete this.treeBrowserDocument;
}
this.treeLoaded = false;
},
/**
* Is the TreePanel open?
* @returns boolean
*/
isOpen: function TP_isOpen()
{
if (this.openInDock)
return this.treeLoaded && this.container;
return this.treeLoaded && this.container.state == "open";
},
/**
* Create the ObjectBox for the given object.
* @param object nsIDOMNode
* @param isRoot boolean - Is this the root object?
* @returns InsideOutBox
*/
createObjectBox: function TP_createObjectBox(object, isRoot)
{
let tag = domplateUtils.getNodeTag(object);
if (tag)
return tag.replace({object: object}, this.treeBrowserDocument);
},
getParentObject: function TP_getParentObject(node)
{
let parentNode = node ? node.parentNode : null;
if (!parentNode) {
// Documents have no parentNode; Attr, Document, DocumentFragment, Entity,
// and Notation. top level windows have no parentNode
if (node && node == this.window.Node.DOCUMENT_NODE) {
// document type
if (node.defaultView) {
let embeddingFrame = node.defaultView.frameElement;
if (embeddingFrame)
return embeddingFrame.parentNode;
}
}
// a Document object without a parentNode or window
return null; // top level has no parent
}
if (parentNode.nodeType == this.window.Node.DOCUMENT_NODE) {
if (parentNode.defaultView) {
return parentNode.defaultView.frameElement;
}
// parent is document element, but no window at defaultView.
return null;
}
if (!parentNode.localName)
return null;
return parentNode;
},
getChildObject: function TP_getChildObject(node, index, previousSibling)
{
if (!node)
return null;
if (node.contentDocument) {
// then the node is a frame
if (index == 0) {
return node.contentDocument.documentElement; // the node's HTMLElement
}
return null;
}
if (node instanceof this.window.GetSVGDocument) {
let svgDocument = node.getSVGDocument();
if (svgDocument) {
// then the node is a frame
if (index == 0) {
return svgDocument.documentElement; // the node's SVGElement
}
return null;
}
}
let child = null;
if (previousSibling) // then we are walking
child = this.getNextSibling(previousSibling);
else
child = this.getFirstChild(node);
if (this.showTextNodesWithWhitespace)
return child;
for (; child; child = this.getNextSibling(child)) {
if (!domplateUtils.isWhitespaceText(child))
return child;
}
return null; // we have no children worth showing.
},
getFirstChild: function TP_getFirstChild(node)
{
this.treeWalker = node.ownerDocument.createTreeWalker(node,
this.window.NodeFilter.SHOW_ALL, null, false);
return this.treeWalker.firstChild();
},
getNextSibling: function TP_getNextSibling(node)
{
let next = this.treeWalker.nextSibling();
if (!next)
delete this.treeWalker;
return next;
},
/////////////////////////////////////////////////////////////////////
// Event Handling
/**
* Handle click events in the html tree panel.
* @param aEvent
* The mouse event.
*/
onTreeClick: function TP_onTreeClick(aEvent)
{
let node;
let target = aEvent.target;
let hitTwisty = false;
if (this.hasClass(target, "twisty")) {
node = this.getRepObject(aEvent.target.nextSibling);
hitTwisty = true;
} else {
node = this.getRepObject(aEvent.target);
}
if (node) {
if (hitTwisty) {
this.ioBox.toggleObject(node);
} else {
if (this.IUI.inspecting) {
this.IUI.stopInspecting(true);
} else {
this.IUI.select(node, true, false);
this.IUI.highlighter.highlightNode(node);
}
}
}
},
/**
* Handle double-click events in the html tree panel.
* (double-clicking an attribute value allows it to be edited)
* @param aEvent
* The mouse event.
*/
onTreeDblClick: function TP_onTreeDblClick(aEvent)
{
// if already editing an attribute value, double-clicking elsewhere
// in the tree is the same as a click, which dismisses the editor
if (this.editingContext)
this.closeEditor();
let target = aEvent.target;
if (this.hasClass(target, "nodeValue")) {
let repObj = this.getRepObject(target);
let attrName = target.getAttribute("data-attributeName");
let attrVal = target.innerHTML;
this.editAttributeValue(target, repObj, attrName, attrVal);
}
},
/**
* Starts the editor for an attribute value.
* @param aAttrObj
* The DOM object representing the attribute value in the HTML Tree
* @param aRepObj
* The original DOM (target) object being inspected/edited
* @param aAttrName
* The name of the attribute being edited
* @param aAttrVal
* The current value of the attribute being edited
*/
editAttributeValue:
function TP_editAttributeValue(aAttrObj, aRepObj, aAttrName, aAttrVal)
{
let editor = this.treeBrowserDocument.getElementById("attribute-editor");
let editorInput =
this.treeBrowserDocument.getElementById("attribute-editor-input");
let attrDims = aAttrObj.getBoundingClientRect();
// figure out actual viewable viewport dimensions (sans scrollbars)
let viewportWidth = this.treeBrowserDocument.documentElement.clientWidth;
let viewportHeight = this.treeBrowserDocument.documentElement.clientHeight;
// saves the editing context for use when the editor is saved/closed
this.editingContext = {
attrObj: aAttrObj,
repObj: aRepObj,
attrName: aAttrName
};
// highlight attribute-value node in tree while editing
this.addClass(aAttrObj, "editingAttributeValue");
// show the editor
this.addClass(editor, "editing");
// offset the editor below the attribute-value node being edited
let editorVeritcalOffset = 2;
// keep the editor comfortably within the bounds of the viewport
let editorViewportBoundary = 5;
// outer editor is sized based on the <input> box inside it
editorInput.style.width = Math.min(attrDims.width, viewportWidth -
editorViewportBoundary) + "px";
editorInput.style.height = Math.min(attrDims.height, viewportHeight -
editorViewportBoundary) + "px";
let editorDims = editor.getBoundingClientRect();
// calculate position for the editor according to the attribute node
let editorLeft = attrDims.left + this.treeIFrame.contentWindow.scrollX -
// center the editor against the attribute value
((editorDims.width - attrDims.width) / 2);
let editorTop = attrDims.top + this.treeIFrame.contentWindow.scrollY +
attrDims.height + editorVeritcalOffset;
// but, make sure the editor stays within the visible viewport
editorLeft = Math.max(0, Math.min(
(this.treeIFrame.contentWindow.scrollX +
viewportWidth - editorDims.width),
editorLeft)
);
editorTop = Math.max(0, Math.min(
(this.treeIFrame.contentWindow.scrollY +
viewportHeight - editorDims.height),
editorTop)
);
// position the editor
editor.style.left = editorLeft + "px";
editor.style.top = editorTop + "px";
// set and select the text
editorInput.value = aAttrVal;
editorInput.select();
// listen for editor specific events
this.bindEditorEvent(editor, "click", function(aEvent) {
aEvent.stopPropagation();
});
this.bindEditorEvent(editor, "dblclick", function(aEvent) {
aEvent.stopPropagation();
});
this.bindEditorEvent(editor, "keypress",
this.handleEditorKeypress.bind(this));
// event notification
Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.EDITOR_OPENED,
null);
},
/**
* Handle binding an event handler for the editor.
* (saves the callback for easier unbinding later)
* @param aEditor
* The DOM object for the editor
* @param aEventName
* The name of the event to listen for
* @param aEventCallback
* The callback to bind to the event (and also to save for later
* unbinding)
*/
bindEditorEvent:
function TP_bindEditorEvent(aEditor, aEventName, aEventCallback)
{
this.editingEvents[aEventName] = aEventCallback;
aEditor.addEventListener(aEventName, aEventCallback, false);
},
/**
* Handle unbinding an event handler from the editor.
* (unbinds the previously bound and saved callback)
* @param aEditor
* The DOM object for the editor
* @param aEventName
* The name of the event being listened for
*/
unbindEditorEvent: function TP_unbindEditorEvent(aEditor, aEventName)
{
aEditor.removeEventListener(aEventName, this.editingEvents[aEventName],
false);
this.editingEvents[aEventName] = null;
},
/**
* Handle keypress events in the editor.
* @param aEvent
* The keyboard event.
*/
handleEditorKeypress: function TP_handleEditorKeypress(aEvent)
{
if (aEvent.which == this.window.KeyEvent.DOM_VK_RETURN) {
this.saveEditor();
} else if (aEvent.keyCode == this.window.KeyEvent.DOM_VK_ESCAPE) {
this.closeEditor();
}
},
/**
* Close the editor and cleanup.
*/
closeEditor: function TP_closeEditor()
{
let editor = this.treeBrowserDocument.getElementById("attribute-editor");
let editorInput =
this.treeBrowserDocument.getElementById("attribute-editor-input");
// remove highlight from attribute-value node in tree
this.removeClass(this.editingContext.attrObj, "editingAttributeValue");
// hide editor
this.removeClass(editor, "editing");
// stop listening for editor specific events
this.unbindEditorEvent(editor, "click");
this.unbindEditorEvent(editor, "dblclick");
this.unbindEditorEvent(editor, "keypress");
// clean up after the editor
editorInput.value = "";
editorInput.blur();
this.editingContext = null;
this.editingEvents = {};
// event notification
Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED,
null);
},
/**
* Commit the edits made in the editor, then close it.
*/
saveEditor: function TP_saveEditor()
{
let editorInput =
this.treeBrowserDocument.getElementById("attribute-editor-input");
// set the new attribute value on the original target DOM element
this.editingContext.repObj.setAttribute(this.editingContext.attrName,
editorInput.value);
// update the HTML tree attribute value
this.editingContext.attrObj.innerHTML = editorInput.value;
this.IUI.isDirty = true;
// event notification
Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED,
null);
this.closeEditor();
},
/**
* Simple tree select method.
* @param aNode the DOM node in the content document to select.
* @param aScroll boolean scroll to the visible node?
*/
select: function TP_select(aNode, aScroll)
{
if (this.ioBox)
this.ioBox.select(aNode, true, true, aScroll);
},
///////////////////////////////////////////////////////////////////////////
//// Utility functions
/**
* Does the given object have a class attribute?
* @param aNode
* the DOM node.
* @param aClass
* The class string.
* @returns boolean
*/
hasClass: function TP_hasClass(aNode, aClass)
{
if (!(aNode instanceof this.window.Element))
return false;
return aNode.classList.contains(aClass);
},
/**
* Add the class name to the given object.
* @param aNode
* the DOM node.
* @param aClass
* The class string.
*/
addClass: function TP_addClass(aNode, aClass)
{
if (aNode instanceof this.window.Element)
aNode.classList.add(aClass);
},
/**
* Remove the class name from the given object
* @param aNode
* the DOM node.
* @param aClass
* The class string.
*/
removeClass: function TP_removeClass(aNode, aClass)
{
if (aNode instanceof this.window.Element)
aNode.classList.remove(aClass);
},
/**
* Get the "repObject" from the HTML panel's domplate-constructed DOM node.
* In this system, a "repObject" is the Object being Represented by the box
* object. It is the "real" object that we're building our facade around.
*
* @param element
* The element in the HTML panel the user clicked.
* @returns either a real node or null
*/
getRepObject: function TP_getRepObject(element)
{
let target = null;
for (let child = element; child; child = child.parentNode) {
if (this.hasClass(child, "repTarget"))
target = child;
if (child.repObject) {
if (!target && this.hasClass(child.repObject, "repIgnore"))
break;
else
return child.repObject;
}
}
return null;
},
/**
* Destructor function. Cleanup.
*/
destroy: function TP_destroy()
{
if (this.isOpen()) {
this.close();
}
domplateUtils.setDOM(null);
delete this.resizer;
delete this.treeWalker;
if (this.treePanelDiv) {
this.treePanelDiv.ownerPanel = null;
let parent = this.treePanelDiv.parentNode;
parent.removeChild(this.treePanelDiv);
delete this.treePanelDiv;
delete this.treeBrowserDocument;
}
if (this.treeIFrame) {
this.treeIFrame.removeEventListener("dblclick", this.onTreeDblClick, false);
this.treeIFrame.removeEventListener("click", this.onTreeClick, false);
let parent = this.treeIFrame.parentNode;
parent.removeChild(this.treeIFrame);
delete this.treeIFrame;
}
if (this.ioBox) {
this.ioBox.destroy();
delete this.ioBox;
}
if (!this.openInDock) {
this.container.removeEventListener("popuphiding", this._boundClose, false);
delete this._boundClose;
}
}
};

View File

@ -61,5 +61,8 @@ _BROWSER_FILES = \
browser_inspector_bug_566084_location_changed.js \ browser_inspector_bug_566084_location_changed.js \
$(NULL) $(NULL)
# Disabled due to constant failures
# browser_inspector_treePanel_click.js \
libs:: $(_BROWSER_FILES) libs:: $(_BROWSER_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir) $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)

View File

@ -5,19 +5,19 @@ let notificationBox = null;
function startLocationTests() { function startLocationTests() {
ok(window.InspectorUI, "InspectorUI variable exists"); ok(window.InspectorUI, "InspectorUI variable exists");
Services.obs.addObserver(runInspectorTests, INSPECTOR_NOTIFICATIONS.OPENED, null); Services.obs.addObserver(runInspectorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, null);
InspectorUI.toggleInspectorUI(); InspectorUI.toggleInspectorUI();
} }
function runInspectorTests() { function runInspectorTests() {
Services.obs.removeObserver(runInspectorTests, INSPECTOR_NOTIFICATIONS.OPENED, null); Services.obs.removeObserver(runInspectorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, null);
let para = content.document.querySelector("p"); let para = content.document.querySelector("p");
ok(para, "found the paragraph element"); ok(para, "found the paragraph element");
is(para.textContent, "init", "paragraph content is correct"); is(para.textContent, "init", "paragraph content is correct");
ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Panel is open"); ok(InspectorUI.isInspectorOpen, "Inspector is open");
InspectorUI.isDirty = true; InspectorUI.isDirty = true;
@ -56,7 +56,7 @@ function onPageLoad() {
is(para.textContent, "test2", "paragraph content is correct"); is(para.textContent, "test2", "paragraph content is correct");
ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(!InspectorUI.isTreePanelOpen, "Inspector Panel is not open"); ok(!InspectorUI.isInspectorOpen, "Inspector Panel is not open");
testEnd(); testEnd();
} }
@ -68,7 +68,7 @@ function locationTest2() {
is(para.textContent, "init", "paragraph content is correct"); is(para.textContent, "init", "paragraph content is correct");
ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Panel is open"); ok(InspectorUI.isInspectorOpen, "Inspector Panel is open");
notificationBox.addEventListener("AlertActive", alertActive2, false); notificationBox.addEventListener("AlertActive", alertActive2, false);
@ -102,7 +102,6 @@ function alertActive2() {
function testEnd() { function testEnd() {
notificationBox = null; notificationBox = null;
InspectorUI.isDirty = false;
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
executeSoon(finish); executeSoon(finish);
} }

View File

@ -23,18 +23,18 @@ function test()
objectNode = doc.querySelector("object"); objectNode = doc.querySelector("object");
ok(objectNode, "we have the object node"); ok(objectNode, "we have the object node");
Services.obs.addObserver(runObjectInspectionTest, Services.obs.addObserver(runObjectInspectionTest,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI(); InspectorUI.toggleInspectorUI();
} }
function runObjectInspectionTest() function runObjectInspectionTest()
{ {
Services.obs.removeObserver(runObjectInspectionTest, Services.obs.removeObserver(runObjectInspectionTest,
INSPECTOR_NOTIFICATIONS.OPENED); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
executeSoon(function() { executeSoon(function() {
Services.obs.addObserver(performTestComparison, Services.obs.addObserver(performTestComparison,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
InspectorUI.inspectNode(objectNode); InspectorUI.inspectNode(objectNode);
}); });
@ -43,18 +43,18 @@ function test()
function performTestComparison() function performTestComparison()
{ {
Services.obs.removeObserver(performTestComparison, Services.obs.removeObserver(performTestComparison,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
is(InspectorUI.selection, objectNode, "selection matches node"); is(InspectorUI.selection, objectNode, "selection matches node");
Services.obs.addObserver(finishUp, Services.obs.addObserver(finishUp,
INSPECTOR_NOTIFICATIONS.CLOSED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
InspectorUI.closeInspectorUI(); InspectorUI.closeInspectorUI();
} }
function finishUp() { function finishUp() {
Services.obs.removeObserver(finishUp, INSPECTOR_NOTIFICATIONS.CLOSED); Services.obs.removeObserver(finishUp, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
doc = objectNode = null; doc = objectNode = null;
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
finish(); finish();

View File

@ -47,18 +47,18 @@ function test()
ok(iframeNode, "we have the iframe node"); ok(iframeNode, "we have the iframe node");
ok(iframeBodyNode, "we have the body node"); ok(iframeBodyNode, "we have the body node");
Services.obs.addObserver(runTests, Services.obs.addObserver(runTests,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI(); InspectorUI.toggleInspectorUI();
} }
function runTests() function runTests()
{ {
Services.obs.removeObserver(runTests, Services.obs.removeObserver(runTests,
INSPECTOR_NOTIFICATIONS.OPENED); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
executeSoon(function() { executeSoon(function() {
Services.obs.addObserver(isTheIframeSelected, Services.obs.addObserver(isTheIframeSelected,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
moveMouseOver(iframeNode, 1, 1); moveMouseOver(iframeNode, 1, 1);
}); });
@ -67,7 +67,7 @@ function test()
function isTheIframeSelected() function isTheIframeSelected()
{ {
Services.obs.removeObserver(isTheIframeSelected, Services.obs.removeObserver(isTheIframeSelected,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
is(InspectorUI.selection, iframeNode, "selection matches node"); is(InspectorUI.selection, iframeNode, "selection matches node");
iframeNode.style.marginBottom = doc.defaultView.innerHeight + "px"; iframeNode.style.marginBottom = doc.defaultView.innerHeight + "px";
@ -75,7 +75,7 @@ function test()
executeSoon(function() { executeSoon(function() {
Services.obs.addObserver(isTheIframeContentSelected, Services.obs.addObserver(isTheIframeContentSelected,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
moveMouseOver(iframeNode, 40, 40); moveMouseOver(iframeNode, 40, 40);
}); });
@ -84,7 +84,7 @@ function test()
function isTheIframeContentSelected() function isTheIframeContentSelected()
{ {
Services.obs.removeObserver(isTheIframeContentSelected, Services.obs.removeObserver(isTheIframeContentSelected,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
is(InspectorUI.selection, iframeBodyNode, "selection matches node"); is(InspectorUI.selection, iframeBodyNode, "selection matches node");
// 184 == 200 + 11(border) + 13(padding) - 40(scroll) // 184 == 200 + 11(border) + 13(padding) - 40(scroll)
@ -92,12 +92,12 @@ function test()
"highlighter height"); "highlighter height");
Services.obs.addObserver(finishUp, Services.obs.addObserver(finishUp,
INSPECTOR_NOTIFICATIONS.CLOSED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
InspectorUI.closeInspectorUI(); InspectorUI.closeInspectorUI();
} }
function finishUp() { function finishUp() {
Services.obs.removeObserver(finishUp, INSPECTOR_NOTIFICATIONS.CLOSED); Services.obs.removeObserver(finishUp, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
doc = iframeNode = iframeBodyNode = null; doc = iframeNode = iframeBodyNode = null;
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
finish(); finish();

View File

@ -3,11 +3,11 @@
/* ***** BEGIN LICENSE BLOCK ***** /* ***** BEGIN LICENSE BLOCK *****
/* Any copyright is dedicated to the Public Domain. /* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ * http://creativecommons.org/publicdomain/zero/1.0/
* *
* Contributor(s): * Contributor(s):
* Rob Campbell <rcampbell@mozilla.com> * Rob Campbell <rcampbell@mozilla.com>
* Mihai Sucan <mihai.sucan@gmail.com> * Mihai Sucan <mihai.sucan@gmail.com>
* Kyle Simpson <ksimpson@mozilla.com> * Kyle Simpson <ksimpson@mozilla.com>
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
@ -25,23 +25,30 @@ function setupEditorTests()
div.setAttribute("id", "foobar"); div.setAttribute("id", "foobar");
div.setAttribute("class", "barbaz"); div.setAttribute("class", "barbaz");
doc.body.appendChild(div); doc.body.appendChild(div);
Services.obs.addObserver(runEditorTests, INSPECTOR_NOTIFICATIONS.OPENED, false); Services.obs.addObserver(setupHTMLPanel, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI(); InspectorUI.toggleInspectorUI();
} }
function setupHTMLPanel()
{
Services.obs.removeObserver(setupHTMLPanel, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
Services.obs.addObserver(runEditorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
InspectorUI.treePanel.open();
}
function runEditorTests() function runEditorTests()
{ {
Services.obs.removeObserver(runEditorTests, INSPECTOR_NOTIFICATIONS.OPENED, false); Services.obs.removeObserver(runEditorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
InspectorUI.stopInspecting(); InspectorUI.stopInspecting();
// setup generator for async test steps // setup generator for async test steps
editorTestSteps = doEditorTestSteps(); editorTestSteps = doEditorTestSteps();
// add step listeners // add step listeners
Services.obs.addObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false); Services.obs.addObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false);
Services.obs.addObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false); Services.obs.addObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false);
Services.obs.addObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false); Services.obs.addObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false);
// start the tests // start the tests
doNextStep(); doNextStep();
@ -49,16 +56,17 @@ function runEditorTests()
function doEditorTestSteps() function doEditorTestSteps()
{ {
let editor = InspectorUI.treeBrowserDocument.getElementById("attribute-editor"); let treePanel = InspectorUI.treePanel;
let editorInput = InspectorUI.treeBrowserDocument.getElementById("attribute-editor-input"); let editor = treePanel.treeBrowserDocument.getElementById("attribute-editor");
let editorInput = treePanel.treeBrowserDocument.getElementById("attribute-editor-input");
// Step 1: grab and test the attribute-value nodes in the HTML panel, then open editor // Step 1: grab and test the attribute-value nodes in the HTML panel, then open editor
let attrValNode_id = InspectorUI.treeBrowserDocument.querySelectorAll(".nodeValue.editable[data-attributeName='id']")[0]; let attrValNode_id = treePanel.treeBrowserDocument.querySelectorAll(".nodeValue.editable[data-attributeName='id']")[0];
let attrValNode_class = InspectorUI.treeBrowserDocument.querySelectorAll(".nodeValue.editable[data-attributeName='class']")[0]; let attrValNode_class = treePanel.treeBrowserDocument.querySelectorAll(".nodeValue.editable[data-attributeName='class']")[0];
is(attrValNode_id.innerHTML, "foobar", "Step 1: we have the correct `id` attribute-value node in the HTML panel"); is(attrValNode_id.innerHTML, "foobar", "Step 1: we have the correct `id` attribute-value node in the HTML panel");
is(attrValNode_class.innerHTML, "barbaz", "we have the correct `class` attribute-value node in the HTML panel"); is(attrValNode_class.innerHTML, "barbaz", "we have the correct `class` attribute-value node in the HTML panel");
// double-click the `id` attribute-value node to open the editor // double-click the `id` attribute-value node to open the editor
executeSoon(function() { executeSoon(function() {
// firing 2 clicks right in a row to simulate a double-click // firing 2 clicks right in a row to simulate a double-click
@ -69,7 +77,7 @@ function doEditorTestSteps()
// Step 2: validate editing session, enter new attribute value into editor, and save input // Step 2: validate editing session, enter new attribute value into editor, and save input
ok(InspectorUI.editingContext, "Step 2: editor session started"); ok(InspectorUI.treePanel.editingContext, "Step 2: editor session started");
let editorVisible = editor.classList.contains("editing"); let editorVisible = editor.classList.contains("editing");
ok(editorVisible, "editor popup visible"); ok(editorVisible, "editor popup visible");
@ -88,13 +96,13 @@ function doEditorTestSteps()
let attrValNodeHighlighted = attrValNode_id.classList.contains("editingAttributeValue"); let attrValNodeHighlighted = attrValNode_id.classList.contains("editingAttributeValue");
ok(attrValNodeHighlighted, "`id` attribute-value node is editor-highlighted"); ok(attrValNodeHighlighted, "`id` attribute-value node is editor-highlighted");
is(InspectorUI.editingContext.repObj, div, "editor session has correct reference to div"); is(treePanel.editingContext.repObj, div, "editor session has correct reference to div");
is(InspectorUI.editingContext.attrObj, attrValNode_id, "editor session has correct reference to `id` attribute-value node in HTML panel"); is(treePanel.editingContext.attrObj, attrValNode_id, "editor session has correct reference to `id` attribute-value node in HTML panel");
is(InspectorUI.editingContext.attrName, "id", "editor session knows correct attribute-name"); is(treePanel.editingContext.attrName, "id", "editor session knows correct attribute-name");
editorInput.value = "Hello World"; editorInput.value = "Hello World";
editorInput.focus(); editorInput.focus();
// hit <enter> to save the inputted value // hit <enter> to save the inputted value
executeSoon(function() { executeSoon(function() {
EventUtils.synthesizeKey("VK_RETURN", {}, attrValNode_id.ownerDocument.defaultView); EventUtils.synthesizeKey("VK_RETURN", {}, attrValNode_id.ownerDocument.defaultView);
@ -106,7 +114,7 @@ function doEditorTestSteps()
// Step 3: validate that the previous editing session saved correctly, then open editor on `class` attribute value // Step 3: validate that the previous editing session saved correctly, then open editor on `class` attribute value
ok(!InspectorUI.editingContext, "Step 3: editor session ended"); ok(!treePanel.editingContext, "Step 3: editor session ended");
editorVisible = editor.classList.contains("editing"); editorVisible = editor.classList.contains("editing");
ok(!editorVisible, "editor popup hidden"); ok(!editorVisible, "editor popup hidden");
attrValNodeHighlighted = attrValNode_id.classList.contains("editingAttributeValue"); attrValNodeHighlighted = attrValNode_id.classList.contains("editingAttributeValue");
@ -124,16 +132,16 @@ function doEditorTestSteps()
// Step 4: enter value into editor, then hit <escape> to discard it // Step 4: enter value into editor, then hit <escape> to discard it
ok(InspectorUI.editingContext, "Step 4: editor session started"); ok(treePanel.editingContext, "Step 4: editor session started");
editorVisible = editor.classList.contains("editing"); editorVisible = editor.classList.contains("editing");
ok(editorVisible, "editor popup visible"); ok(editorVisible, "editor popup visible");
is(InspectorUI.editingContext.attrObj, attrValNode_class, "editor session has correct reference to `class` attribute-value node in HTML panel"); is(treePanel.editingContext.attrObj, attrValNode_class, "editor session has correct reference to `class` attribute-value node in HTML panel");
is(InspectorUI.editingContext.attrName, "class", "editor session knows correct attribute-name"); is(treePanel.editingContext.attrName, "class", "editor session knows correct attribute-name");
editorInput.value = "Hello World"; editorInput.value = "Hello World";
editorInput.focus(); editorInput.focus();
// hit <escape> to discard the inputted value // hit <escape> to discard the inputted value
executeSoon(function() { executeSoon(function() {
EventUtils.synthesizeKey("VK_ESCAPE", {}, attrValNode_class.ownerDocument.defaultView); EventUtils.synthesizeKey("VK_ESCAPE", {}, attrValNode_class.ownerDocument.defaultView);
@ -143,7 +151,7 @@ function doEditorTestSteps()
// Step 5: validate that the previous editing session discarded correctly, then open editor on `id` attribute value again // Step 5: validate that the previous editing session discarded correctly, then open editor on `id` attribute value again
ok(!InspectorUI.editingContext, "Step 5: editor session ended"); ok(!treePanel.editingContext, "Step 5: editor session ended");
editorVisible = editor.classList.contains("editing"); editorVisible = editor.classList.contains("editing");
ok(!editorVisible, "editor popup hidden"); ok(!editorVisible, "editor popup hidden");
is(div.getAttribute("class"), "barbaz", "`class` attribute-value *not* updated"); is(div.getAttribute("class"), "barbaz", "`class` attribute-value *not* updated");
@ -159,15 +167,15 @@ function doEditorTestSteps()
// Step 6: validate that editor opened again, then test double-click inside of editor (should do nothing) // Step 6: validate that editor opened again, then test double-click inside of editor (should do nothing)
ok(InspectorUI.editingContext, "Step 6: editor session started"); ok(treePanel.editingContext, "Step 6: editor session started");
editorVisible = editor.classList.contains("editing"); editorVisible = editor.classList.contains("editing");
ok(editorVisible, "editor popup visible"); ok(editorVisible, "editor popup visible");
// double-click on the editor input box // double-click on the editor input box
executeSoon(function() { executeSoon(function() {
// firing 2 clicks right in a row to simulate a double-click // firing 2 clicks right in a row to simulate a double-click
EventUtils.synthesizeMouse(editorInput, 2, 2, {clickCount: 2}, editorInput.ownerDocument.defaultView); EventUtils.synthesizeMouse(editorInput, 2, 2, {clickCount: 2}, editorInput.ownerDocument.defaultView);
// since the previous double-click is supposed to do nothing, // since the previous double-click is supposed to do nothing,
// wait a brief moment, then move on to the next step // wait a brief moment, then move on to the next step
executeSoon(function() { executeSoon(function() {
@ -178,12 +186,12 @@ function doEditorTestSteps()
yield; // End of Step 6 yield; // End of Step 6
// Step 7: validate that editing session is still correct, then enter a value and try a click // Step 7: validate that editing session is still correct, then enter a value and try a click
// outside of editor (should cancel the editing session) // outside of editor (should cancel the editing session)
ok(InspectorUI.editingContext, "Step 7: editor session still going"); ok(treePanel.editingContext, "Step 7: editor session still going");
editorVisible = editor.classList.contains("editing"); editorVisible = editor.classList.contains("editing");
ok(editorVisible, "editor popup still visible"); ok(editorVisible, "editor popup still visible");
editorInput.value = "all your base are belong to us"; editorInput.value = "all your base are belong to us";
// single-click the `class` attribute-value node // single-click the `class` attribute-value node
@ -195,18 +203,18 @@ function doEditorTestSteps()
// Step 8: validate that the editor was closed and that the editing was not saved // Step 8: validate that the editor was closed and that the editing was not saved
ok(!InspectorUI.editingContext, "Step 8: editor session ended"); ok(!treePanel.editingContext, "Step 8: editor session ended");
editorVisible = editor.classList.contains("editing"); editorVisible = editor.classList.contains("editing");
ok(!editorVisible, "editor popup hidden"); ok(!editorVisible, "editor popup hidden");
is(div.getAttribute("id"), "Hello World", "`id` attribute-value *not* updated"); is(div.getAttribute("id"), "Hello World", "`id` attribute-value *not* updated");
is(attrValNode_id.innerHTML, "Hello World", "attribute-value node in HTML panel *not* updated"); is(attrValNode_id.innerHTML, "Hello World", "attribute-value node in HTML panel *not* updated");
// End of Step 8 // End of Step 8
// end of all steps, so clean up // end of all steps, so clean up
Services.obs.removeObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false); Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false);
Services.obs.removeObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false); Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false);
Services.obs.removeObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false); Services.obs.removeObserver(doNextStep, InspectorUI.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED, false);
executeSoon(finishUp); executeSoon(finishUp);
} }

View File

@ -80,18 +80,18 @@ function setupHighlighterTests()
h1 = doc.querySelectorAll("h1")[0]; h1 = doc.querySelectorAll("h1")[0];
ok(h1, "we have the header node"); ok(h1, "we have the header node");
Services.obs.addObserver(runSelectionTests, Services.obs.addObserver(runSelectionTests,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI(); InspectorUI.toggleInspectorUI();
} }
function runSelectionTests() function runSelectionTests()
{ {
Services.obs.removeObserver(runSelectionTests, Services.obs.removeObserver(runSelectionTests,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
executeSoon(function() { executeSoon(function() {
Services.obs.addObserver(performTestComparisons, Services.obs.addObserver(performTestComparisons,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
EventUtils.synthesizeMouse(h1, 2, 2, {type: "mousemove"}, content); EventUtils.synthesizeMouse(h1, 2, 2, {type: "mousemove"}, content);
}); });
} }
@ -99,7 +99,7 @@ function runSelectionTests()
function performTestComparisons(evt) function performTestComparisons(evt)
{ {
Services.obs.removeObserver(performTestComparisons, Services.obs.removeObserver(performTestComparisons,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
InspectorUI.stopInspecting(); InspectorUI.stopInspecting();
ok(InspectorUI.highlighter.isHighlighting, "highlighter is highlighting"); ok(InspectorUI.highlighter.isHighlighting, "highlighter is highlighting");

View File

@ -43,7 +43,6 @@ let div1;
let div2; let div2;
let iframe1; let iframe1;
let iframe2; let iframe2;
let highlighterFrame;
function createDocument() function createDocument()
{ {
@ -87,28 +86,27 @@ function moveMouseOver(aElement)
function setupIframeTests() function setupIframeTests()
{ {
Services.obs.addObserver(runIframeTests, Services.obs.addObserver(runIframeTests,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.openInspectorUI(); InspectorUI.openInspectorUI();
} }
function runIframeTests() function runIframeTests()
{ {
Services.obs.removeObserver(runIframeTests, Services.obs.removeObserver(runIframeTests,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
Services.obs.addObserver(performTestComparisons1, Services.obs.addObserver(performTestComparisons1,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
highlighterFrame = InspectorUI.highlighter.iframe;
executeSoon(moveMouseOver.bind(this, div1)); executeSoon(moveMouseOver.bind(this, div1));
} }
function performTestComparisons1() function performTestComparisons1()
{ {
Services.obs.removeObserver(performTestComparisons1, Services.obs.removeObserver(performTestComparisons1,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
Services.obs.addObserver(performTestComparisons2, Services.obs.addObserver(performTestComparisons2,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
is(InspectorUI.selection, div1, "selection matches div1 node"); is(InspectorUI.selection, div1, "selection matches div1 node");
is(InspectorUI.highlighter.highlitNode, div1, "highlighter matches selection"); is(InspectorUI.highlighter.highlitNode, div1, "highlighter matches selection");
@ -119,7 +117,7 @@ function performTestComparisons1()
function performTestComparisons2() function performTestComparisons2()
{ {
Services.obs.removeObserver(performTestComparisons2, Services.obs.removeObserver(performTestComparisons2,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
is(InspectorUI.selection, div2, "selection matches div2 node"); is(InspectorUI.selection, div2, "selection matches div2 node");
is(InspectorUI.highlighter.highlitNode, div2, "highlighter matches selection"); is(InspectorUI.highlighter.highlitNode, div2, "highlighter matches selection");

View File

@ -38,6 +38,7 @@
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
let doc; let doc;
let salutation; let salutation;
let closing;
function createDocument() function createDocument()
{ {
@ -60,24 +61,35 @@ function startInspectorTests()
{ {
ok(InspectorUI, "InspectorUI variable exists"); ok(InspectorUI, "InspectorUI variable exists");
Services.obs.addObserver(runInspectorTests, Services.obs.addObserver(runInspectorTests,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI(); InspectorUI.toggleInspectorUI();
} }
function runInspectorTests() function runInspectorTests()
{ {
Services.obs.removeObserver(runInspectorTests, Services.obs.removeObserver(runInspectorTests,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
Services.obs.addObserver(runContextMenuTest, Services.obs.addObserver(treePanelTests,
INSPECTOR_NOTIFICATIONS.CLOSED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
ok(InspectorUI.toolbar, "we have the toolbar.");
ok(!InspectorUI.toolbar.hidden, "toolbar is visible"); ok(!InspectorUI.toolbar.hidden, "toolbar is visible");
let iframe = document.getElementById("inspector-tree-iframe");
is(InspectorUI.treeIFrame, iframe, "Inspector IFrame matches");
ok(InspectorUI.inspecting, "Inspector is inspecting"); ok(InspectorUI.inspecting, "Inspector is inspecting");
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
ok(InspectorUI.highlighter, "Highlighter is up"); ok(InspectorUI.highlighter, "Highlighter is up");
InspectorUI.treePanel.open();
}
function treePanelTests()
{
Services.obs.removeObserver(treePanelTests,
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
Services.obs.addObserver(runContextMenuTest,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
executeSoon(function() { executeSoon(function() {
InspectorUI.closeInspectorUI(); InspectorUI.closeInspectorUI();
}); });
@ -85,8 +97,8 @@ function runInspectorTests()
function runContextMenuTest() function runContextMenuTest()
{ {
Services.obs.removeObserver(runContextMenuTest, INSPECTOR_NOTIFICATIONS.CLOSED, false); Services.obs.removeObserver(runContextMenuTest, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
Services.obs.addObserver(inspectNodesFromContextTest, INSPECTOR_NOTIFICATIONS.OPENED, false); Services.obs.addObserver(inspectNodesFromContextTest, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
salutation = doc.getElementById("salutation"); salutation = doc.getElementById("salutation");
ok(salutation, "hello, context menu test!"); ok(salutation, "hello, context menu test!");
let eventDeets = { type : "contextmenu", button : 2 }; let eventDeets = { type : "contextmenu", button : 2 };
@ -96,7 +108,7 @@ function runContextMenuTest()
ok(contextInspectMenuItem, "we have the inspect context menu item"); ok(contextInspectMenuItem, "we have the inspect context menu item");
EventUtils.synthesizeMouse(salutation, 2, 2, eventDeets); EventUtils.synthesizeMouse(salutation, 2, 2, eventDeets);
is(contextMenu.state, "showing", "context menu is open"); is(contextMenu.state, "showing", "context menu is open");
is(contextInspectMenuItem.hidden, !InspectorUI.enabled, "is context menu item enabled?"); is(!contextInspectMenuItem.hidden, gPrefService.getBoolPref("devtools.inspector.enabled"), "is context menu item enabled?");
contextMenu.hidePopup(); contextMenu.hidePopup();
executeSoon(function() { executeSoon(function() {
InspectorUI.openInspectorUI(salutation); InspectorUI.openInspectorUI(salutation);
@ -105,26 +117,65 @@ function runContextMenuTest()
function inspectNodesFromContextTest() function inspectNodesFromContextTest()
{ {
Services.obs.removeObserver(inspectNodesFromContextTest, INSPECTOR_NOTIFICATIONS.OPENED, false); Services.obs.removeObserver(inspectNodesFromContextTest, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
Services.obs.addObserver(finishInspectorTests, INSPECTOR_NOTIFICATIONS.CLOSED, false); Services.obs.addObserver(openInspectorForContextTest, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
ok(!InspectorUI.inspecting, "Inspector is not actively highlighting"); ok(!InspectorUI.inspecting, "Inspector is not actively highlighting");
is(InspectorUI.selection, salutation, "Inspector is highlighting salutation"); is(InspectorUI.selection, salutation, "Inspector is highlighting salutation");
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is closed");
// TODO: These tests depend on the style inspector patches. // TODO: These tests depend on the style inspector patches.
todo(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); todo(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open");
todo(InspectorUI.isDOMPanelOpen, "Inspector DOM Panel is open"); executeSoon(function() {
InspectorUI.closeInspectorUI(true); InspectorUI.closeInspectorUI(true);
});
}
function openInspectorForContextTest()
{
Services.obs.removeObserver(openInspectorForContextTest, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
Services.obs.addObserver(inspectNodesFromContextTestWhileOpen, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
executeSoon(function() {
InspectorUI.openInspectorUI(salutation);
});
}
function inspectNodesFromContextTestWhileOpen()
{
Services.obs.removeObserver(inspectNodesFromContextTestWhileOpen, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
Services.obs.addObserver(inspectNodesFromContextTestTrap, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
Services.obs.addObserver(inspectNodesFromContextTestHighlight, InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
is(InspectorUI.selection, salutation, "Inspector is highlighting salutation");
closing = doc.getElementById("closing");
ok(closing, "we have the closing statement");
executeSoon(function() {
InspectorUI.openInspectorUI(closing);
});
}
function inspectNodesFromContextTestHighlight()
{
Services.obs.removeObserver(inspectNodesFromContextTestHighlight, InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
Services.obs.addObserver(finishInspectorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
is(InspectorUI.selection, closing, "InspectorUI.selection is header");
executeSoon(function() {
InspectorUI.closeInspectorUI(true);
});
}
function inspectNodesFromContextTestTrap()
{
Services.obs.removeObserver(inspectNodesFromContextTestTrap, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
ok(false, "Inspector UI has been opened again. We Should Not Be Here!");
} }
function finishInspectorTests() function finishInspectorTests()
{ {
Services.obs.removeObserver(finishInspectorTests, Services.obs.removeObserver(finishInspectorTests,
INSPECTOR_NOTIFICATIONS.CLOSED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
ok(!InspectorUI.highlighter, "Highlighter is gone"); ok(!InspectorUI.highlighter, "Highlighter is gone");
ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is closed"); ok(!InspectorUI.treePanel, "Inspector Tree Panel is closed");
ok(!InspectorUI.inspecting, "Inspector is not inspecting"); ok(!InspectorUI.inspecting, "Inspector is not inspecting");
ok(InspectorUI.toolbar.hidden, "toolbar is hidden"); ok(!InspectorUI.toolbar, "toolbar is hidden");
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
finish(); finish();

View File

@ -39,16 +39,20 @@
let doc; let doc;
let h1; let h1;
let p2;
let toolsLength = 0;
let toolEvents = 0;
let tool1; let tool1;
let tool2; let tool2;
let tool3; let tool3;
let initToolsMethod = InspectorUI.initTools;
function createDocument() function createDocument()
{ {
let div = doc.createElement("div"); let div = doc.createElement("div");
let h1 = doc.createElement("h1"); h1 = doc.createElement("h1");
let p1 = doc.createElement("p"); let p1 = doc.createElement("p");
let p2 = doc.createElement("p"); p2 = doc.createElement("p");
let div2 = doc.createElement("div"); let div2 = doc.createElement("div");
let p3 = doc.createElement("p"); let p3 = doc.createElement("p");
doc.title = "Inspector Tree Selection Test"; doc.title = "Inspector Tree Selection Test";
@ -79,73 +83,70 @@ function createDocument()
function setupHighlighterTests() function setupHighlighterTests()
{ {
h1 = doc.querySelectorAll("h1")[0];
ok(h1, "we have the header node"); ok(h1, "we have the header node");
Services.obs.addObserver(inspectorOpen, "inspector-opened", false); Services.obs.addObserver(inspectorOpen, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
registerTools();
InspectorUI.toggleInspectorUI(); InspectorUI.toggleInspectorUI();
} }
function inspectorOpen() function inspectorOpen()
{ {
info("we received the inspector-opened notification"); info("we received the inspector-opened notification");
Services.obs.removeObserver(inspectorOpen, "inspector-opened", false); Services.obs.removeObserver(inspectorOpen, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
Services.obs.addObserver(startToolTests, "inspector-highlighting", false); toolsLength = InspectorUI.tools.length;
let rect = h1.getBoundingClientRect(); toolEvents = InspectorUI.toolEvents.length;
executeSoon(function() { info("tools registered");
EventUtils.synthesizeMouse(h1, 2, 2, {type: "mousemove"}, content); Services.obs.addObserver(startToolTests, InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
}); InspectorUI.inspectNode(h1);
} }
function startToolTests(evt) function startToolTests(evt)
{ {
info("we received the inspector-highlighting notification"); Services.obs.removeObserver(startToolTests, InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
Services.obs.removeObserver(startToolTests, "inspector-highlighting", false);
InspectorUI.stopInspecting(); InspectorUI.stopInspecting();
info("Getting InspectorUI.tools"); info("Getting InspectorUI.tools");
let tools = InspectorUI.tools; let tools = InspectorUI.tools;
tool1 = InspectorUI.tools["tool_1"]; tool1 = InspectorUI.tools["tool_1"];
tool2 = InspectorUI.tools["tool_2"]; tool2 = InspectorUI.tools["tool_2"];
tool3 = InspectorUI.tools["tool_3"]; tool3 = InspectorUI.tools["tool_3"];
info("Checking panel states 1"); info("Checking panel states 1");
ok(tool1.context.panelIsClosed, "Panel 1 is closed"); ok(!tool1.isOpen, "Panel 1 is closed");
ok(tool2.context.panelIsClosed, "Panel 2 is closed"); ok(!tool2.isOpen, "Panel 2 is closed");
ok(tool3.context.panelIsClosed, "Panel 3 is closed"); ok(!tool3.isOpen, "Panel 3 is closed");
info("Calling show method for all tools"); info("Calling show method for all tools");
tool1.onShow.apply(tool1.context, [h1]); InspectorUI.toolShow(tool1);
tool2.onShow.apply(tool2.context, [h1]); InspectorUI.toolShow(tool2);
tool3.onShow.apply(tool3.context, [h1]); InspectorUI.toolShow(tool3);
info("Checking panel states 2"); info("Checking panel states 2");
ok(tool1.context.panelIsOpen, "Panel 1 is open"); ok(tool1.isOpen, "Panel 1 is open");
ok(tool2.context.panelIsOpen, "Panel 2 is open"); ok(tool2.isOpen, "Panel 2 is open");
ok(tool3.context.panelIsOpen, "Panel 3 is open"); ok(tool3.isOpen, "Panel 3 is open");
info("Calling selectNode method for all tools"); info("Calling selectNode method for all tools, should see 3 selects");
tool1.onSelect.apply(tool1.context, [h1]); InspectorUI.inspectNode(p2);
tool2.onSelect.apply(tool2.context, [h1]);
tool3.onSelect.apply(tool3.context, [h1]);
info("Calling hide method for all tools"); info("Calling hide method for all tools");
tool1.onHide.apply(tool1.context, [h1]); InspectorUI.toolHide(tool1);
tool2.onHide.apply(tool2.context, [h1]); InspectorUI.toolHide(tool2);
tool3.onHide.apply(tool3.context, [h1]); InspectorUI.toolHide(tool3);
info("Checking panel states 3"); info("Checking panel states 3");
ok(tool1.context.panelIsClosed, "Panel 1 is closed"); ok(!tool1.isOpen, "Panel 1 is closed");
ok(tool2.context.panelIsClosed, "Panel 2 is closed"); ok(!tool2.isOpen, "Panel 2 is closed");
ok(tool3.context.panelIsClosed, "Panel 3 is closed"); ok(!tool3.isOpen, "Panel 3 is closed");
info("Showing tools 1 & 3"); info("Showing tools 1 & 3");
tool1.onShow.apply(tool1.context, [h1]); InspectorUI.toolShow(tool1);
tool3.onShow.apply(tool3.context, [h1]); InspectorUI.toolShow(tool3);
info("Checking panel states 4"); info("Checking panel states 4");
ok(tool1.context.panelIsOpen, "Panel 1 is open"); ok(tool1.isOpen, "Panel 1 is open");
ok(tool2.context.panelIsClosed, "Panel 2 is closed"); ok(!tool2.isOpen, "Panel 2 is closed");
ok(tool3.context.panelIsOpen, "Panel 3 is open"); ok(tool3.isOpen, "Panel 3 is open");
gBrowser.selectedTab = gBrowser.addTab(); gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() { gBrowser.selectedBrowser.addEventListener("load", function() {
@ -160,24 +161,52 @@ function testSecondTab()
{ {
info("Opened second tab"); info("Opened second tab");
info("Checking panel states 5"); info("Checking panel states 5");
ok(tool1.context.panelIsClosed, "Panel 1 is closed");
ok(tool2.context.panelIsClosed, "Panel 2 is closed"); let tools = InspectorUI.tools;
ok(tool3.context.panelIsClosed, "Panel 3 is closed"); ok(!(tool1 in tools), "Panel 1 not in tools");
ok(!(tool2 in tools), "Panel 2 not in tools");
ok(!(tool3 in tools), "Panel 3 not in tools");
info("Closing current tab"); info("Closing current tab");
Services.obs.addObserver(testOriginalTab, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
}
function testOriginalTab()
{
Services.obs.removeObserver(testOriginalTab, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
info("Checking panel states 6"); info("Checking panel states 6");
ok(tool1.context.panelIsOpen, "Panel 1 is open");
ok(tool2.context.panelIsClosed, "Panel 2 is closed");
ok(tool3.context.panelIsOpen, "Panel 3 is open");
executeSoon(finishUp); info("Tools: " + InspectorUI.tools);
// reacquaint ourselves with our tools
tool1 = InspectorUI.tools["tool_1"];
tool2 = InspectorUI.tools["tool_2"];
tool3 = InspectorUI.tools["tool_3"];
ok(tool1.isOpen, "Panel 1 is open after reactivation");
ok(!tool2.isOpen, "Panel 2 is closed after reactivation");
ok(tool3.isOpen, "Panel 3 is open after reactivation");
Services.obs.addObserver(unregisterTools, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
InspectorUI.closeInspectorUI(true);
}
function unregisterTools()
{
Services.obs.removeObserver(unregisterTools, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
let tools = InspectorUI.tools;
ok(!(tool1 in tools), "Tool 1 removed");
ok(!(tool2 in tools), "Tool 2 removed");
ok(!(tool3 in tools), "Tool 3 removed");
is(tools.length, toolsLength, "Number of Registered Tools matches original");
is(InspectorUI.toolEvents.length, toolEvents, "Number of tool events matches original");
finishUp();
} }
function finishUp() { function finishUp() {
InspectorUI.closeInspectorUI(true);
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
InspectorUI.initTools = initToolsMethod;
finish(); finish();
} }
@ -188,7 +217,7 @@ function test()
gBrowser.selectedBrowser.addEventListener("load", function() { gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
doc = content.document; doc = content.document;
waitForFocus(registerTools, content); waitForFocus(createDocument, content);
}, true); }, true);
content.location = "data:text/html,registertool tests for inspector"; content.location = "data:text/html,registertool tests for inspector";
@ -196,10 +225,12 @@ function test()
function registerTools() function registerTools()
{ {
createDocument(); InspectorUI.initTools = function() {
registerTool(new testTool("tool_1", "Tool 1", "Tool 1 tooltip", "I")); info("(re)registering tools");
registerTool(new testTool("tool_2", "Tool 2", "Tool 2 tooltip", "J")); registerTool(new testTool("tool_1", "Tool 1", "Tool 1 tooltip", "I"));
registerTool(new testTool("tool_3", "Tool 3", "Tool 3 tooltip", "K")); registerTool(new testTool("tool_2", "Tool 2", "Tool 2 tooltip", "J"));
registerTool(new testTool("tool_3", "Tool 3", "Tool 3 tooltip", "K"));
}
} }
function registerTool(aTool) function registerTool(aTool)
@ -210,10 +241,11 @@ function registerTool(aTool)
tooltiptext: aTool.tooltip, tooltiptext: aTool.tooltip,
accesskey: aTool.accesskey, accesskey: aTool.accesskey,
context: aTool, context: aTool,
get isOpen() aTool.isOpen(),
onSelect: aTool.selectNode, onSelect: aTool.selectNode,
onShow: aTool.show, show: aTool.show,
onHide: aTool.hide, hide: aTool.hide,
panel: aTool.panel unregister: aTool.destroy,
}); });
} }
@ -223,19 +255,13 @@ function testTool(aToolId, aLabel, aTooltip, aAccesskey)
this.id = aToolId; this.id = aToolId;
this.label = aLabel; this.label = aLabel;
this.tooltip = aTooltip; this.tooltip = aTooltip;
this.accesskey = aAccesskey this.accesskey = aAccesskey;
this.panel = this.createPanel(); this._isOpen = false;
} }
testTool.prototype = { testTool.prototype = {
get panelIsOpen() isOpen: function BIR_isOpen() {
{ return this._isOpen;
return this.panel.state == "open" || this.panel.state == "showing";
},
get panelIsClosed()
{
return this.panel.state == "closed" || this.panel.state == "hiding";
}, },
selectNode: function BIR_selectNode(aNode) { selectNode: function BIR_selectNode(aNode) {
@ -244,32 +270,23 @@ testTool.prototype = {
}, },
show: function BIR_show(aNode) { show: function BIR_show(aNode) {
this.panel.openPopup(gBrowser.selectedBrowser, this._isOpen = true;
"end_before", 0, 20, false, false);
is(InspectorUI.selection, aNode, is(InspectorUI.selection, aNode,
"show: currently selected node was passed: " + this.id); "show: currently selected node was passed: " + this.id);
}, },
hide: function BIR_hide() { hide: function BIR_hide() {
info(this.id + " hide"); info(this.id + " hide");
this.panel.hidePopup(); this._isOpen = false;
}, },
createPanel: function BIR_createPanel() { destroy: function BIR_destroy() {
let popupSet = document.getElementById("mainPopupSet"); info("tool destroyed " + this.id);
let ns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; if (this.isOpen())
let panel = this.panel = document.createElementNS(ns, "panel"); this.hide();
panel.setAttribute("orient", "vertical"); delete this.id;
panel.setAttribute("noautofocus", "true"); delete this.label;
panel.setAttribute("noautohide", "true"); delete this.tooltip;
panel.setAttribute("titlebar", "normal"); delete this.accesskey;
panel.setAttribute("close", "true");
panel.setAttribute("label", "Panel for " + this.id);
panel.setAttribute("width", 200);
panel.setAttribute("height", 400);
popupSet.appendChild(panel);
ok(panel.parentNode == popupSet, "Panel created and appended successfully");
return panel;
}, },
}; };

View File

@ -65,16 +65,16 @@ function createDocument()
function toggleInspector() function toggleInspector()
{ {
Services.obs.addObserver(inspectNode, INSPECTOR_NOTIFICATIONS.OPENED, false); Services.obs.addObserver(inspectNode, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI(); InspectorUI.toggleInspectorUI();
} }
function inspectNode() function inspectNode()
{ {
Services.obs.removeObserver(inspectNode, Services.obs.removeObserver(inspectNode,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
Services.obs.addObserver(performScrollingTest, Services.obs.addObserver(performScrollingTest,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
executeSoon(function() { executeSoon(function() {
InspectorUI.inspectNode(div); InspectorUI.inspectNode(div);
@ -84,7 +84,7 @@ function inspectNode()
function performScrollingTest() function performScrollingTest()
{ {
Services.obs.removeObserver(performScrollingTest, Services.obs.removeObserver(performScrollingTest,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
EventUtils.synthesizeMouseScroll(div, 10, 10, EventUtils.synthesizeMouseScroll(div, 10, 10,
{axis:"vertical", delta:50, type:"MozMousePixelScroll"}, {axis:"vertical", delta:50, type:"MozMousePixelScroll"},

View File

@ -39,8 +39,8 @@
function test() function test()
{ {
ok(window.InspectorUI, "InspectorUI variable exists"); let InspectorStore = InspectorUI.store;
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
is(InspectorStore.length, 0, "InspectorStore is empty"); is(InspectorStore.length, 0, "InspectorStore is empty");
ok(InspectorStore.isEmpty(), "InspectorStore is empty (confirmed)"); ok(InspectorStore.isEmpty(), "InspectorStore is empty (confirmed)");
is(typeof InspectorStore.store, "object", is(typeof InspectorStore.store, "object",

View File

@ -47,23 +47,23 @@ function inspectorTabOpen1()
{ {
ok(window.InspectorUI, "InspectorUI variable exists"); ok(window.InspectorUI, "InspectorUI variable exists");
ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(InspectorStore.isEmpty(), "InspectorStore is empty"); ok(InspectorUI.store.isEmpty(), "Inspector.store is empty");
Services.obs.addObserver(inspectorUIOpen1, Services.obs.addObserver(inspectorUIOpen1,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.openInspectorUI(); InspectorUI.openInspectorUI();
} }
function inspectorUIOpen1() function inspectorUIOpen1()
{ {
Services.obs.removeObserver(inspectorUIOpen1, Services.obs.removeObserver(inspectorUIOpen1,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
// Make sure the inspector is open. // Make sure the inspector is open.
ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
ok(!InspectorStore.isEmpty(), "InspectorStore is not empty"); ok(!InspectorUI.store.isEmpty(), "InspectorUI.store is not empty");
is(InspectorStore.length, 1, "InspectorStore.length = 1"); is(InspectorUI.store.length, 1, "Inspector.store.length = 1");
// Highlight a node. // Highlight a node.
div = content.document.getElementsByTagName("div")[0]; div = content.document.getElementsByTagName("div")[0];
@ -87,13 +87,13 @@ function inspectorTabOpen2()
{ {
// Make sure the inspector is closed. // Make sure the inspector is closed.
ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(!InspectorUI.isPanelOpen, "Inspector Tree Panel is closed"); ok(!InspectorUI.treePanel, "Inspector Tree Panel is closed");
is(InspectorStore.length, 1, "InspectorStore.length = 1"); is(InspectorUI.store.length, 1, "Inspector.store.length = 1");
// Activate the inspector again. // Activate the inspector again.
executeSoon(function() { executeSoon(function() {
Services.obs.addObserver(inspectorUIOpen2, Services.obs.addObserver(inspectorUIOpen2,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.openInspectorUI(); InspectorUI.openInspectorUI();
}); });
} }
@ -101,12 +101,12 @@ function inspectorTabOpen2()
function inspectorUIOpen2() function inspectorUIOpen2()
{ {
Services.obs.removeObserver(inspectorUIOpen2, Services.obs.removeObserver(inspectorUIOpen2,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
// Make sure the inspector is open. // Make sure the inspector is open.
ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
is(InspectorStore.length, 2, "InspectorStore.length = 2"); is(InspectorUI.store.length, 2, "Inspector.store.length = 2");
// Disable highlighting. // Disable highlighting.
InspectorUI.toggleInspection(); InspectorUI.toggleInspection();
@ -115,7 +115,7 @@ function inspectorUIOpen2()
// Switch back to tab 1. // Switch back to tab 1.
executeSoon(function() { executeSoon(function() {
Services.obs.addObserver(inspectorFocusTab1, Services.obs.addObserver(inspectorFocusTab1,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
gBrowser.selectedTab = tab1; gBrowser.selectedTab = tab1;
}); });
} }
@ -123,29 +123,78 @@ function inspectorUIOpen2()
function inspectorFocusTab1() function inspectorFocusTab1()
{ {
Services.obs.removeObserver(inspectorFocusTab1, Services.obs.removeObserver(inspectorFocusTab1,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
// Make sure the inspector is still open. // Make sure the inspector is still open.
ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
is(InspectorStore.length, 2, "InspectorStore.length = 2"); is(InspectorUI.store.length, 2, "Inspector.store.length = 2");
is(InspectorUI.selection, div, "selection matches the div element");
Services.obs.addObserver(inspectorOpenTreePanelTab1,
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
InspectorUI.treePanel.open();
}
function inspectorOpenTreePanelTab1()
{
Services.obs.removeObserver(inspectorOpenTreePanelTab1,
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
is(InspectorUI.store.length, 2, "Inspector.store.length = 2");
is(InspectorUI.selection, div, "selection matches the div element"); is(InspectorUI.selection, div, "selection matches the div element");
// Switch back to tab 2. // Switch back to tab 2.
Services.obs.addObserver(inspectorFocusTab2, Services.obs.addObserver(inspectorFocusTab2,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
gBrowser.selectedTab = tab2; gBrowser.selectedTab = tab2;
} }
function inspectorFocusTab2() function inspectorFocusTab2()
{ {
Services.obs.removeObserver(inspectorFocusTab2, Services.obs.removeObserver(inspectorFocusTab2,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
// Make sure the inspector is still open. // Make sure the inspector is still open.
ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
is(InspectorStore.length, 2, "InspectorStore.length = 2"); is(InspectorUI.store.length, 2, "Inspector.store.length is 2");
isnot(InspectorUI.selection, div, "selection does not match the div element");
// Switch back to tab 1.
Services.obs.addObserver(inspectorSecondFocusTab1,
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
gBrowser.selectedTab = tab1;
}
function inspectorSecondFocusTab1()
{
Services.obs.removeObserver(inspectorSecondFocusTab1,
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
is(InspectorUI.store.length, 2, "Inspector.store.length = 2");
is(InspectorUI.selection, div, "selection matches the div element");
// Switch back to tab 2.
Services.obs.addObserver(inspectorSecondFocusTab2,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
gBrowser.selectedTab = tab2;
}
function inspectorSecondFocusTab2()
{
Services.obs.removeObserver(inspectorSecondFocusTab2,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
// Make sure the inspector is still open.
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
is(InspectorUI.store.length, 2, "Inspector.store.length is 2");
isnot(InspectorUI.selection, div, "selection does not match the div element"); isnot(InspectorUI.selection, div, "selection does not match the div element");
// Remove tab 1. // Remove tab 1.
@ -161,8 +210,8 @@ function inspectorTabUnload1(evt)
// Make sure the Inspector is still open and that the state is correct. // Make sure the Inspector is still open and that the state is correct.
ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
is(InspectorStore.length, 1, "InspectorStore.length = 1"); is(InspectorUI.store.length, 1, "Inspector.store.length = 1");
InspectorUI.closeInspectorUI(); InspectorUI.closeInspectorUI();
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();

View File

@ -17,43 +17,47 @@ function test() {
waitForFocus(setupTest, content); waitForFocus(setupTest, content);
}, true); }, true);
content.location = "data:text/html,<div><p></p></div>"; content.location = 'data:text/html,<div style="width: 200px; height: 200px"><p></p></div>';
function setupTest() { function setupTest() {
node1 = doc.querySelector("div"); node1 = doc.querySelector("div");
node2 = doc.querySelector("p"); node2 = doc.querySelector("p");
Services.obs.addObserver(runTests, INSPECTOR_NOTIFICATIONS.OPENED, false); Services.obs.addObserver(runTests, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI(); InspectorUI.toggleInspectorUI();
} }
function runTests() { function runTests() {
Services.obs.removeObserver(runTests, INSPECTOR_NOTIFICATIONS.OPENED); Services.obs.removeObserver(runTests, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
testNode1(); Services.obs.addObserver(testNode1, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
InspectorUI.select(node1, true, true, true);
InspectorUI.openTreePanel();
} }
function testNode1() { function testNode1() {
let box = InspectorUI.ioBox.createObjectBox(node1); dump("testNode1\n");
box.click(); Services.obs.removeObserver(testNode1, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
executeSoon(function() { is(InspectorUI.selection, node1, "selection matches node");
is(InspectorUI.selection, node1, "selection matches node"); is(InspectorUI.highlighter.node, node1, "selection matches node");
is(InspectorUI.highlighter.node, node1, "selection matches node"); testNode2();
testNode2();
});
} }
function testNode2() { function testNode2() {
let box = InspectorUI.ioBox.createObjectBox(node2); dump("testNode2\n")
box.click(); Services.obs.addObserver(testHighlightingNode2, InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
executeSoon(function() { InspectorUI.treePanelSelect("node2");
is(InspectorUI.selection, node2, "selection matches node"); }
is(InspectorUI.highlighter.node, node2, "selection matches node");
Services.obs.addObserver(finishUp, INSPECTOR_NOTIFICATIONS.CLOSED, false); function testHighlightingNode2() {
InspectorUI.closeInspectorUI(); dump("testHighlightingNode2\n")
}); Services.obs.removeObserver(testHighlightingNode2, InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
is(InspectorUI.selection, node2, "selection matches node");
is(InspectorUI.highlighter.node, node2, "selection matches node");
Services.obs.addObserver(finishUp, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
InspectorUI.closeInspectorUI();
} }
function finishUp() { function finishUp() {
Services.obs.removeObserver(finishUp, INSPECTOR_NOTIFICATIONS.CLOSED); Services.obs.removeObserver(finishUp, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
doc = node1 = node2 = null; doc = node1 = node2 = null;
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
finish(); finish();

View File

@ -64,17 +64,26 @@ function xhr_onReadyStateChange() {
xhr = null; xhr = null;
Services.obs.addObserver(inspectorOpened, Services.obs.addObserver(inspectorOpened,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.openInspectorUI(); InspectorUI.openInspectorUI();
} }
function inspectorOpened() function inspectorOpened()
{ {
Services.obs.removeObserver(inspectorOpened, Services.obs.removeObserver(inspectorOpened,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
Services.obs.addObserver(treePanelOpened, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
InspectorUI.treePanel.open();
}
function treePanelOpened()
{
Services.obs.removeObserver(treePanelOpened,
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
ok(InspectorUI.inspecting, "Inspector is highlighting"); ok(InspectorUI.inspecting, "Inspector is highlighting");
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open"); ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
InspectorUI.stopInspecting(); InspectorUI.stopInspecting();
ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(!InspectorUI.inspecting, "Inspector is not highlighting");
@ -91,23 +100,23 @@ function inspectorOpened()
ok(iframeDiv, "Found the div element inside the iframe"); ok(iframeDiv, "Found the div element inside the iframe");
InspectorUI.inspectNode(iframeDiv); InspectorUI.inspectNode(iframeDiv);
ok(InspectorUI.treePanelDiv, "InspectorUI.treePanelDiv is available"); ok(InspectorUI.treePanel.treePanelDiv, "InspectorUI.treePanelDiv is available");
is(InspectorUI.treePanelDiv.innerHTML.replace(/^\s+|\s+$/mg, ''), is(InspectorUI.treePanel.treePanelDiv.innerHTML.replace(/^\s+|\s+$/mg, ''),
expectedResult, "treePanelDiv.innerHTML is correct"); expectedResult, "treePanelDiv.innerHTML is correct");
expectedResult = null; expectedResult = null;
Services.obs.addObserver(inspectorClosed, Services.obs.addObserver(inspectorClosed,
INSPECTOR_NOTIFICATIONS.CLOSED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
InspectorUI.closeInspectorUI(); InspectorUI.closeInspectorUI();
} }
function inspectorClosed() function inspectorClosed()
{ {
Services.obs.removeObserver(inspectorClosed, Services.obs.removeObserver(inspectorClosed,
INSPECTOR_NOTIFICATIONS.CLOSED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
ok(!InspectorUI.inspecting, "Inspector is not highlighting"); ok(!InspectorUI.inspecting, "Inspector is not highlighting");
ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is not open"); ok(!InspectorUI.treePanel, "Inspector Tree Panel is not open");
gBrowser.removeCurrentTab(); gBrowser.removeCurrentTab();
finish(); finish();

View File

@ -68,16 +68,16 @@ function setupSelectionTests()
h1 = doc.querySelectorAll("h1")[0]; h1 = doc.querySelectorAll("h1")[0];
ok(h1, "we have the header node"); ok(h1, "we have the header node");
Services.obs.addObserver(runSelectionTests, Services.obs.addObserver(runSelectionTests,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.openInspectorUI(); InspectorUI.openInspectorUI();
} }
function runSelectionTests() function runSelectionTests()
{ {
Services.obs.removeObserver(runSelectionTests, Services.obs.removeObserver(runSelectionTests,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
Services.obs.addObserver(performTestComparisons, Services.obs.addObserver(performTestComparisons,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
executeSoon(function() { executeSoon(function() {
InspectorUI.inspectNode(h1); InspectorUI.inspectNode(h1);
}); });
@ -86,7 +86,7 @@ function runSelectionTests()
function performTestComparisons(evt) function performTestComparisons(evt)
{ {
Services.obs.removeObserver(performTestComparisons, Services.obs.removeObserver(performTestComparisons,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
is(h1, InspectorUI.selection, "selection matches node"); is(h1, InspectorUI.selection, "selection matches node");
ok(InspectorUI.highlighter.isHighlighting, "highlighter is highlighting"); ok(InspectorUI.highlighter.isHighlighting, "highlighter is highlighting");

View File

@ -1,4 +1,5 @@
browser.jar: browser.jar:
* content/browser/inspector.html (highlighter/inspector.html)
content/browser/NetworkPanel.xhtml (webconsole/NetworkPanel.xhtml) content/browser/NetworkPanel.xhtml (webconsole/NetworkPanel.xhtml)
* content/browser/scratchpad.xul (scratchpad/scratchpad.xul) * content/browser/scratchpad.xul (scratchpad/scratchpad.xul)
* content/browser/scratchpad.js (scratchpad/scratchpad.js) * content/browser/scratchpad.js (scratchpad/scratchpad.js)

View File

@ -12,11 +12,11 @@
# for the specific language governing rights and limitations under the # for the specific language governing rights and limitations under the
# License. # License.
# #
# The Original Code is HUDService code. # The Original Code is Scratchpad Build Code.
# #
# The Initial Developer of the Original Code is Mozilla Corporation. # The Initial Developer of the Original Code is The Mozilla Foundation.
# #
# Portions created by the Initial Developer are Copyright (C) 2010 # Portions created by the Initial Developer are Copyright (C) 2011
# the Initial Developer. All Rights Reserved. # the Initial Developer. All Rights Reserved.
# #
# Contributor(s): # Contributor(s):
@ -44,9 +44,7 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk include $(DEPTH)/config/autoconf.mk
ifdef ENABLE_TESTS ifdef ENABLE_TESTS
ifneq (mobile,$(MOZ_BUILD_APP))
DIRS += test DIRS += test
endif endif
endif
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

View File

@ -21,9 +21,10 @@
* the Initial Developer. All Rights Reserved. * the Initial Developer. All Rights Reserved.
* *
* Contributor(s): * Contributor(s):
* Joe Walker (jwalker@mozilla.com) (original author) * Joe Walker (jwalker@mozilla.com) (Original Author)
* Mihai Șucan <mihai.sucan@gmail.com> * Mihai Șucan <mihai.sucan@gmail.com>
* Michael Ratcliffe <mratcliffe@mozilla.com> * Michael Ratcliffe <mratcliffe@mozilla.com>
* Rob Campbell <rcampbell@mozilla.com>
* *
* Alternatively, the contents of this file may be used under the terms of * 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 * either the GNU General Public License Version 2 or later (the "GPL"), or

View File

@ -21,7 +21,8 @@
* the Initial Developer. All Rights Reserved. * the Initial Developer. All Rights Reserved.
* *
* Contributor(s): * Contributor(s):
* Mike Ratcliffe <mratcliffe@mozilla.com> * Mike Ratcliffe <mratcliffe@mozilla.com> (Original Author)
* Rob Campbell <rcampbell@mozilla.com>
* *
* Alternatively, the contents of this file may be used under the terms of * 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 * either the GNU General Public License Version 2 or later (the "GPL"), or
@ -109,8 +110,6 @@ var StyleInspector = {
let iframeReady = false; let iframeReady = false;
function SI_iframeOnload() { function SI_iframeOnload() {
iframe.removeEventListener("load", SI_iframeOnload, true); iframe.removeEventListener("load", SI_iframeOnload, true);
panel.cssLogic = new CssLogic();
panel.cssHtmlTree = new CssHtmlTree(iframe, panel.cssLogic, panel);
iframeReady = true; iframeReady = true;
if (panelReady) { if (panelReady) {
SI_popupShown.call(panel); SI_popupShown.call(panel);
@ -124,6 +123,10 @@ var StyleInspector = {
function SI_popupShown() { function SI_popupShown() {
panelReady = true; panelReady = true;
if (iframeReady) { if (iframeReady) {
if (!this.cssLogic) {
this.cssLogic = new CssLogic();
this.cssHtmlTree = new CssHtmlTree(iframe, this.cssLogic, this);
}
let selectedNode = this.selectedNode || null; let selectedNode = this.selectedNode || null;
this.cssLogic.highlight(selectedNode); this.cssLogic.highlight(selectedNode);
this.cssHtmlTree.highlight(selectedNode); this.cssHtmlTree.highlight(selectedNode);
@ -162,12 +165,9 @@ var StyleInspector = {
panel.selectNode = function SI_selectNode(aNode) panel.selectNode = function SI_selectNode(aNode)
{ {
this.selectedNode = aNode; this.selectedNode = aNode;
if (this.isOpen()) { if (this.isOpen() && !this.hasAttribute("dimmed")) {
this.cssLogic.highlight(aNode); this.cssLogic.highlight(aNode);
this.cssHtmlTree.highlight(aNode); this.cssHtmlTree.highlight(aNode);
} else {
let win = Services.wm.getMostRecentWindow("navigator:browser");
this.openPopup(win.gBrowser.selectedBrowser, "end_before", 0, 0, false, false);
} }
}; };
@ -176,6 +176,10 @@ var StyleInspector = {
*/ */
panel.destroy = function SI_destroy() panel.destroy = function SI_destroy()
{ {
if (!this.cssLogic)
return;
if (this.isOpen())
this.hideTool();
this.cssLogic = null; this.cssLogic = null;
this.cssHtmlTree = null; this.cssHtmlTree = null;
this.removeEventListener("popupshown", SI_popupShown); this.removeEventListener("popupshown", SI_popupShown);
@ -184,6 +188,37 @@ var StyleInspector = {
Services.obs.notifyObservers(null, "StyleInspector-closed", null); Services.obs.notifyObservers(null, "StyleInspector-closed", null);
}; };
/**
* Dim or undim a panel by setting or removing a dimmed attribute.
*
* @param aState
* true = dim, false = undim
*/
panel.dimTool = function SI_dimTool(aState)
{
if (!this.isOpen())
return;
if (aState) {
this.setAttribute("dimmed", "true");
} else if (this.hasAttribute("dimmed")) {
this.removeAttribute("dimmed");
}
};
panel.showTool = function SI_showTool(aSelection)
{
this.selectNode(aSelection);
let win = Services.wm.getMostRecentWindow("navigator:browser");
this.openPopup(win.gBrowser.selectedBrowser, "end_before", 0, 0,
false, false);
};
panel.hideTool = function SI_hideTool()
{
this.hidePopup();
};
/** /**
* Is the Style Inspector initialized? * Is the Style Inspector initialized?
* @returns {Boolean} true or false * @returns {Boolean} true or false

View File

@ -174,26 +174,18 @@ function styleInspectorClosedFromConsole1()
{ {
Services.obs.removeObserver(styleInspectorClosedFromConsole1, Services.obs.removeObserver(styleInspectorClosedFromConsole1,
"StyleInspector-closed", false); "StyleInspector-closed", false);
info("Style Inspector 1 closed"); info("Style Inspector 1 and 2 closed");
Services.obs.addObserver(styleInspectorClosedFromConsole2,
"StyleInspector-closed", false);
}
function styleInspectorClosedFromConsole2()
{
Services.obs.removeObserver(styleInspectorClosedFromConsole2,
"StyleInspector-closed", false);
info("Style Inspector 2 closed");
executeSoon(cleanUp); executeSoon(cleanUp);
} }
function cleanUp() function cleanUp()
{ {
let popupSet = document.getElementById("mainPopupSet"); let panels = document.querySelector("panel[hudToolId]");
ok(!popupSet.lastChild.hasAttribute("hudToolId"), ok(!panels,
"all style inspector panels are now detached and ready for garbage collection"); "all style inspector panels are now detached and ready for garbage collection");
info("cleaning up"); info("cleaning up");
doc = hudBox = stylePanels = jsterm = null; doc = hudBox = stylePanels = jsterm = null;
finishTest(); finishTest();
} }

View File

@ -165,7 +165,10 @@ const LEVELS = {
info: SEVERITY_INFO, info: SEVERITY_INFO,
log: SEVERITY_LOG, log: SEVERITY_LOG,
trace: SEVERITY_LOG, trace: SEVERITY_LOG,
dir: SEVERITY_LOG dir: SEVERITY_LOG,
group: SEVERITY_LOG,
groupCollapsed: SEVERITY_LOG,
groupEnd: SEVERITY_LOG
}; };
// The lowest HTTP response code (inclusive) that is considered an error. // The lowest HTTP response code (inclusive) that is considered an error.
@ -252,6 +255,9 @@ const ERRORS = { LOG_MESSAGE_MISSING_ARGS:
LOG_OUTPUT_FAILED: "Log Failure: Could not append messageNode to outputNode", LOG_OUTPUT_FAILED: "Log Failure: Could not append messageNode to outputNode",
}; };
// The indent of a console group in pixels.
const GROUP_INDENT = 12;
/** /**
* Implements the nsIStreamListener and nsIRequestObserver interface. Used * Implements the nsIStreamListener and nsIRequestObserver interface. Used
* within the HS_httpObserverFactory function to get the response body of * within the HS_httpObserverFactory function to get the response body of
@ -2005,6 +2011,20 @@ HUD_SERVICE.prototype =
sourceLine = aMessage.lineNumber; sourceLine = aMessage.lineNumber;
break; break;
case "group":
case "groupCollapsed":
clipboardText = body = formatResult(args);
sourceURL = aMessage.filename;
sourceLine = aMessage.lineNumber;
hud.groupDepth++;
break;
case "groupEnd":
if (hud.groupDepth > 0) {
hud.groupDepth--;
}
return;
default: default:
Cu.reportError("Unknown Console API log level: " + level); Cu.reportError("Unknown Console API log level: " + level);
return; return;
@ -2014,6 +2034,7 @@ HUD_SERVICE.prototype =
CATEGORY_WEBDEV, CATEGORY_WEBDEV,
LEVELS[level], LEVELS[level],
body, body,
aHUDId,
sourceURL, sourceURL,
sourceLine, sourceLine,
clipboardText, clipboardText,
@ -2076,7 +2097,8 @@ HUD_SERVICE.prototype =
let chromeDocument = hud.HUDBox.ownerDocument; let chromeDocument = hud.HUDBox.ownerDocument;
let message = stringBundle.GetStringFromName("ConsoleAPIDisabled"); let message = stringBundle.GetStringFromName("ConsoleAPIDisabled");
let node = ConsoleUtils.createMessageNode(chromeDocument, CATEGORY_JS, let node = ConsoleUtils.createMessageNode(chromeDocument, CATEGORY_JS,
SEVERITY_WARNING, message); SEVERITY_WARNING, message,
aHUDId);
ConsoleUtils.outputMessageNode(node, aHUDId); ConsoleUtils.outputMessageNode(node, aHUDId);
}, },
@ -2116,6 +2138,7 @@ HUD_SERVICE.prototype =
aCategory, aCategory,
severity, severity,
aScriptError.errorMessage, aScriptError.errorMessage,
hudId,
aScriptError.sourceName, aScriptError.sourceName,
aScriptError.lineNumber); aScriptError.lineNumber);
@ -2576,6 +2599,7 @@ HUD_SERVICE.prototype =
CATEGORY_NETWORK, CATEGORY_NETWORK,
SEVERITY_LOG, SEVERITY_LOG,
msgNode, msgNode,
hudId,
null, null,
null, null,
clipboardText); clipboardText);
@ -3081,6 +3105,11 @@ HeadsUpDisplay.prototype = {
consolePanel: null, consolePanel: null,
/**
* The nesting depth of the currently active console group.
*/
groupDepth: 0,
get mainPopupSet() get mainPopupSet()
{ {
return this.chromeDocument.getElementById("mainPopupSet"); return this.chromeDocument.getElementById("mainPopupSet");
@ -4438,7 +4467,7 @@ function JSTermHelper(aJSTerm)
if (!errstr) { if (!errstr) {
let stylePanel = StyleInspector.createPanel(); let stylePanel = StyleInspector.createPanel();
stylePanel.setAttribute("hudToolId", aJSTerm.hudId); stylePanel.setAttribute("hudToolId", aJSTerm.hudId);
stylePanel.selectNode(aNode); stylePanel.showTool(aNode);
} else { } else {
aJSTerm.writeOutput(errstr + "\n", CATEGORY_OUTPUT, SEVERITY_ERROR); aJSTerm.writeOutput(errstr + "\n", CATEGORY_OUTPUT, SEVERITY_ERROR);
} }
@ -4752,7 +4781,8 @@ JSTerm.prototype = {
let node = ConsoleUtils.createMessageNode(this.parentNode.ownerDocument, let node = ConsoleUtils.createMessageNode(this.parentNode.ownerDocument,
CATEGORY_OUTPUT, CATEGORY_OUTPUT,
SEVERITY_LOG, SEVERITY_LOG,
aOutputString); aOutputString,
this.hudId);
let linkNode = node.querySelector(".webconsole-msg-body"); let linkNode = node.querySelector(".webconsole-msg-body");
@ -4799,7 +4829,7 @@ JSTerm.prototype = {
{ {
let node = ConsoleUtils.createMessageNode(this.parentNode.ownerDocument, let node = ConsoleUtils.createMessageNode(this.parentNode.ownerDocument,
aCategory, aSeverity, aCategory, aSeverity,
aOutputMessage); aOutputMessage, this.hudId);
ConsoleUtils.outputMessageNode(node, this.hudId); ConsoleUtils.outputMessageNode(node, this.hudId);
}, },
@ -5540,6 +5570,8 @@ ConsoleUtils = {
* The severity of the message: one of the SEVERITY_* constants; * The severity of the message: one of the SEVERITY_* constants;
* @param string|nsIDOMNode aBody * @param string|nsIDOMNode aBody
* The body of the message, either a simple string or a DOM node. * The body of the message, either a simple string or a DOM node.
* @param number aHUDId
* The HeadsUpDisplay ID.
* @param string aSourceURL [optional] * @param string aSourceURL [optional]
* The URL of the source file that emitted the error. * The URL of the source file that emitted the error.
* @param number aSourceLine [optional] * @param number aSourceLine [optional]
@ -5557,8 +5589,8 @@ ConsoleUtils = {
*/ */
createMessageNode: createMessageNode:
function ConsoleUtils_createMessageNode(aDocument, aCategory, aSeverity, function ConsoleUtils_createMessageNode(aDocument, aCategory, aSeverity,
aBody, aSourceURL, aSourceLine, aBody, aHUDId, aSourceURL,
aClipboardText, aLevel) { aSourceLine, aClipboardText, aLevel) {
if (aBody instanceof Ci.nsIDOMNode && aClipboardText == null) { if (aBody instanceof Ci.nsIDOMNode && aClipboardText == null) {
throw new Error("HUDService.createMessageNode(): DOM node supplied " + throw new Error("HUDService.createMessageNode(): DOM node supplied " +
"without any clipboard text"); "without any clipboard text");
@ -5569,6 +5601,9 @@ ConsoleUtils = {
// long multi-line messages. // long multi-line messages.
let iconContainer = aDocument.createElementNS(XUL_NS, "vbox"); let iconContainer = aDocument.createElementNS(XUL_NS, "vbox");
iconContainer.classList.add("webconsole-msg-icon-container"); iconContainer.classList.add("webconsole-msg-icon-container");
// Apply the curent group by indenting appropriately.
let hud = HUDService.getHudReferenceById(aHUDId);
iconContainer.style.marginLeft = hud.groupDepth * GROUP_INDENT + "px";
// Make the icon node. It's sprited and the actual region of the image is // Make the icon node. It's sprited and the actual region of the image is
// determined by CSS rules. // determined by CSS rules.
@ -6669,6 +6704,7 @@ ConsoleProgressListener.prototype = {
CATEGORY_NETWORK, CATEGORY_NETWORK,
SEVERITY_LOG, SEVERITY_LOG,
msgNode, msgNode,
this.hudId,
null, null,
null, null,
uri.spec); uri.spec);

View File

@ -145,6 +145,7 @@ _BROWSER_TEST_FILES = \
browser_webconsole_bug_653531_highlighter_console_helper.js \ browser_webconsole_bug_653531_highlighter_console_helper.js \
browser_webconsole_bug_659907_console_dir.js \ browser_webconsole_bug_659907_console_dir.js \
browser_webconsole_bug_678816.js \ browser_webconsole_bug_678816.js \
browser_webconsole_bug_664131_console_group.js \
head.js \ head.js \
$(NULL) $(NULL)

View File

@ -25,7 +25,8 @@ function populateConsoleRepeats(aHudRef) {
let node = ConsoleUtils.createMessageNode(hud.ownerDocument, let node = ConsoleUtils.createMessageNode(hud.ownerDocument,
CATEGORY_CSS, CATEGORY_CSS,
SEVERITY_WARNING, SEVERITY_WARNING,
"css log x"); "css log x",
aHudRef.hudId);
ConsoleUtils.outputMessageNode(node, aHudRef.hudId); ConsoleUtils.outputMessageNode(node, aHudRef.hudId);
} }
} }
@ -38,7 +39,8 @@ function populateConsole(aHudRef) {
let node = ConsoleUtils.createMessageNode(hud.ownerDocument, let node = ConsoleUtils.createMessageNode(hud.ownerDocument,
CATEGORY_CSS, CATEGORY_CSS,
SEVERITY_WARNING, SEVERITY_WARNING,
"css log " + i); "css log " + i,
aHudRef.hudId);
ConsoleUtils.outputMessageNode(node, aHudRef.hudId); ConsoleUtils.outputMessageNode(node, aHudRef.hudId);
} }
} }

View File

@ -82,18 +82,18 @@ function setupHighlighterTests()
h1 = doc.querySelectorAll("h1")[0]; h1 = doc.querySelectorAll("h1")[0];
ok(h1, "we have the header node"); ok(h1, "we have the header node");
Services.obs.addObserver(runSelectionTests, Services.obs.addObserver(runSelectionTests,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI(); InspectorUI.toggleInspectorUI();
} }
function runSelectionTests() function runSelectionTests()
{ {
Services.obs.removeObserver(runSelectionTests, Services.obs.removeObserver(runSelectionTests,
INSPECTOR_NOTIFICATIONS.OPENED, false); InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
executeSoon(function() { executeSoon(function() {
Services.obs.addObserver(performTestComparisons, Services.obs.addObserver(performTestComparisons,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
EventUtils.synthesizeMouse(h1, 2, 2, {type: "mousemove"}, content); EventUtils.synthesizeMouse(h1, 2, 2, {type: "mousemove"}, content);
}); });
} }
@ -101,7 +101,7 @@ function runSelectionTests()
function performTestComparisons(evt) function performTestComparisons(evt)
{ {
Services.obs.removeObserver(performTestComparisons, Services.obs.removeObserver(performTestComparisons,
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
InspectorUI.stopInspecting(); InspectorUI.stopInspecting();
ok(InspectorUI.highlighter.isHighlighting, "highlighter is highlighting"); ok(InspectorUI.highlighter.isHighlighting, "highlighter is highlighting");

View File

@ -0,0 +1,48 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Tests that console.group/groupEnd works as intended.
const GROUP_INDENT = 12;
function test() {
addTab("data:text/html,Web Console test for bug 664131: Expand console " +
"object with group methods");
browser.addEventListener("load", onLoad, true);
}
function onLoad(aEvent) {
browser.removeEventListener(aEvent.type, arguments.callee, true);
openConsole();
let hudId = HUDService.getHudIdByWindow(content);
let hud = HUDService.hudReferences[hudId];
outputNode = hud.outputNode;
content.console.group("a");
findLogEntry("a");
let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
is(msg.length, 1, "one message node displayed");
is(msg[0].style.marginLeft, GROUP_INDENT + "px", "correct group indent found");
content.console.log("inside");
findLogEntry("inside");
let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
is(msg.length, 2, "two message nodes displayed");
is(msg[1].style.marginLeft, GROUP_INDENT + "px", "correct group indent found");
content.console.groupEnd("a");
content.console.log("outside");
findLogEntry("outside");
let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
is(msg.length, 3, "three message nodes displayed");
is(msg[2].style.marginLeft, "0px", "correct group indent found");
content.console.groupCollapsed("b");
findLogEntry("b");
let msg = outputNode.querySelectorAll(".webconsole-msg-icon-container");
is(msg.length, 4, "four message nodes displayed");
is(msg[3].style.marginLeft, GROUP_INDENT + "px", "correct group indent found");
finishTest();
}

View File

@ -10,9 +10,6 @@
console.assert() console.assert()
console.clear() console.clear()
console.dirxml() console.dirxml()
console.group()
console.groupCollapsed()
console.groupEnd()
console.profile() console.profile()
console.profileEnd() console.profileEnd()
console.count() console.count()

View File

@ -7,3 +7,18 @@ confirmNavigationAway.buttonLeaveAccesskey=L
confirmNavigationAway.buttonStay=Stay on Page confirmNavigationAway.buttonStay=Stay on Page
confirmNavigationAway.buttonStayAccesskey=S confirmNavigationAway.buttonStayAccesskey=S
# LOCALIZATION NOTE (htmlPanel): Used in the Inspector tool's openInspectorUI
# method when registering the HTML panel.
# LOCALIZATION NOTE (htmlPanel.label): This is a lable for a button that
# activates the Web Developer->Inspect UI's HTML Tree Panel.
htmlPanel.label=HTML
# LOCALIZATION NOTE (htmlPanel.tooltiptext): The text that appears when a user
# hovers over the HTML panel's toolbar button.
htmlPanel.tooltiptext=HTML panel
# LOCALIZATION NOTE (htmlPanel.accesskey): The key bound to the HTML panel's
# toolbar button.
htmlPanel.accesskey=H

View File

@ -41,3 +41,9 @@ group.Positioning_and_Page_Flow=Positioning and Page Flow
group.Borders=Borders group.Borders=Borders
group.Lists=Lists group.Lists=Lists
group.Effects_and_Other=Effects and Other group.Effects_and_Other=Effects and Other
# LOCALIZATION NOTE (style.highlighter.button): These strings are used inside
# html tree of the highlighter for the style inspector button
style.highlighter.button.label=Style
style.highlighter.accesskey=S
style.highlighter.button.tooltip=Inspect element styles

View File

@ -1942,3 +1942,12 @@ panel[dimmed="true"] {
box-shadow: 0 0 0 1px black; box-shadow: 0 0 0 1px black;
outline-color: white; outline-color: white;
} }
/*
* need a "bumpy" background image for this!
*/
#inspector-horizontal-splitter {
background: none !important;
-moz-appearance: none;
cursor: n-resize;
}

View File

@ -2602,3 +2602,13 @@ panel[dimmed="true"] {
#inspector-tools > toolbarbutton[checked]:hover:active { #inspector-tools > toolbarbutton[checked]:hover:active {
background-color: hsla(210,8%,5%,.2); background-color: hsla(210,8%,5%,.2);
} }
/*
* need a "bumpy" background image for this!
*/
#inspector-horizontal-splitter {
background: none !important;
-moz-appearance: none;
cursor: n-resize;
}

View File

@ -2558,3 +2558,13 @@ panel[dimmed="true"] {
box-shadow: 0 0 0 1px black; box-shadow: 0 0 0 1px black;
outline-color: white; outline-color: white;
} }
/*
* need a "bumpy" background image for this!
*/
#inspector-horizontal-splitter {
background: none !important;
-moz-appearance: none;
cursor: n-resize;
}

View File

@ -94,6 +94,15 @@ ConsoleAPI.prototype = {
dir: function CA_dir() { dir: function CA_dir() {
self.notifyObservers(outerID, innerID, "dir", arguments); self.notifyObservers(outerID, innerID, "dir", arguments);
}, },
group: function CA_group() {
self.notifyObservers(outerID, innerID, "group", self.beginGroup(arguments));
},
groupCollapsed: function CA_groupCollapsed() {
self.notifyObservers(outerID, innerID, "groupCollapsed", self.beginGroup(arguments));
},
groupEnd: function CA_groupEnd() {
self.notifyObservers(outerID, innerID, "groupEnd", arguments);
},
__exposedProps__: { __exposedProps__: {
log: "r", log: "r",
info: "r", info: "r",
@ -101,7 +110,10 @@ ConsoleAPI.prototype = {
error: "r", error: "r",
debug: "r", debug: "r",
trace: "r", trace: "r",
dir: "r" dir: "r",
group: "r",
groupCollapsed: "r",
groupEnd: "r"
} }
}; };
@ -120,6 +132,9 @@ ConsoleAPI.prototype = {
debug: genPropDesc('debug'), debug: genPropDesc('debug'),
trace: genPropDesc('trace'), trace: genPropDesc('trace'),
dir: genPropDesc('dir'), dir: genPropDesc('dir'),
group: genPropDesc('group'),
groupCollapsed: genPropDesc('groupCollapsed'),
groupEnd: genPropDesc('groupEnd'),
__noSuchMethod__: { enumerable: true, configurable: true, writable: true, __noSuchMethod__: { enumerable: true, configurable: true, writable: true,
value: function() {} }, value: function() {} },
__mozillaConsole__: { value: true } __mozillaConsole__: { value: true }
@ -229,6 +244,13 @@ ConsoleAPI.prototype = {
} }
return stack; return stack;
},
/**
* Begin a new group for logging output together.
**/
beginGroup: function CA_beginGroup() {
return Array.prototype.join.call(arguments[0], " ");
} }
}; };

View File

@ -108,9 +108,52 @@ function testLocationData(aMessageObject) {
is(aMessageObject.arguments[i], a, "correct arg " + i); is(aMessageObject.arguments[i], a, "correct arg " + i);
}); });
// Test finished startGroupTest();
ConsoleObserver.destroy(); }
finish();
function startGroupTest() {
// Reset the observer function to cope with the fabricated test data.
ConsoleObserver.observe = function CO_observe(aSubject, aTopic, aData) {
try {
testConsoleGroup(aSubject.wrappedJSObject);
} catch (ex) {
// XXX Exceptions in this function currently aren't reported, because of
// some XPConnect weirdness, so report them manually
ok(false, "Exception thrown in CO_observe: " + ex);
}
};
let button = gWindow.document.getElementById("test-groups");
ok(button, "found #test-groups button");
EventUtils.synthesizeMouse(button, 2, 2, {}, gWindow);
}
function testConsoleGroup(aMessageObject) {
let messageWindow = getWindowByWindowId(aMessageObject.ID);
is(messageWindow, gWindow, "found correct window by window ID");
ok(aMessageObject.level == "group" ||
aMessageObject.level == "groupCollapsed" ||
aMessageObject.level == "groupEnd",
"expected level received");
is(aMessageObject.functionName, "testGroups", "functionName matches");
ok(aMessageObject.lineNumber >= 32 && aMessageObject.lineNumber <= 34,
"lineNumber matches");
if (aMessageObject.level == "groupCollapsed") {
ok(aMessageObject.arguments == "a group", "groupCollapsed arguments matches");
}
else if (aMessageObject.level == "group") {
ok(aMessageObject.arguments == "b group", "group arguments matches");
}
else if (aMessageObject.level == "groupEnd") {
ok(Array.prototype.join.call(aMessageObject.arguments, " ") == "b group", "groupEnd arguments matches");
}
if (aMessageObject.level == "groupEnd") {
// Test finished
ConsoleObserver.destroy();
finish();
}
} }
function startTraceTest() { function startTraceTest() {
@ -195,6 +238,9 @@ function consoleAPISanityTest() {
ok(win.console.error, "console.error is here"); ok(win.console.error, "console.error is here");
ok(win.console.trace, "console.trace is here"); ok(win.console.trace, "console.trace is here");
ok(win.console.dir, "console.dir is here"); ok(win.console.dir, "console.dir is here");
ok(win.console.group, "console.group is here");
ok(win.console.groupCollapsed, "console.groupCollapsed is here");
ok(win.console.groupEnd, "console.groupEnd is here");
} }
var ConsoleObserver = { var ConsoleObserver = {

View File

@ -27,6 +27,12 @@
console.warn(str); console.warn(str);
console.error(str); console.error(str);
} }
function testGroups() {
console.groupCollapsed("a", "group");
console.group("b", "group");
console.groupEnd("b", "group");
}
</script> </script>
</head> </head>
<body> <body>
@ -34,5 +40,6 @@
<button onclick="test();">Log stuff</button> <button onclick="test();">Log stuff</button>
<button id="test-trace" onclick="foobar585956a('omg');">Test trace</button> <button id="test-trace" onclick="foobar585956a('omg');">Test trace</button>
<button id="test-location" onclick="foobar646025('omg');">Test location</button> <button id="test-location" onclick="foobar646025('omg');">Test location</button>
<button id="test-groups" onclick="testGroups();">Test groups</button>
</body> </body>
</html> </html>

View File

@ -27,6 +27,9 @@ function doTest() {
"debug": "function", "debug": "function",
"trace": "function", "trace": "function",
"dir": "function", "dir": "function",
"group": "function",
"groupCollapsed": "function",
"groupEnd": "function",
"__noSuchMethod__": "function" "__noSuchMethod__": "function"
}; };

View File

@ -53,6 +53,7 @@
<content> <content>
<xul:hbox class="select-keep select-cell"> <xul:hbox class="select-keep select-cell">
<xul:checkbox class="addon-keep-checkbox" anonid="keep" <xul:checkbox class="addon-keep-checkbox" anonid="keep"
xbl:inherits="tooltiptext=name"
oncommand="document.getBindingParent(this).keepChanged();"/> oncommand="document.getBindingParent(this).keepChanged();"/>
</xul:hbox> </xul:hbox>
<xul:hbox class="select-icon select-cell"> <xul:hbox class="select-icon select-cell">

View File

@ -114,6 +114,10 @@
display: none; display: none;
} }
.select-keep .addon-keep-checkbox:-moz-focusring {
outline: 1px dotted ThreeDDarkShadow;
}
.select-icon { .select-icon {
width: 20px; width: 20px;
} }

View File

@ -124,6 +124,10 @@
width: 13px; width: 13px;
} }
.select-keep .addon-keep-checkbox:-moz-focusring {
outline: 1px dotted ThreeDDarkShadow;
}
.select-keep .checkbox-label-box { .select-keep .checkbox-label-box {
display: none; display: none;
} }