Merge central to inbound

This commit is contained in:
Marco Bonardo 2012-02-27 13:46:22 +01:00
commit b976af9f21
76 changed files with 2321 additions and 903 deletions

View File

@ -1028,6 +1028,9 @@ pref("devtools.errorconsole.enabled", false);
// Enable the Inspector
pref("devtools.inspector.enabled", true);
pref("devtools.inspector.htmlHeight", 112);
pref("devtools.inspector.htmlPanelOpen", false);
pref("devtools.inspector.sidebarOpen", false);
pref("devtools.inspector.activeSidebar", "ruleview");
// Enable the Debugger
pref("devtools.debugger.enabled", false);

View File

@ -25,6 +25,7 @@
# Shawn Wilsher <me@shawnwilsher.com>
# Ehsan Akhgari <ehsan.akhgari@gmail.com>
# Rob Campbell <rcampbell@mozilla.com>
# Paul Rouget <paul@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
@ -153,6 +154,14 @@
oncommand="InspectorUI.toggleSidebar();"/>
<command id="Inspector:Tilt"
oncommand="Tilt.initialize();"/>
<command id="Inspector:HTMLPanel"
oncommand="InspectorUI.toggleHTMLPanel();"/>
<command id="Inspector:CopyInner"
oncommand="InspectorUI.copyInnerHTML();"/>
<command id="Inspector:CopyOuter"
oncommand="InspectorUI.copyOuterHTML();"/>
<command id="Inspector:DeleteNode"
oncommand="InspectorUI.deleteNode();"/>
</commandset>
<broadcasterset id="mainBroadcasterSet">
@ -167,7 +176,7 @@
type="checkbox" group="sidebar"
sidebarurl="chrome://browser/content/history/history-panel.xul"
oncommand="toggleSidebar('viewHistorySidebar');"/>
<broadcaster id="viewWebPanelsSidebar" autoCheck="false"
type="checkbox" group="sidebar" sidebarurl="chrome://browser/content/web-panels.xul"
oncommand="toggleSidebar('viewWebPanelsSidebar');"/>

View File

@ -38,6 +38,7 @@
# David Dahl <ddahl@mozilla.com>
# Frank Yan <fyan@mozilla.com>
# Victor Porof <vporof@mozilla.com>
# Paul Rouget <paul@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
@ -227,20 +228,21 @@
</hbox>
</panel>
<panel id="inspector-tree-panel"
orient="vertical"
hidden="true"
ignorekeys="true"
noautofocus="true"
noautohide="true"
titlebar="normal"
close="true"
label="&inspectPanelTitle.label;">
<hbox id="tree-panel-resizer-box" align="end">
<spacer flex="1" />
<resizer dir="bottomend" />
</hbox>
</panel>
<menupopup id="inspector-node-popup">
<menuitem id="inspectorHTMLCopyInner"
label="&inspectorHTMLCopyInner.label;"
accesskey="&inspectorHTMLCopyInner.accesskey;"
command="Inspector:CopyInner"/>
<menuitem id="inspectorHTMLCopyOuter"
label="&inspectorHTMLCopyOuter.label;"
accesskey="&inspectorHTMLCopyOuter.accesskey;"
command="Inspector:CopyOuter"/>
<menuseparator/>
<menuitem id="inspectorHTMLDelete"
label="&inspectorHTMLDelete.label;"
accesskey="&inspectorHTMLDelete.accesskey;"
command="Inspector:DeleteNode"/>
</menupopup>
<menupopup id="toolbar-context-menu"
onpopupshowing="onViewToolbarsPopupShowing(event);">
@ -994,45 +996,44 @@
class="devtools-toolbar"
nowindowdrag="true"
hidden="true">
<vbox flex="1">
<resizer id="inspector-top-resizer" flex="1"
dir="top" disabled="true"
element="inspector-tree-box"/>
<hbox>
#ifdef XP_MACOSX
<toolbarbutton id="highlighter-closebutton"
oncommand="InspectorUI.closeInspectorUI(false);"
tooltiptext="&inspectCloseButton.tooltiptext;"/>
<toolbarbutton id="highlighter-closebutton"
oncommand="InspectorUI.closeInspectorUI(false);"
tooltiptext="&inspectCloseButton.tooltiptext;"/>
#endif
<toolbarbutton id="inspector-inspect-toolbutton"
class="devtools-toolbarbutton"
label="&inspectButton.label;"
accesskey="&inspectButton.accesskey;"
command="Inspector:Inspect"/>
<arrowscrollbox id="inspector-breadcrumbs"
flex="1" orient="horizontal"
clicktoscroll="true"/>
<hbox id="inspector-tools">
<toolbarbutton id="inspector-3D-button"
class="devtools-toolbarbutton"
hidden="true"
label="&inspect3DViewButton.label;"
accesskey="&inspect3DViewButton.accesskey;"
command="Inspector:Tilt"/>
<toolbarbutton id="inspector-style-button"
class="devtools-toolbarbutton"
label="&inspectStyleButton.label;"
accesskey="&inspectStyleButton.accesskey;"
command="Inspector:Sidebar"/>
<!-- registered tools go here -->
</hbox>
<toolbarbutton id="inspector-inspect-toolbutton"
class="devtools-toolbarbutton"
label="&inspectButton.label;"
accesskey="&inspectButton.accesskey;"
command="Inspector:Inspect"/>
<toolbarbutton id="inspector-treepanel-toolbutton"
class="devtools-toolbarbutton"
label="&htmlPanel.label;"
accesskey="&htmlPanel.accesskey;"
tooltiptext="&htmlPanel.tooltiptext;"
command="Inspector:HTMLPanel"/>
<arrowscrollbox id="inspector-breadcrumbs"
flex="1" orient="horizontal"
clicktoscroll="true"/>
<hbox id="inspector-tools">
<toolbarbutton id="inspector-3D-button"
class="devtools-toolbarbutton"
hidden="true"
label="&inspect3DViewButton.label;"
accesskey="&inspect3DViewButton.accesskey;"
command="Inspector:Tilt"/>
<toolbarbutton id="inspector-style-button"
class="devtools-toolbarbutton"
label="&inspectStyleButton.label;"
accesskey="&inspectStyleButton.accesskey;"
command="Inspector:Sidebar"/>
<!-- registered tools go here -->
</hbox>
#ifndef XP_MACOSX
<toolbarbutton id="highlighter-closebutton"
oncommand="InspectorUI.closeInspectorUI(false);"
tooltiptext="&inspectCloseButton.tooltiptext;"/>
<toolbarbutton id="highlighter-closebutton"
oncommand="InspectorUI.closeInspectorUI(false);"
tooltiptext="&inspectCloseButton.tooltiptext;"/>
#endif
</hbox>
</vbox>
</toolbar>
<toolbar id="addon-bar"
toolbarname="&addonBarCmd.label;" accesskey="&addonBarCmd.accesskey;"

View File

@ -34,14 +34,6 @@
direction: ltr;
}
#inspector-top-resizer {
display: none;
}
#inspector-toolbar[treepanel-open] > vbox > #inspector-top-resizer {
display: -moz-box;
}
/*
* Node Infobar
*/

View File

@ -349,7 +349,7 @@ DebuggerView.Properties = {
}
// compute the id of the element if not specified
aId = aId || (aName + "-scope");
aId = aId || (aName.toLowerCase().trim().replace(" ", "-") + "-scope");
// contains generic nodes and functionality
let element = this._createPropertyElement(aName, aId, "scope", this._vars);
@ -541,12 +541,12 @@ DebuggerView.Properties = {
* An array containing the key and grip properties, specifying
* the value and/or type & class of the variable (if the type
* is not specified, it will be inferred from the value).
* e.g. ["someProp0": 42]
* ["someProp1": true]
* ["someProp2": "nasu"]
* ["someProp3": { type: "undefined" }]
* ["someProp4": { type: "null" }]
* ["someProp5": { type: "object", class: "Object" }]
* e.g. ["someProp0", 42]
* ["someProp1", true]
* ["someProp2", "nasu"]
* ["someProp3", { type: "undefined" }]
* ["someProp4", { type: "null" }]
* ["someProp5", { type: "object", class: "Object" }]
* @param string aName
* Optional, the property name.
* @paarm string aId

View File

@ -34,7 +34,8 @@ function test_early_debugger_statement(aActor)
gClient.addListener("paused", paused);
// This should continue without nesting an event loop and calling
// the onPaused hook, because we haven't attached yet.
gTab.linkedBrowser.contentWindow.wrappedJSObject.runDebuggerStatement();
// TODO: uncomment this when bug 723563 is fixed.
//gTab.linkedBrowser.contentWindow.wrappedJSObject.runDebuggerStatement();
gClient.removeListener("paused", paused);

View File

@ -87,7 +87,7 @@ function test_attach_removed_tab()
});
gClient.request({ to: gTab2Actor, type: "attach" }, function(aResponse) {
is(aResponse.type, "exited", "Tab should consider itself exited.");
is(aResponse.error, "noSuchActor", "Tab should be gone.");
finish_test();
});
}

View File

@ -64,7 +64,7 @@ function TreePanel(aContext, aIUI) {
TreePanel.prototype = {
showTextNodesWithWhitespace: false,
id: "treepanel", // DO NOT LOCALIZE
openInDock: true,
_open: false,
/**
* The tree panel container element.
@ -75,11 +75,7 @@ TreePanel.prototype = {
*/
get container()
{
if (this.openInDock) {
return this.document.getElementById("inspector-tree-box");
}
return this.document.getElementById("inspector-tree-panel");
return this.document.getElementById("inspector-tree-box");
},
/**
@ -93,6 +89,8 @@ TreePanel.prototype = {
this.IUI = aIUI;
this.window = aContext;
this.document = this.window.document;
this.button =
this.IUI.chromeDoc.getElementById("inspector-treepanel-toolbutton");
domplateUtils.setDOM(this.window);
@ -100,28 +98,7 @@ TreePanel.prototype = {
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);
},
/**
@ -154,13 +131,14 @@ TreePanel.prototype = {
*/
open: function TP_open()
{
if (this.initializingTreePanel && !this.treeLoaded) {
if (this._open) {
return;
}
this._open = true;
this.button.setAttribute("checked", true);
this.initializingTreePanel = true;
if (!this.openInDock)
this.container.hidden = false;
this.treeIFrame = this.document.getElementById("inspector-tree-iframe");
if (!this.treeIFrame) {
@ -168,65 +146,13 @@ TreePanel.prototype = {
this.treeIFrame.setAttribute("id", "inspector-tree-iframe");
this.treeIFrame.flex = 1;
this.treeIFrame.setAttribute("type", "content");
this.treeIFrame.setAttribute("context", "inspector-node-popup");
}
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.state = "open";
try {
treeBox.height =
Services.prefs.getIntPref("devtools.inspector.htmlHeight");
@ -235,22 +161,26 @@ TreePanel.prototype = {
}
treeBox.minHeight = 64;
treeBox.flex = 1;
toolbarParent.insertBefore(treeBox, toolbar);
this.IUI.toolbar.setAttribute("treepanel-open", "true");
this.splitter = this.document.createElement("splitter");
this.splitter.id = "inspector-tree-splitter";
let container = this.document.getElementById("appcontent");
container.appendChild(this.splitter);
container.appendChild(treeBox);
treeBox.appendChild(this.treeIFrame);
let boundLoadedInitializeTreePanel = function loadedInitializeTreePanel()
this._boundLoadedInitializeTreePanel = function loadedInitializeTreePanel()
{
this.treeIFrame.removeEventListener("load",
boundLoadedInitializeTreePanel, true);
this._boundLoadedInitializeTreePanel, true);
delete this._boundLoadedInitializeTreePanel;
this.initializeIFrame();
}.bind(this);
this.treeIFrame.addEventListener("load",
boundLoadedInitializeTreePanel, true);
this._boundLoadedInitializeTreePanel, true);
let src = this.treeIFrame.getAttribute("src");
if (src != INSPECTOR_URI) {
@ -265,17 +195,22 @@ TreePanel.prototype = {
*/
close: function TP_close()
{
if (this.openInDock) {
this.IUI.toolbar.removeAttribute("treepanel-open");
this._open = false;
let treeBox = this.container;
Services.prefs.setIntPref("devtools.inspector.htmlHeight", treeBox.height);
let treeBoxParent = treeBox.parentNode;
treeBoxParent.removeChild(treeBox);
} else {
this.container.hidePopup();
// Stop caring about the tree iframe load if it's in progress.
if (this._boundLoadedInitializeTreePanel) {
this.treeIFrame.removeEventListener("load",
this._boundLoadedInitializeTreePanel, true);
delete this._boundLoadedInitializeTreePanel;
}
this.button.removeAttribute("checked");
let treeBox = this.container;
Services.prefs.setIntPref("devtools.inspector.htmlHeight", treeBox.height);
let treeBoxParent = treeBox.parentNode;
treeBoxParent.removeChild(this.splitter);
treeBoxParent.removeChild(treeBox);
if (this.treePanelDiv) {
this.treePanelDiv.ownerPanel = null;
let parent = this.treePanelDiv.parentNode;
@ -293,10 +228,15 @@ TreePanel.prototype = {
*/
isOpen: function TP_isOpen()
{
if (this.openInDock)
return this.treeLoaded && this.container;
return this._open;
},
return this.treeLoaded && this.container.state == "open";
/**
* Toggle the TreePanel.
*/
toggle: function TP_toggle()
{
this.isOpen() ? this.close() : this.open();
},
/**
@ -669,6 +609,20 @@ TreePanel.prototype = {
return null;
},
/**
* Remove a node box from the tree view.
* @param aElement
* The DOM node to remove from the HTML IOBox.
*/
deleteChildBox: function TP_deleteChildBox(aElement)
{
let childBox = this.ioBox.findObjectBox(aElement);
if (!childBox) {
return;
}
childBox.parentNode.removeChild(childBox);
},
/**
* Destructor function. Cleanup.
*/
@ -705,11 +659,6 @@ TreePanel.prototype = {
this.ioBox.destroy();
delete this.ioBox;
}
if (!this.openInDock) {
this.container.removeEventListener("popuphiding", this._boundClose, false);
delete this._boundClose;
}
}
};

View File

@ -43,7 +43,11 @@
* ***** END LICENSE BLOCK ***** */
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var EXPORTED_SYMBOLS = ["Highlighter"];
@ -59,6 +63,9 @@ const INSPECTOR_INVISIBLE_ELEMENTS = {
"title": true,
};
const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
// add ":visited" and ":link" after bug 713106 is fixed
/**
* A highlighter mechanism.
*
@ -109,6 +116,8 @@ const INSPECTOR_INVISIBLE_ELEMENTS = {
* "highlighting" - Highlighter is highlighting
* "locked" - The selected node has been locked
* "unlocked" - The selected ndoe has been unlocked
* "pseudoclasstoggled" - A pseudo-class lock has changed on the selected node
*
* Structure:
*
@ -238,6 +247,17 @@ Highlighter.prototype = {
}
},
/**
* Notify that a pseudo-class lock was toggled on the highlighted element
*
* @param aPseudo - The pseudo-class to toggle, e.g. ":hover".
*/
pseudoClassLockToggled: function Highlighter_pseudoClassLockToggled(aPseudo)
{
this.emitEvent("pseudoclasstoggled", [aPseudo]);
this.updateInfobar();
},
/**
* Update the highlighter size and position.
*/
@ -446,29 +466,80 @@ Highlighter.prototype = {
let classesBox = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
classesBox.id = "highlighter-nodeinfobar-classes";
let pseudoClassesBox = this.chromeDoc.createElementNS("http://www.w3.org/1999/xhtml", "span");
pseudoClassesBox.id = "highlighter-nodeinfobar-pseudo-classes";
// Add some content to force a better boundingClientRect down below.
classesBox.textContent = "&nbsp;";
pseudoClassesBox.textContent = "&nbsp;";
nodeInfobar.appendChild(tagNameLabel);
nodeInfobar.appendChild(idLabel);
nodeInfobar.appendChild(classesBox);
nodeInfobar.appendChild(pseudoClassesBox);
container.appendChild(arrowBoxTop);
container.appendChild(nodeInfobar);
container.appendChild(arrowBoxBottom);
aParent.appendChild(container);
nodeInfobar.onclick = (function _onInfobarRightClick(aEvent) {
if (aEvent.button == 2) {
this.openPseudoClassMenu();
}
}).bind(this);
let barHeight = container.getBoundingClientRect().height;
this.nodeInfo = {
tagNameLabel: tagNameLabel,
idLabel: idLabel,
classesBox: classesBox,
pseudoClassesBox: pseudoClassesBox,
container: container,
barHeight: barHeight,
};
},
/**
* Open the infobar's pseudo-class context menu.
*/
openPseudoClassMenu: function Highlighter_openPseudoClassMenu()
{
let menu = this.chromeDoc.createElement("menupopup");
menu.id = "infobar-context-menu";
let popupSet = this.chromeDoc.getElementById("mainPopupSet");
popupSet.appendChild(menu);
let fragment = this.buildPseudoClassMenu();
menu.appendChild(fragment);
menu.openPopup(this.nodeInfo.pseudoClassesBox, "end_before", 0, 0, true, false);
},
/**
* Create the menuitems for toggling the selection's pseudo-class state
*
* @returns DocumentFragment. The menuitems for toggling pseudo-classes.
*/
buildPseudoClassMenu: function IUI_buildPseudoClassesMenu()
{
let fragment = this.chromeDoc.createDocumentFragment();
for (let i = 0; i < PSEUDO_CLASSES.length; i++) {
let pseudo = PSEUDO_CLASSES[i];
let item = this.chromeDoc.createElement("menuitem");
item.setAttribute("type", "checkbox");
item.setAttribute("label", pseudo);
item.addEventListener("command",
this.pseudoClassLockToggled.bind(this, pseudo), false);
item.setAttribute("checked", DOMUtils.hasPseudoClassLock(this.node,
pseudo));
fragment.appendChild(item);
}
return fragment;
},
/**
* Highlight a rectangular region.
*
@ -543,6 +614,14 @@ Highlighter.prototype = {
classes.textContent = this.node.classList.length ?
"." + Array.join(this.node.classList, ".") : "";
// Pseudo-classes
let pseudos = PSEUDO_CLASSES.filter(function(pseudo) {
return DOMUtils.hasPseudoClassLock(this.node, pseudo);
}, this);
let pseudoBox = this.nodeInfo.pseudoClassesBox;
pseudoBox.textContent = pseudos.join("");
},
/**
@ -617,8 +696,8 @@ Highlighter.prototype = {
*/
computeZoomFactor: function Highlighter_computeZoomFactor() {
this.zoom =
this.win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils)
this.win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils)
.screenPixelsPerCSSPixel;
},
@ -805,3 +884,6 @@ Highlighter.prototype = {
///////////////////////////////////////////////////////////////////////////
XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils)
});

View File

@ -42,6 +42,7 @@
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Cu = Components.utils;
const Ci = Components.interfaces;
const Cr = Components.results;
@ -82,6 +83,8 @@ const INSPECTOR_NOTIFICATIONS = {
EDITOR_SAVED: "inspector-editor-saved",
};
const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
///////////////////////////////////////////////////////////////////////////
//// InspectorUI
@ -108,7 +111,6 @@ InspectorUI.prototype = {
tools: null,
toolEvents: null,
inspecting: false,
treePanelEnabled: true,
ruleViewEnabled: true,
isDirty: false,
store: null,
@ -137,25 +139,44 @@ InspectorUI.prototype = {
this.sidebarSplitter.removeAttribute("hidden");
this.stylingButton.checked = true;
// Activate the first tool in the sidebar, only if none previously-
// selected. We'll want to do a followup to remember selected tool-states.
// If no tool is already selected, show the last-used sidebar if available,
// otherwise just show the first.
if (!Array.some(this.sidebarToolbar.children,
function(btn) btn.hasAttribute("checked"))) {
let firstButtonId = this.getToolbarButtonId(this.sidebarTools[0].id);
this.chromeDoc.getElementById(firstButtonId).click();
let activePanel = this.sidebarTools[0];
let activeId = this.store.getValue(this.winID, "activeSidebar");
if (activeId && this.tools[activeId]) {
activePanel = this.tools[activeId];
}
this.activateSidebarPanel(activePanel.id);
}
this.store.setValue(this.winID, "sidebarOpen", true);
Services.prefs.setBoolPref("devtools.inspector.sidebarOpen", true);
},
/**
* Hide the Sidebar.
* Tear down the sidebar.
*/
hideSidebar: function IUI_hideSidebar()
_destroySidebar: function IUI_destroySidebar()
{
this.sidebarBox.setAttribute("hidden", "true");
this.sidebarSplitter.setAttribute("hidden", "true");
this.stylingButton.checked = false;
},
/**
* Hide the sidebar.
*/
hideSidebar: function IUI_hideSidebar()
{
this._destroySidebar();
this.store.setValue(this.winID, "sidebarOpen", false);
Services.prefs.setBoolPref("devtools.inspector.sidebarOpen", false);
},
/**
* Show or hide the sidebar. Called from the Styling button on the
* highlighter toolbar.
@ -169,6 +190,25 @@ InspectorUI.prototype = {
}
},
/**
* Activate a sidebar panel by id.
*/
activateSidebarPanel: function IUI_activateSidebarPanel(aID)
{
let buttonId = this.getToolbarButtonId(aID);
this.chromeDoc.getElementById(buttonId).click();
},
get activeSidebarPanel()
{
for each (let tool in this.sidebarTools) {
if (this.sidebarDeck.selectedPanel == this.getToolIframe(tool)) {
return tool.id;
}
}
return null;
},
/**
* Getter to test if the Sidebar is open or not.
*/
@ -192,6 +232,22 @@ InspectorUI.prototype = {
}
},
/**
* Toggle the TreePanel.
*/
toggleHTMLPanel: function TP_toggle()
{
if (this.treePanel.isOpen()) {
this.treePanel.close();
Services.prefs.setBoolPref("devtools.inspector.htmlPanelOpen", false);
this.store.setValue(this.winID, "htmlPanelOpen", false);
} else {
this.treePanel.open();
Services.prefs.setBoolPref("devtools.inspector.htmlPanelOpen", true);
this.store.setValue(this.winID, "htmlPanelOpen", true);
}
},
/**
* Is the inspector UI open? Simply check if the toolbar is visible or not.
*
@ -260,9 +316,7 @@ InspectorUI.prototype = {
this.initTools();
this.chromeWin.Tilt.setup();
if (this.treePanelEnabled) {
this.treePanel = new TreePanel(this.chromeWin, this);
}
this.treePanel = new TreePanel(this.chromeWin, this);
if (Services.prefs.getBoolPref("devtools.ruleview.enabled") &&
!this.toolRegistered("ruleview")) {
@ -310,6 +364,7 @@ InspectorUI.prototype = {
show: this.openRuleView,
hide: this.closeRuleView,
onSelect: this.selectInRuleView,
onChanged: this.changeInRuleView,
panel: null,
unregister: this.destroyRuleView,
sidebar: true,
@ -349,6 +404,16 @@ InspectorUI.prototype = {
this.store.setValue(this.winID, "selectedNode", null);
this.store.setValue(this.winID, "inspecting", true);
this.store.setValue(this.winID, "isDirty", this.isDirty);
this.store.setValue(this.winID, "htmlPanelOpen",
Services.prefs.getBoolPref("devtools.inspector.htmlPanelOpen"));
this.store.setValue(this.winID, "sidebarOpen",
Services.prefs.getBoolPref("devtools.inspector.sidebarOpen"));
this.store.setValue(this.winID, "activeSidebar",
Services.prefs.getCharPref("devtools.inspector.activeSidebar"));
this.win.addEventListener("pagehide", this, true);
}
},
@ -400,6 +465,8 @@ InspectorUI.prototype = {
if (this.treePanel && this.treePanel.editingContext)
this.treePanel.closeEditor();
this.treePanel.destroy();
if (this.closing || !this.win || !this.browser) {
return;
}
@ -417,6 +484,7 @@ InspectorUI.prototype = {
if (!aKeepStore) {
this.store.deleteStore(this.winID);
this.win.removeEventListener("pagehide", this, true);
this.clearPseudoClassLocks();
} else {
// Update the store before closing.
if (this.selection) {
@ -435,13 +503,12 @@ InspectorUI.prototype = {
this.stopInspecting();
this.saveToolState(this.winID);
this.toolsDo(function IUI_toolsHide(aTool) {
this.unregisterTool(aTool);
}.bind(this));
// close the sidebar
this.hideSidebar();
this._destroySidebar();
if (this.highlighter) {
this.highlighter.destroy();
@ -503,7 +570,7 @@ InspectorUI.prototype = {
this.inspecting = false;
this.toolsDim(false);
if (this.highlighter.getNode()) {
this.select(this.highlighter.getNode(), true, true, !aPreventScroll);
this.select(this.highlighter.getNode(), true, !aPreventScroll);
} else {
this.select(null, true, true);
}
@ -511,15 +578,17 @@ InspectorUI.prototype = {
},
/**
* Select an object in the tree view.
* Select an object in the inspector.
* @param aNode
* node to inspect
* @param forceUpdate
* force an update?
* @param aScroll boolean
* scroll the tree panel?
* @param aFrom [optional] string
* which part of the UI the selection occured from
*/
select: function IUI_select(aNode, forceUpdate, aScroll)
select: function IUI_select(aNode, forceUpdate, aScroll, aFrom)
{
// if currently editing an attribute value, using the
// highlighter dismisses the editor
@ -530,6 +599,10 @@ InspectorUI.prototype = {
aNode = this.defaultSelection;
if (forceUpdate || aNode != this.selection) {
if (aFrom != "breadcrumbs") {
this.clearPseudoClassLocks();
}
this.selection = aNode;
if (!this.inspecting) {
this.highlighter.highlight(this.selection);
@ -538,9 +611,45 @@ InspectorUI.prototype = {
this.breadcrumbs.update();
this.chromeWin.Tilt.update(aNode);
this.treePanel.select(aNode, aScroll);
this.toolsSelect(aScroll);
},
/**
* Toggle the pseudo-class lock on the currently inspected element. If the
* pseudo-class is :hover or :active, that pseudo-class will also be toggled
* on every ancestor of the element, mirroring real :hover and :active
* behavior.
*
* @param aPseudo the pseudo-class lock to toggle, e.g. ":hover"
*/
togglePseudoClassLock: function IUI_togglePseudoClassLock(aPseudo)
{
if (DOMUtils.hasPseudoClassLock(this.selection, aPseudo)) {
this.breadcrumbs.nodeHierarchy.forEach(function(crumb) {
DOMUtils.removePseudoClassLock(crumb.node, aPseudo);
});
} else {
let hierarchical = aPseudo == ":hover" || aPseudo == ":active";
let node = this.selection;
do {
DOMUtils.addPseudoClassLock(node, aPseudo);
node = node.parentNode;
} while (hierarchical && node.parentNode)
}
this.nodeChanged();
},
/**
* Clear all pseudo-class locks applied to elements in the node hierarchy
*/
clearPseudoClassLocks: function IUI_clearPseudoClassLocks()
{
this.breadcrumbs.nodeHierarchy.forEach(function(crumb) {
DOMUtils.clearPseudoClassLocks(crumb.node);
});
},
/**
* Called when the highlighted node is changed by a tool.
@ -552,6 +661,7 @@ InspectorUI.prototype = {
nodeChanged: function IUI_nodeChanged(aUpdater)
{
this.highlighter.invalidateSize();
this.breadcrumbs.updateSelectors();
this.toolsOnChanged(aUpdater);
},
@ -577,17 +687,32 @@ InspectorUI.prototype = {
self.select(self.highlighter.getNode(), false, false);
});
this.highlighter.addListener("pseudoclasstoggled", function(aPseudo) {
self.togglePseudoClassLock(aPseudo);
});
if (this.store.getValue(this.winID, "inspecting")) {
this.startInspecting();
this.highlighter.unlock();
} else {
this.highlighter.lock();
}
this.restoreToolState(this.winID);
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.STATE_RESTORED, null);
this.win.focus();
this.highlighter.highlight();
if (this.store.getValue(this.winID, "htmlPanelOpen")) {
this.treePanel.open();
}
if (this.store.getValue(this.winID, "sidebarOpen")) {
this.showSidebar();
}
Services.obs.notifyObservers({wrappedJSObject: this},
INSPECTOR_NOTIFICATIONS.OPENED, null);
this.highlighter.highlight();
},
/**
@ -714,6 +839,46 @@ InspectorUI.prototype = {
}
},
/**
* Copy the innerHTML of the selected Node to the clipboard. Called via the
* Inspector:CopyInner command.
*/
copyInnerHTML: function IUI_copyInnerHTML()
{
let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].
getService(Ci.nsIClipboardHelper);
clipboard.copyString(this.selection.innerHTML);
},
/**
* Copy the outerHTML of the selected Node to the clipboard. Called via the
* Inspector:CopyOuter command.
*/
copyOuterHTML: function IUI_copyOuterHTML()
{
let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].
getService(Ci.nsIClipboardHelper);
clipboard.copyString(this.selection.outerHTML);
},
/**
* Delete the selected node. Called via the Inspector:DeleteNode command.
*/
deleteNode: function IUI_deleteNode()
{
let selection = this.selection;
let parent = this.selection.parentNode;
// remove the node from the treepanel
this.treePanel.deleteChildBox(selection);
// remove the node from content
parent.removeChild(selection);
this.breadcrumbs.invalidateHierarchy();
// select the parent node in the highlighter, treepanel, breadcrumbs
this.inspectNode(parent);
},
/////////////////////////////////////////////////////////////////////////
//// CssRuleView methods
@ -796,6 +961,15 @@ InspectorUI.prototype = {
if (this.ruleView)
this.ruleView.highlight(aNode);
},
/**
* Update the rules for the current node in the Css Rule View.
*/
changeInRuleView: function IUI_selectInRuleView()
{
if (this.ruleView)
this.ruleView.nodeChanged();
},
ruleViewChanged: function IUI_ruleViewChanged()
{
@ -1087,6 +1261,8 @@ InspectorUI.prototype = {
let btn = this.chromeDoc.getElementById(this.getToolbarButtonId(aTool.id));
btn.setAttribute("checked", "true");
if (aTool.sidebar) {
Services.prefs.setCharPref("devtools.inspector.activeSidebar", aTool.id);
this.store.setValue(this.winID, "activeSidebar", aTool.id);
this.sidebarDeck.selectedPanel = this.getToolIframe(aTool);
this.sidebarTools.forEach(function(other) {
if (other != aTool)
@ -1180,57 +1356,6 @@ InspectorUI.prototype = {
delete this.tools[aRegObj.id];
},
/**
* Save a list of open tools to the inspector store.
*
* @param aWinID The ID of the window used to save the associated tools
*/
saveToolState: function IUI_saveToolState(aWinID)
{
let openTools = {};
this.toolsDo(function IUI_toolsSetId(aTool) {
if (aTool.isOpen) {
openTools[aTool.id] = true;
}
});
this.store.setValue(aWinID, "openTools", openTools);
},
/**
* Restore tools previously save using saveToolState().
*
* @param aWinID The ID of the window to which the associated tools are to be
* restored.
*/
restoreToolState: function IUI_restoreToolState(aWinID)
{
let openTools = this.store.getValue(aWinID, "openTools");
let activeSidebarTool;
if (openTools) {
this.toolsDo(function IUI_toolsOnShow(aTool) {
if (aTool.id in openTools) {
if (aTool.sidebar && !this.isSidebarOpen) {
this.showSidebar();
activeSidebarTool = aTool;
}
this.toolShow(aTool);
}
}.bind(this));
this.sidebarTools.forEach(function(tool) {
if (tool != activeSidebarTool)
this.chromeDoc.getElementById(
this.getToolbarButtonId(tool.id)).removeAttribute("checked");
}.bind(this));
}
if (this.store.getValue(this.winID, "inspecting")) {
this.highlighter.unlock();
} else {
this.highlighter.lock();
}
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.STATE_RESTORED, null);
},
/**
* For each tool in the tools collection select the current node that is
* selected in the highlighter
@ -1254,7 +1379,7 @@ InspectorUI.prototype = {
toolsDim: function IUI_toolsDim(aState)
{
this.toolsDo(function IUI_toolsDim(aTool) {
if (aTool.isOpen && "dim" in aTool) {
if ("dim" in aTool) {
aTool.dim.call(aTool.context, aState);
}
});
@ -1270,7 +1395,7 @@ InspectorUI.prototype = {
toolsOnChanged: function IUI_toolsChanged(aUpdater)
{
this.toolsDo(function IUI_toolsOnChanged(aTool) {
if (aTool.isOpen && ("onChanged" in aTool) && aTool != aUpdater) {
if (("onChanged" in aTool) && aTool != aUpdater) {
aTool.onChanged.call(aTool.context);
}
});
@ -1664,6 +1789,13 @@ HTMLBreadcrumbs.prototype = {
for (let i = 0; i < aNode.classList.length; i++) {
text += "." + aNode.classList[i];
}
for (let i = 0; i < PSEUDO_CLASSES.length; i++) {
let pseudo = PSEUDO_CLASSES[i];
if (DOMUtils.hasPseudoClassLock(aNode, pseudo)) {
text += pseudo;
}
}
return text;
},
@ -1689,6 +1821,9 @@ HTMLBreadcrumbs.prototype = {
let classesLabel = this.IUI.chromeDoc.createElement("label");
classesLabel.className = "inspector-breadcrumbs-classes plain";
let pseudosLabel = this.IUI.chromeDoc.createElement("label");
pseudosLabel.className = "inspector-breadcrumbs-pseudo-classes plain";
tagLabel.textContent = aNode.tagName.toLowerCase();
idLabel.textContent = aNode.id ? ("#" + aNode.id) : "";
@ -1699,9 +1834,15 @@ HTMLBreadcrumbs.prototype = {
}
classesLabel.textContent = classesText;
let pseudos = PSEUDO_CLASSES.filter(function(pseudo) {
return DOMUtils.hasPseudoClassLock(aNode, pseudo);
}, this);
pseudosLabel.textContent = pseudos.join("");
fragment.appendChild(tagLabel);
fragment.appendChild(idLabel);
fragment.appendChild(classesLabel);
fragment.appendChild(pseudosLabel);
return fragment;
},
@ -1741,7 +1882,7 @@ HTMLBreadcrumbs.prototype = {
item.onmouseup = (function(aNode) {
return function() {
inspector.select(aNode, true, true);
inspector.select(aNode, true, true, "breadcrumbs");
}
})(nodes[i]);
@ -1895,7 +2036,7 @@ HTMLBreadcrumbs.prototype = {
button.onBreadcrumbsClick = function onBreadcrumbsClick() {
inspector.stopInspecting();
inspector.select(aNode, true, true);
inspector.select(aNode, true, true, "breadcrumbs");
};
button.onclick = (function _onBreadcrumbsRightClick(aEvent) {
@ -2010,6 +2151,20 @@ HTMLBreadcrumbs.prototype = {
let element = this.nodeHierarchy[this.currentIndex].button;
scrollbox.ensureElementIsVisible(element);
},
updateSelectors: function BC_updateSelectors()
{
for (let i = this.nodeHierarchy.length - 1; i >= 0; i--) {
let crumb = this.nodeHierarchy[i];
let button = crumb.button;
while(button.hasChildNodes()) {
button.removeChild(button.firstChild);
}
button.appendChild(this.prettyPrintNodeAsXUL(crumb.node));
button.setAttribute("tooltiptext", this.prettyPrintNodeAsText(crumb.node));
}
},
/**
* Update the breadcrumbs display when a new node is selected.
@ -2051,6 +2206,8 @@ HTMLBreadcrumbs.prototype = {
// Make sure the selected node and its neighbours are visible.
this.scroll();
this.updateSelectors();
},
}
@ -2070,3 +2227,6 @@ XPCOMUtils.defineLazyGetter(this, "StyleInspector", function () {
return obj.StyleInspector;
});
XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
});

View File

@ -70,6 +70,9 @@ _BROWSER_FILES = \
browser_inspector_ruleviewstore.js \
browser_inspector_duplicate_ruleview.js \
browser_inspector_invalidate.js \
browser_inspector_sidebarstate.js \
browser_inspector_treePanel_menu.js \
browser_inspector_pseudoclass_lock.js \
head.js \
$(NULL)

View File

@ -34,7 +34,7 @@ function setupHTMLPanel()
{
Services.obs.removeObserver(setupHTMLPanel, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
Services.obs.addObserver(runEditorTests, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
InspectorUI.toolShow(InspectorUI.treePanel.registrationObject);
InspectorUI.toggleHTMLPanel();
}
function runEditorTests()

View File

@ -0,0 +1,154 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let DOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
let doc;
let div;
let pseudo = ":hover";
function test()
{
waitForExplicitFinish();
ignoreAllUncaughtExceptions();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html,pseudo-class lock tests";
}
function createDocument()
{
div = doc.createElement("div");
div.textContent = "test div";
let head = doc.getElementsByTagName('head')[0];
let style = doc.createElement('style');
let rules = doc.createTextNode('div { color: red; } div:hover { color: blue; }');
style.appendChild(rules);
head.appendChild(style);
doc.body.appendChild(div);
setupTests();
}
function setupTests()
{
Services.obs.addObserver(selectNode,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.openInspectorUI();
}
function selectNode()
{
Services.obs.removeObserver(selectNode,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
executeSoon(function() {
InspectorUI.highlighter.addListener("nodeselected", openRuleView);
InspectorUI.inspectNode(div);
});
}
function openRuleView()
{
Services.obs.addObserver(performTests,
InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, false);
InspectorUI.showSidebar();
InspectorUI.openRuleView();
}
function performTests()
{
Services.obs.removeObserver(performTests,
InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY);
InspectorUI.highlighter.removeListener("nodeselected", performTests);
// toggle the class
InspectorUI.highlighter.pseudoClassLockToggled(pseudo);
testAdded();
// toggle the lock off
InspectorUI.highlighter.pseudoClassLockToggled(pseudo);
testRemoved();
testRemovedFromUI();
// toggle it back on
InspectorUI.highlighter.pseudoClassLockToggled(pseudo);
// close the inspector
Services.obs.addObserver(testInspectorClosed,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
InspectorUI.closeInspectorUI();
}
function testAdded()
{
// lock is applied to it and ancestors
let node = div;
do {
is(DOMUtils.hasPseudoClassLock(node, pseudo), true,
"pseudo-class lock has been applied");
node = node.parentNode;
} while (node.parentNode)
// infobar selector contains pseudo-class
let pseudoClassesBox = document.getElementById("highlighter-nodeinfobar-pseudo-classes");
is(pseudoClassesBox.textContent, pseudo, "pseudo-class in infobar selector");
// ruleview contains pseudo-class rule
is(InspectorUI.ruleView.element.children.length, 3,
"rule view is showing 3 rules for pseudo-class locked div");
is(InspectorUI.ruleView.element.children[1]._ruleEditor.rule.selectorText,
"div:hover", "rule view is showing " + pseudo + " rule");
}
function testRemoved()
{
// lock removed from node and ancestors
let node = div;
do {
is(DOMUtils.hasPseudoClassLock(node, pseudo), false,
"pseudo-class lock has been removed");
node = node.parentNode;
} while (node.parentNode)
}
function testRemovedFromUI()
{
// infobar selector doesn't contain pseudo-class
let pseudoClassesBox = document.getElementById("highlighter-nodeinfobar-pseudo-classes");
is(pseudoClassesBox.textContent, "", "pseudo-class removed from infobar selector");
// ruleview no longer contains pseudo-class rule
is(InspectorUI.ruleView.element.children.length, 2,
"rule view is showing 2 rules after removing lock");
}
function testInspectorClosed()
{
Services.obs.removeObserver(testInspectorClosed,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
testRemoved();
finishUp();
}
function finishUp()
{
doc = div = null;
gBrowser.removeCurrentTab();
finish();
}

View File

@ -148,45 +148,6 @@ function startToolTests(evt)
ok(!tool2.isOpen, "Panel 2 is closed");
ok(tool3.isOpen, "Panel 3 is open");
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
waitForFocus(testSecondTab, content);
}, true);
content.location = "data:text/html,registertool new tab test for inspector";
}
function testSecondTab()
{
info("Opened second tab");
info("Checking panel states 5");
let tools = InspectorUI.tools;
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");
Services.obs.addObserver(testOriginalTab, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
gBrowser.removeCurrentTab();
}
function testOriginalTab()
{
Services.obs.removeObserver(testOriginalTab, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
info("Checking panel states 6");
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);
}

View File

@ -128,8 +128,8 @@ function ruleViewOpened2()
is(prop.name, "background-color", "First prop is the background color prop.");
ok(!prop.enabled, "First prop should be disabled.");
gBrowser.removeCurrentTab();
InspectorUI.closeInspectorUI();
gBrowser.removeCurrentTab();
finish();
}

View File

@ -0,0 +1,74 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let doc;
function createDocument()
{
doc.body.innerHTML = '<h1>Sidebar state test</h1>';
doc.title = "Sidebar State Test";
// Open the sidebar and wait for the default view (the rule view) to show.
Services.obs.addObserver(inspectorRuleViewOpened,
InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY, false);
InspectorUI.openInspectorUI();
InspectorUI.showSidebar();
}
function inspectorRuleViewOpened()
{
Services.obs.removeObserver(inspectorRuleViewOpened,
InspectorUI.INSPECTOR_NOTIFICATIONS.RULEVIEWREADY);
is(InspectorUI.activeSidebarPanel, "ruleview", "Rule View is selected by default");
// Select the computed view and turn off the inspector.
InspectorUI.activateSidebarPanel("styleinspector");
Services.obs.addObserver(inspectorClosed,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
InspectorUI.closeInspectorUI();
}
function inspectorClosed()
{
// Reopen the inspector, expect the computed view to be loaded.
Services.obs.removeObserver(inspectorClosed,
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
Services.obs.addObserver(computedViewPopulated,
"StyleInspector-populated", false);
InspectorUI.openInspectorUI();
}
function computedViewPopulated()
{
Services.obs.removeObserver(computedViewPopulated,
"StyleInspector-populated");
is(InspectorUI.activeSidebarPanel, "styleinspector", "Computed view is selected by default.");
finishTest();
}
function finishTest()
{
InspectorUI.closeInspectorUI();
gBrowser.removeCurrentTab();
finish();
}
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function() {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = "data:text/html,basic tests for inspector";
}

View File

@ -96,6 +96,7 @@ function inspectorTabOpen2()
executeSoon(function() {
Services.obs.addObserver(inspectorUIOpen2,
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
clearUserPrefs();
InspectorUI.openInspectorUI();
});
}
@ -136,7 +137,7 @@ function inspectorFocusTab1()
Services.obs.addObserver(inspectorOpenTreePanelTab1,
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
InspectorUI.treePanel.open();
InspectorUI.toggleHTMLPanel();
}
function inspectorOpenTreePanelTab1()
@ -153,7 +154,7 @@ function inspectorOpenTreePanelTab1()
executeSoon(function() {
InspectorUI.showSidebar();
InspectorUI.toolShow(InspectorUI.stylePanel.registrationObject);
InspectorUI.activateSidebarPanel("styleinspector");
});
}

View File

@ -0,0 +1,97 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
function test() {
waitForExplicitFinish();
let doc;
let node1;
let div;
function createDocument() {
div = doc.createElement("div");
let h1 = doc.createElement("h1");
let p1 = doc.createElement("p");
let p2 = doc.createElement("p");
doc.title = "Inspector Tree Menu Test";
h1.textContent = "Inspector Tree Menu Test";
p1.textContent = "This is some example text";
div.appendChild(h1);
div.appendChild(p1);
doc.body.appendChild(div);
node1 = p1;
setupTest();
}
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
doc = content.document;
waitForFocus(createDocument, content);
}, true);
content.location = content.location = "data:text/html,basic tests for inspector";;
function setupTest() {
Services.obs.addObserver(runTests, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
InspectorUI.toggleInspectorUI();
}
function runTests() {
Services.obs.removeObserver(runTests, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
Services.obs.addObserver(testCopyInnerMenu, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
InspectorUI.stopInspecting();
InspectorUI.inspectNode(node1, true);
InspectorUI.treePanel.open();
}
function testCopyInnerMenu() {
let copyInner = document.getElementById("inspectorHTMLCopyInner");
ok(copyInner, "the popup menu has a copy inner html menu item");
waitForClipboard("This is some example text",
function() { copyInner.doCommand(); },
testCopyOuterMenu, testCopyOuterMenu);
}
function testCopyOuterMenu() {
let copyOuter = document.getElementById("inspectorHTMLCopyOuter");
ok(copyOuter, "the popup menu has a copy outer html menu item");
waitForClipboard("<p>This is some example text</p>",
function() { copyOuter.doCommand(); },
testDeleteNode, testDeleteNode);
}
function testDeleteNode() {
let deleteNode = document.getElementById("inspectorHTMLDelete");
ok(deleteNode, "the popup menu has a delete menu item");
InspectorUI.highlighter.addListener("nodeselected", deleteTest);
let commandEvent = document.createEvent("XULCommandEvent");
commandEvent.initCommandEvent("command", true, true, window, 0, false, false,
false, false, null);
deleteNode.dispatchEvent(commandEvent);
}
function deleteTest() {
InspectorUI.highlighter.removeListener("nodeSelected", deleteTest);
Services.obs.addObserver(finishUp, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
is(InspectorUI.selection, div, "parent node selected");
let p = doc.querySelector("P");
is(p, null, "node deleted");
executeSoon(function() {
InspectorUI.closeInspectorUI();
});
}
function finishUp() {
Services.obs.removeObserver(finishUp, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
doc = node1 = div = null;
gBrowser.removeCurrentTab();
finish();
}
}

View File

@ -41,6 +41,16 @@ let tempScope = {};
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm", tempScope);
let LayoutHelpers = tempScope.LayoutHelpers;
// Clear preferences that may be set during the course of tests.
function clearUserPrefs()
{
Services.prefs.clearUserPref("devtools.inspector.htmlPanelOpen");
Services.prefs.clearUserPref("devtools.inspector.sidebarOpen");
Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
}
registerCleanupFunction(clearUserPrefs);
function isHighlighting()
{
let veil = InspectorUI.highlighter.veilTransparentBox;
@ -78,3 +88,4 @@ function midPoint(aPointA, aPointB)
pointC.y = (aPointB.y - aPointA.y) / 2 + aPointA.y;
return pointC;
}

View File

@ -441,7 +441,8 @@ var Scratchpad = {
},
/**
* Write out a value at the current insertion point as a block comment
* Write out a value at the next line from the current insertion point.
* The comment block will always be preceded by a newline character.
* @param object aValue
* The Object to write out as a string
*/
@ -452,7 +453,7 @@ var Scratchpad = {
selection.end : // after selected text
this.editor.getCharCount(); // after text end
let newComment = "/*\n" + aValue + "\n*/";
let newComment = "\n/*\n" + aValue + "\n*/";
this.setText(newComment, insertionPoint, insertionPoint);

View File

@ -21,7 +21,7 @@ function runTests()
var scratchpad = gScratchpadWindow.Scratchpad;
var message = "\"Hello World!\""
var openComment = "/*\n";
var openComment = "\n/*\n";
var closeComment = "\n*/";
var error = "throw new Error(\"Ouch!\")";
let messageArray = {};

View File

@ -30,25 +30,25 @@ function verifyFalsies(sp)
{
sp.setText("undefined");
sp.display();
is(sp.selectedText, "/*\nundefined\n*/", "'undefined' is displayed");
is(sp.selectedText, "\n/*\nundefined\n*/", "'undefined' is displayed");
sp.setText("false");
sp.display();
is(sp.selectedText, "/*\nfalse\n*/", "'false' is displayed");
is(sp.selectedText, "\n/*\nfalse\n*/", "'false' is displayed");
sp.setText("0");
sp.display();
is(sp.selectedText, "/*\n0\n*/", "'0' is displayed");
is(sp.selectedText, "\n/*\n0\n*/", "'0' is displayed");
sp.setText("null");
sp.display();
is(sp.selectedText, "/*\nnull\n*/", "'null' is displayed");
is(sp.selectedText, "\n/*\nnull\n*/", "'null' is displayed");
sp.setText("NaN");
sp.display();
is(sp.selectedText, "/*\nNaN\n*/", "'NaN' is displayed");
is(sp.selectedText, "\n/*\nNaN\n*/", "'NaN' is displayed");
sp.setText("''");
sp.display();
is(sp.selectedText, "/*\n\n*/", "empty string is displayed");
is(sp.selectedText, "\n/*\n\n*/", "empty string is displayed");
}

View File

@ -40,13 +40,13 @@ function runTests()
is(content.wrappedJSObject.foobarBug636725, 3,
"display() updated window.foobarBug636725");
is(sp.getText(), "++window.foobarBug636725/*\n3\n*/",
is(sp.getText(), "++window.foobarBug636725\n/*\n3\n*/",
"display() shows evaluation result in the textbox");
is(sp.selectedText, "/*\n3\n*/", "selectedText is correct");
is(sp.selectedText, "\n/*\n3\n*/", "selectedText is correct");
let selection = sp.getSelectionRange();
is(selection.start, 24, "selection.start is correct");
is(selection.end, 31, "selection.end is correct");
is(selection.end, 32, "selection.end is correct");
// Test selection run() and display().
@ -94,16 +94,16 @@ function runTests()
"display() worked for the selected range");
is(sp.getText(), "window.foobarBug636725" +
"/*\na\n*/" +
"\n/*\na\n*/" +
" = 'c';\n" +
"window.foobarBug636725 = 'b';",
"display() shows evaluation result in the textbox");
is(sp.selectedText, "/*\na\n*/", "selectedText is correct");
is(sp.selectedText, "\n/*\na\n*/", "selectedText is correct");
selection = sp.getSelectionRange();
is(selection.start, 22, "selection.start is correct");
is(selection.end, 29, "selection.end is correct");
is(selection.end, 30, "selection.end is correct");
sp.deselect();

View File

@ -116,7 +116,7 @@ function ElementStyle(aElement, aStore)
// how their .style attribute reflects them as computed values.
this.dummyElement = doc.createElementNS(this.element.namespaceURI,
this.element.tagName);
this._populate();
this.populate();
}
// We're exporting _ElementStyle for unit tests.
var _ElementStyle = ElementStyle;
@ -147,7 +147,7 @@ ElementStyle.prototype = {
* Refresh the list of rules to be displayed for the active element.
* Upon completion, this.rules[] will hold a list of Rule objects.
*/
_populate: function ElementStyle_populate()
populate: function ElementStyle_populate()
{
this.rules = [];
@ -713,15 +713,33 @@ CssRuleView.prototype = {
this._createEditors();
},
/**
* Update the rules for the currently highlighted element.
*/
nodeChanged: function CssRuleView_nodeChanged()
{
this._clearRules();
this._elementStyle.populate();
this._createEditors();
},
/**
* Clear the rules.
*/
_clearRules: function CssRuleView_clearRules()
{
while (this.element.hasChildNodes()) {
this.element.removeChild(this.element.lastChild);
}
},
/**
* Clear the rule view.
*/
clear: function CssRuleView_clear()
{
while (this.element.hasChildNodes()) {
this.element.removeChild(this.element.lastChild);
}
this._clearRules();
this._viewedElement = null;
this._elementStyle = null;
},

View File

@ -120,6 +120,11 @@ StyleInspector.prototype = {
this.cssHtmlTree.highlight(selectedNode);
this.iframe.removeEventListener("load", boundIframeOnLoad, true);
this.iframeReady = true;
// Now that we've loaded, select any node we were previously asked
// to show.
this.selectNode(this.selectedNode);
Services.obs.notifyObservers(null, "StyleInspector-opened", null);
}
}.bind(this);
@ -215,11 +220,16 @@ StyleInspector.prototype = {
*/
isOpen: function SI_isOpen()
{
return this.openDocked ? this.iframeReady && this.IUI.isSidebarOpen &&
return this.openDocked ? this.IUI.isSidebarOpen &&
(this.IUI.sidebarDeck.selectedPanel == this.iframe) :
this.panel && this.panel.state && this.panel.state == "open";
},
isLoaded: function SI_isLoaded()
{
return this.openDocked ? this.iframeReady : this.iframeReady && this.panelReady;
},
/**
* Select from Path (via CssHtmlTree_pathClick)
* @param aNode The node to inspect.
@ -242,7 +252,7 @@ StyleInspector.prototype = {
selectNode: function SI_selectNode(aNode)
{
this.selectedNode = aNode;
if (this.isOpen() && !this.dimmed) {
if (this.isLoaded() && !this.dimmed) {
this.cssLogic.highlight(aNode);
this.cssHtmlTree.highlight(aNode);
}
@ -253,7 +263,7 @@ StyleInspector.prototype = {
*/
updateNode: function SI_updateNode()
{
if (this.isOpen() && !this.dimmed) {
if (this.isLoaded() && !this.dimmed) {
this.cssLogic.highlight(this.selectedNode);
this.cssHtmlTree.refreshPanel();
}

View File

@ -127,7 +127,6 @@ Tilt.prototype = {
chromeWindow: this.chromeWindow,
contentWindow: this.chromeWindow.gBrowser.selectedBrowser.contentWindow,
parentNode: this.chromeWindow.gBrowser.selectedBrowser.parentNode,
requestAnimationFrame: this.chromeWindow.mozRequestAnimationFrame,
notifications: this.NOTIFICATIONS
});
@ -141,7 +140,7 @@ Tilt.prototype = {
},
/**
* Destroys a specific instance of the visualizer.
* Starts destroying a specific instance of the visualizer.
*
* @param {String} aId
* the identifier of the instance in the visualizers array
@ -150,43 +149,49 @@ Tilt.prototype = {
*/
destroy: function T_destroy(aId, aAnimateFlag)
{
// if the visualizer is already destroyed, don't do anything
if (!this.visualizers[aId]) {
// if the visualizer is destroyed or destroying, don't do anything
if (!this.visualizers[aId] || this._isDestroying) {
return;
}
this._isDestroying = true;
let controller = this.visualizers[aId].controller;
let presenter = this.visualizers[aId].presenter;
let content = presenter.contentWindow;
let pageXOffset = content.pageXOffset * presenter.transforms.zoom;
let pageYOffset = content.pageYOffset * presenter.transforms.zoom;
TiltUtils.setDocumentZoom(this.chromeWindow, presenter.transforms.zoom);
// if we're not doing any outro animation, just finish destruction directly
if (!aAnimateFlag) {
this._finish(aId);
return;
}
if (!this.isDestroying) {
this.isDestroying = true;
// otherwise, trigger the outro animation and notify necessary observers
Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.DESTROYING, null);
let finalize = function T_finalize(aId) {
this.visualizers[aId].removeOverlay();
this.visualizers[aId].cleanup();
this.visualizers[aId] = null;
controller.removeEventListeners();
controller.arcball.reset([-pageXOffset, -pageYOffset]);
presenter.executeDestruction(this._finish.bind(this, aId));
},
this.isDestroying = false;
this.chromeWindow.gBrowser.selectedBrowser.focus();
Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.DESTROYED, null);
};
/**
* Finishes detroying a specific instance of the visualizer.
*
* @param {String} aId
* the identifier of the instance in the visualizers array
*/
_finish: function T__finish(aId)
{
this.visualizers[aId].removeOverlay();
this.visualizers[aId].cleanup();
this.visualizers[aId] = null;
if (!aAnimateFlag) {
finalize.call(this, aId);
return;
}
let controller = this.visualizers[aId].controller;
let presenter = this.visualizers[aId].presenter;
let content = presenter.contentWindow;
let pageXOffset = content.pageXOffset * presenter.transforms.zoom;
let pageYOffset = content.pageYOffset * presenter.transforms.zoom;
Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.DESTROYING, null);
TiltUtils.setDocumentZoom(this.chromeWindow, presenter.transforms.zoom);
controller.removeEventListeners();
controller.arcball.reset([-pageXOffset, -pageYOffset]);
presenter.executeDestruction(finalize.bind(this, aId));
}
this._isDestroying = false;
this.chromeWindow.gBrowser.selectedBrowser.focus();
Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.DESTROYED, null);
},
/**
@ -286,16 +291,18 @@ Tilt.prototype = {
// FIXME: this shouldn't be done here, see bug #705131
let onOpened = function() {
if (this.currentInstance) {
this.chromeWindow.InspectorUI.stopInspecting();
this.inspectButton.disabled = true;
this.highlighterContainer.style.display = "none";
if (this.inspector && this.highlighter && this.currentInstance) {
this.inspector.stopInspecting();
this.inspector.inspectToolbutton.disabled = true;
this.highlighter.hide();
}
}.bind(this);
let onClosed = function() {
this.inspectButton.disabled = false;
this.highlighterContainer.style.display = "";
if (this.inspector && this.highlighter) {
this.inspector.inspectToolbutton.disabled = false;
this.highlighter.show();
}
}.bind(this);
Services.obs.addObserver(onOpened,
@ -337,32 +344,27 @@ Tilt.prototype = {
return this.visualizers[this.currentWindowId];
},
/**
* Gets the current InspectorUI instance.
*/
get inspector()
{
return this.chromeWindow.InspectorUI;
},
/**
* Gets the current Highlighter instance from the InspectorUI.
*/
get highlighter()
{
return this.inspector.highlighter;
},
/**
* Gets the Tilt button in the Inspector toolbar.
*/
get tiltButton()
{
return this.chromeWindow.document.getElementById(
"inspector-3D-button");
},
/**
* Gets the Inspect button in the Inspector toolbar.
* FIXME: this shouldn't be needed here, remove after bug #705131
*/
get inspectButton()
{
return this.chromeWindow.document.getElementById(
"inspector-inspect-toolbutton");
},
/**
* Gets the Highlighter contaniner stack.
* FIXME: this shouldn't be needed here, remove after bug #705131
*/
get highlighterContainer()
{
return this.chromeWindow.document.getElementById(
"highlighter-container");
return this.chromeWindow.document.getElementById("inspector-3D-button");
}
};

View File

@ -92,6 +92,8 @@ TiltGL.Renderer = function TGL_Renderer(aCanvas, onError, onLoad)
*/
this.width = aCanvas.width;
this.height = aCanvas.height;
this.initialWidth = this.width;
this.initialHeight = this.height;
/**
* The current model view matrix.
@ -864,21 +866,29 @@ TiltGL.Program.prototype = {
// use the the program if it wasn't already set
this._context.useProgram(this._ref);
this.cleanupVertexAttrib();
// check if the required vertex attributes aren't already set
if (utils._enabledAttributes < this._attributes.length) {
utils._enabledAttributes = this._attributes.length;
// enable any necessary vertex attributes using the cache
for (let i in this._attributes) {
if (this._attributes.hasOwnProperty(i)) {
this._context.enableVertexAttribArray(this._attributes[i]);
}
}
// enable any necessary vertex attributes using the cache
for each (let attribute in this._attributes) {
this._context.enableVertexAttribArray(attribute);
utils._enabledAttributes.push(attribute);
}
}
},
/**
* Disables all currently enabled vertex attribute arrays.
*/
cleanupVertexAttrib: function TGLP_cleanupVertexAttrib()
{
let utils = TiltGL.ProgramUtils;
for each (let attribute in utils._enabledAttributes) {
this._context.disableVertexAttribArray(attribute);
}
utils._enabledAttributes = [];
},
/**
* Binds a vertex buffer as an array buffer for a specific shader attribute.
*
@ -949,9 +959,9 @@ TiltGL.Program.prototype = {
{
let gl = this._context;
gl.uniform1i(this._uniforms[aSampler], 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, aTexture._ref);
gl.uniform1i(this._uniforms[aSampler], 0);
},
/**
@ -1177,7 +1187,7 @@ TiltGL.ProgramUtils = {
/**
* Represents the current enabled attributes.
*/
_enabledAttributes: -1
_enabledAttributes: []
};
/**
@ -1415,7 +1425,7 @@ TiltGL.TextureUtils = {
/**
* This shim renders a content window to a canvas element, but clamps the
* maximum width and height of the canvas to half the WebGL MAX_TEXTURE_SIZE.
* maximum width and height of the canvas to the WebGL MAX_TEXTURE_SIZE.
*
* @param {Window} aContentWindow
* the content window to get a texture from
@ -1615,5 +1625,5 @@ TiltGL.create3DContext = function TGL_create3DContext(aCanvas, aFlags)
TiltGL.clearCache = function TGL_clearCache()
{
TiltGL.ProgramUtils._activeProgram = -1;
TiltGL.ProgramUtils._enabledAttributes = -1;
TiltGL.ProgramUtils._enabledAttributes = [];
};

View File

@ -518,8 +518,8 @@ TiltUtils.destroyObject = function TU_destroyObject(aScope)
}
// objects in Tilt usually use a function to handle internal destruction
if ("function" === typeof aScope.finalize) {
aScope.finalize();
if ("function" === typeof aScope._finalize) {
aScope._finalize();
}
for (let i in aScope) {
if (aScope.hasOwnProperty(i)) {

File diff suppressed because it is too large Load Diff

View File

@ -38,9 +38,6 @@
***** END LICENSE BLOCK *****/
"use strict";
const SIXTEEN_OVER_255 = 16 / 255;
const ONE_OVER_255 = 1 / 255;
/**
* Given the initialization data (thickness, sizes and information about
* each DOM node) this worker sends back the arrays representing
@ -52,27 +49,44 @@ const ONE_OVER_255 = 1 / 255;
self.onmessage = function TWC_onMessage(event)
{
let data = event.data;
let maxGroupNodes = parseInt(data.maxGroupNodes);
let thickness = data.thickness;
let style = data.style;
let texWidth = data.texWidth;
let texHeight = data.texHeight;
let nodesInfo = data.nodesInfo;
// create the arrays used to construct the 3D mesh data
let vertices = [];
let texCoord = [];
let color = [];
let stacksIndices = [];
let wireframeIndices = [];
let meshWidth = 0;
let meshHeight = 0;
let mesh = {
allVertices: [],
groups: [],
width: 0,
height: 0
};
let vertices;
let texCoord;
let color;
let stacksIndices;
let wireframeIndices;
let index;
// seed the random function to get the same values each time
// we're doing this to avoid ugly z-fighting with overlapping nodes
self.random.seed(0);
// go through all the dom nodes and compute the verts, texcoord etc.
for (let n = 0, i = 0, len = nodesInfo.length; n < len; n++) {
for (let n = 0, len = nodesInfo.length; n < len; n++) {
// check if we need to start creating a new group
if (n % maxGroupNodes === 0) {
vertices = []; // recreate the arrays used to construct the 3D mesh data
texCoord = [];
color = [];
stacksIndices = [];
wireframeIndices = [];
index = 0;
}
let info = nodesInfo[n];
let depth = info.depth;
let coord = info.coord;
@ -155,6 +169,7 @@ self.onmessage = function TWC_onMessage(event)
g20, g21, g22,
g20, g21, g22);
let i = index; // number of vertex points, used to create the indices array
let ip1 = i + 1;
let ip2 = ip1 + 1;
let ip3 = ip2 + 1;
@ -182,23 +197,28 @@ self.onmessage = function TWC_onMessage(event)
ip11, ip3, ip10, ip2);
}
// number of vertex points, used for creating the indices array
i += 12; // a vertex has 3 coords: x, y and z
// there are 12 vertices in a stack representing a node
index += 12;
// set the maximum mesh width and height to calculate the center offset
meshWidth = Math.max(w, meshWidth);
meshHeight = Math.max(h, meshHeight);
mesh.width = Math.max(w, mesh.width);
mesh.height = Math.max(h, mesh.height);
// check if we need to save the currently active group; this happens after
// we filled all the "slots" in a group or there aren't any remaining nodes
if (((n + 1) % maxGroupNodes === 0) || (n === len - 1)) {
mesh.groups.push({
vertices: vertices,
texCoord: texCoord,
color: color,
stacksIndices: stacksIndices,
wireframeIndices: wireframeIndices
});
mesh.allVertices = mesh.allVertices.concat(vertices);
}
}
self.postMessage({
vertices: vertices,
texCoord: texCoord,
color: color,
stacksIndices: stacksIndices,
wireframeIndices: wireframeIndices,
meshWidth: meshWidth,
meshHeight: meshHeight
});
self.postMessage(mesh);
close();
};

View File

@ -80,6 +80,7 @@ _BROWSER_TEST_FILES = \
browser_tilt_picking_highlight01.js \
browser_tilt_picking_highlight02.js \
browser_tilt_picking_highlight03.js \
browser_tilt_picking_miv.js \
browser_tilt_utils01.js \
browser_tilt_utils02.js \
browser_tilt_utils03.js \

View File

@ -62,11 +62,23 @@ function performTest(canvas, arcball, callback) {
window.setTimeout(function() {
info("Synthesizing arcball reset key press.");
arcball.onResetStart = function() {
arcball._onResetStart = function() {
info("Starting arcball reset animation.");
};
arcball.onResetFinish = function() {
arcball._onResetStep = function() {
info("\nlastRot: " + quat4.str(arcball._lastRot) +
"\ndeltaRot: " + quat4.str(arcball._deltaRot) +
"\ncurrentRot: " + quat4.str(arcball._currentRot) +
"\nlastTrans: " + vec3.str(arcball._lastTrans) +
"\ndeltaTrans: " + vec3.str(arcball._deltaTrans) +
"\ncurrentTrans: " + vec3.str(arcball._currentTrans) +
"\nadditionalRot: " + vec3.str(arcball._additionalRot) +
"\nadditionalTrans: " + vec3.str(arcball._additionalTrans) +
"\nzoomAmount: " + arcball._zoomAmount);
};
arcball._onResetFinish = function() {
ok(isApproxVec(arcball._lastRot, [0, 0, 0, 1]),
"The arcball _lastRot field wasn't reset correctly.");
ok(isApproxVec(arcball._deltaRot, [0, 0, 0, 1]),
@ -89,8 +101,10 @@ function performTest(canvas, arcball, callback) {
ok(isApproxVec([arcball._zoomAmount], [0]),
"The arcball _zoomAmount field wasn't reset correctly.");
info("Finishing arcball reset test.");
callback();
executeSoon(function() {
info("Finishing arcball reset test.");
callback();
});
};
EventUtils.synthesizeKey("VK_R", { type: "keydown" });

View File

@ -60,11 +60,23 @@ function performTest(canvas, arcball, callback) {
window.setTimeout(function() {
info("Synthesizing arcball reset key press.");
arcball.onResetStart = function() {
arcball._onResetStart = function() {
info("Starting arcball reset animation.");
};
arcball.onResetFinish = function() {
arcball._onResetStep = function() {
info("\nlastRot: " + quat4.str(arcball._lastRot) +
"\ndeltaRot: " + quat4.str(arcball._deltaRot) +
"\ncurrentRot: " + quat4.str(arcball._currentRot) +
"\nlastTrans: " + vec3.str(arcball._lastTrans) +
"\ndeltaTrans: " + vec3.str(arcball._deltaTrans) +
"\ncurrentTrans: " + vec3.str(arcball._currentTrans) +
"\nadditionalRot: " + vec3.str(arcball._additionalRot) +
"\nadditionalTrans: " + vec3.str(arcball._additionalTrans) +
"\nzoomAmount: " + arcball._zoomAmount);
};
arcball._onResetFinish = function() {
ok(isApproxVec(arcball._lastRot, [0, 0, 0, 1]),
"The arcball _lastRot field wasn't reset correctly.");
ok(isApproxVec(arcball._deltaRot, [0, 0, 0, 1]),
@ -87,8 +99,10 @@ function performTest(canvas, arcball, callback) {
ok(isApproxVec([arcball._zoomAmount], [0]),
"The arcball _zoomAmount field wasn't reset correctly.");
info("Finishing arcball reset test.");
callback();
executeSoon(function() {
info("Finishing arcball reset test.");
callback();
});
};
EventUtils.synthesizeKey("VK_R", { type: "keydown" });

View File

@ -48,10 +48,10 @@ function test() {
let arcball3 = new TiltVisualizer.Arcball(window, 512, 512);
let sphereVec = vec3.create();
arcball3.pointToSphere(123, 456, 256, 512, 512, sphereVec);
arcball3._pointToSphere(123, 456, 256, 512, 512, sphereVec);
ok(isApproxVec(sphereVec, [-0.009765625, 0.390625, 0.9204980731010437]),
"The pointToSphere() function didn't map the coordinates correctly.");
"The _pointToSphere() function didn't map the coordinates correctly.");
let stack1 = [];
let expect1 = [

View File

@ -47,7 +47,7 @@ function test() {
EventUtils.synthesizeKey("VK_A", { type: "keydown" });
EventUtils.synthesizeKey("VK_LEFT", { type: "keydown" });
instance.controller.update();
instance.controller._update();
ok(!isEqualVec(tran(), prev_tran),
"After a translation key is pressed, the vector should change.");
@ -58,7 +58,7 @@ function test() {
cancellingEvent();
instance.controller.update();
instance.controller._update();
ok(!isEqualVec(tran(), prev_tran),
"Even if the canvas lost focus, the vector has some inertia.");
@ -70,7 +70,7 @@ function test() {
while (!isEqualVec(tran(), prev_tran) ||
!isEqualVec(rot(), prev_rot)) {
instance.controller.update();
instance.controller._update();
save();
}

View File

@ -21,15 +21,13 @@ function test() {
let presenter = instance.presenter;
let canvas = presenter.canvas;
presenter.onSetupMesh = function() {
presenter._onSetupMesh = function() {
presenter.pickNode(canvas.width / 2, 10, {
onpick: function(data)
{
ok(data.index > 0,
"Simply picking a node didn't work properly.");
ok(!presenter.highlight.disabled,
"After only picking a node, it shouldn't be highlighted.");
Services.obs.addObserver(cleanup, DESTROYED, false);
InspectorUI.closeInspectorUI();

View File

@ -23,13 +23,13 @@ function test() {
presenter = instance.presenter;
Services.obs.addObserver(whenNodeRemoved, NODE_REMOVED, false);
presenter.onSetupMesh = function() {
presenter._onSetupMesh = function() {
presenter.highlightNodeAt(presenter.canvas.width / 2, 10, {
onpick: function()
{
ok(presenter._currentSelection > 0,
"Highlighting a node didn't work properly.");
ok(!presenter.highlight.disabled,
ok(!presenter._highlight.disabled,
"After highlighting a node, it should be highlighted. D'oh.");
presenter.deleteNode();
@ -44,14 +44,14 @@ function test() {
function whenNodeRemoved() {
ok(presenter._currentSelection > 0,
"Deleting a node shouldn't change the current selection.");
ok(presenter.highlight.disabled,
ok(presenter._highlight.disabled,
"After deleting a node, it shouldn't be highlighted.");
let nodeIndex = presenter._currentSelection;
let meshData = presenter.meshData;
let vertices = presenter._meshStacks[0].vertices.components;
for (let i = 0, k = 36 * nodeIndex; i < 36; i++) {
is(meshData.vertices[i + k], 0,
is(vertices[i + k], 0,
"The stack vertices weren't degenerated properly.");
}

View File

@ -24,7 +24,7 @@ function test() {
presenter = instance.presenter;
Services.obs.addObserver(whenHighlighting, HIGHLIGHTING, false);
presenter.onInitializationFinished = function() {
presenter._onInitializationFinished = function() {
let contentDocument = presenter.contentWindow.document;
let div = contentDocument.getElementById("far-far-away");
@ -38,9 +38,9 @@ function test() {
function whenHighlighting() {
ok(presenter._currentSelection > 0,
"Highlighting a node didn't work properly.");
ok(!presenter.highlight.disabled,
ok(!presenter._highlight.disabled,
"After highlighting a node, it should be highlighted. D'oh.");
ok(presenter.controller.arcball._resetInterval,
ok(presenter.controller.arcball._resetInProgress,
"Highlighting a node that's not already visible should trigger a reset!");
executeSoon(function() {
@ -52,7 +52,7 @@ function whenHighlighting() {
function whenUnhighlighting() {
ok(presenter._currentSelection < 0,
"Unhighlighting a should remove the current selection.");
ok(presenter.highlight.disabled,
ok(presenter._highlight.disabled,
"After unhighlighting a node, it shouldn't be highlighted anymore. D'oh.");
executeSoon(function() {

View File

@ -23,7 +23,7 @@ function test() {
presenter = instance.presenter;
Services.obs.addObserver(whenHighlighting, HIGHLIGHTING, false);
presenter.onSetupMesh = function() {
presenter._onSetupMesh = function() {
let contentDocument = presenter.contentWindow.document;
let div = contentDocument.getElementById("first-law");
@ -37,9 +37,9 @@ function test() {
function whenHighlighting() {
ok(presenter._currentSelection > 0,
"Highlighting a node didn't work properly.");
ok(!presenter.highlight.disabled,
ok(!presenter._highlight.disabled,
"After highlighting a node, it should be highlighted. D'oh.");
ok(!presenter.controller.arcball._resetInterval,
ok(!presenter.controller.arcball._resetInProgress,
"Highlighting a node that's already visible shouldn't trigger a reset.");
executeSoon(function() {
@ -51,7 +51,7 @@ function whenHighlighting() {
function whenUnhighlighting() {
ok(presenter._currentSelection < 0,
"Unhighlighting a should remove the current selection.");
ok(presenter.highlight.disabled,
ok(presenter._highlight.disabled,
"After unhighlighting a node, it shouldn't be highlighted anymore. D'oh.");
executeSoon(function() {

View File

@ -23,7 +23,7 @@ function test() {
presenter = instance.presenter;
Services.obs.addObserver(whenHighlighting, HIGHLIGHTING, false);
presenter.onSetupMesh = function() {
presenter._onSetupMesh = function() {
presenter.highlightNodeAt(presenter.canvas.width / 2, 10);
};
}
@ -34,7 +34,7 @@ function test() {
function whenHighlighting() {
ok(presenter._currentSelection > 0,
"Highlighting a node didn't work properly.");
ok(!presenter.highlight.disabled,
ok(!presenter._highlight.disabled,
"After highlighting a node, it should be highlighted. D'oh.");
executeSoon(function() {
@ -46,7 +46,7 @@ function whenHighlighting() {
function whenUnhighlighting() {
ok(presenter._currentSelection < 0,
"Unhighlighting a should remove the current selection.");
ok(presenter.highlight.disabled,
ok(presenter._highlight.disabled,
"After unhighlighting a node, it shouldn't be highlighted anymore. D'oh.");
executeSoon(function() {

View File

@ -23,7 +23,7 @@ function test() {
presenter = instance.presenter;
Services.obs.addObserver(whenHighlighting, HIGHLIGHTING, false);
presenter.onSetupMesh = function() {
presenter._onSetupMesh = function() {
presenter.highlightNodeFor(5); // 1 = html, 2 = body, 3 = first div
};
}
@ -34,7 +34,7 @@ function test() {
function whenHighlighting() {
ok(presenter._currentSelection > 0,
"Highlighting a node didn't work properly.");
ok(!presenter.highlight.disabled,
ok(!presenter._highlight.disabled,
"After highlighting a node, it should be highlighted. D'oh.");
executeSoon(function() {
@ -46,7 +46,7 @@ function whenHighlighting() {
function whenUnhighlighting() {
ok(presenter._currentSelection < 0,
"Unhighlighting a should remove the current selection.");
ok(presenter.highlight.disabled,
ok(presenter._highlight.disabled,
"After unhighlighting a node, it shouldn't be highlighted anymore. D'oh.");
executeSoon(function() {

View File

@ -0,0 +1,71 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let presenter;
function test() {
if (!isTiltEnabled()) {
info("Skipping highlight test because Tilt isn't enabled.");
return;
}
if (!isWebGLSupported()) {
info("Skipping highlight test because WebGL isn't supported.");
return;
}
requestLongerTimeout(10);
waitForExplicitFinish();
createTab(function() {
createTilt({
onTiltOpen: function(instance)
{
presenter = instance.presenter;
Services.obs.addObserver(whenHighlighting, HIGHLIGHTING, false);
presenter._onInitializationFinished = function() {
let contentDocument = presenter.contentWindow.document;
let div = contentDocument.getElementById("far-far-away");
presenter.highlightNode(div);
};
}
});
});
}
function whenHighlighting() {
ok(presenter._currentSelection > 0,
"Highlighting a node didn't work properly.");
ok(!presenter._highlight.disabled,
"After highlighting a node, it should be highlighted. D'oh.");
ok(!presenter.controller.arcball._resetInProgress,
"Highlighting a node that's not already visible shouldn't trigger a reset " +
"without this being explicitly requested!");
EventUtils.sendKey("F");
executeSoon(whenBringingIntoView);
}
function whenBringingIntoView() {
ok(presenter._currentSelection > 0,
"The node should still be selected.");
ok(!presenter._highlight.disabled,
"The node should still be highlighted");
ok(presenter.controller.arcball._resetInProgress,
"Highlighting a node that's not already visible should trigger a reset " +
"when this is being explicitly requested!");
executeSoon(function() {
Services.obs.addObserver(cleanup, DESTROYED, false);
InspectorUI.closeInspectorUI();
});
}
function cleanup() {
Services.obs.removeObserver(whenHighlighting, HIGHLIGHTING);
Services.obs.removeObserver(cleanup, DESTROYED);
gBrowser.removeCurrentTab();
finish();
}

View File

@ -2,10 +2,6 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let tmp = {};
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm", tmp);
let LayoutHelpers = tmp.LayoutHelpers;
function init(callback) {
let iframe = gBrowser.ownerDocument.createElement("iframe");

View File

@ -11,7 +11,7 @@ let someObject = {
};
let anotherObject = {
finalize: function()
_finalize: function()
{
someObject.c = 3;
}

View File

@ -19,7 +19,6 @@ function test() {
chromeWindow: window,
contentWindow: gBrowser.selectedBrowser.contentWindow,
parentNode: gBrowser.selectedBrowser.parentNode,
requestAnimationFrame: window.mozRequestAnimationFrame,
inspectorUI: window.InspectorUI,
onError: function onWebGLError()
@ -71,33 +70,33 @@ function test() {
}
function testPresenter(presenter) {
ok(presenter.renderer,
ok(presenter._renderer,
"The presenter renderer wasn't initialized properly.");
ok(presenter.visualizationProgram,
ok(presenter._visualizationProgram,
"The presenter visualizationProgram wasn't initialized properly.");
ok(presenter.texture,
ok(presenter._texture,
"The presenter texture wasn't initialized properly.");
ok(!presenter.meshStacks,
ok(!presenter._meshStacks,
"The presenter meshStacks shouldn't be initialized yet.");
ok(!presenter.meshWireframe,
ok(!presenter._meshWireframe,
"The presenter meshWireframe shouldn't be initialized yet.");
ok(presenter.traverseData,
ok(presenter._traverseData,
"The presenter nodesInformation wasn't initialized properly.");
ok(presenter.highlight,
ok(presenter._highlight,
"The presenter highlight wasn't initialized properly.");
ok(presenter.highlight.disabled,
"The presenter highlight should be initially disabled");
ok(isApproxVec(presenter.highlight.v0, [0, 0, 0]),
ok(presenter._highlight.disabled,
"The presenter highlight should be initially disabled.");
ok(isApproxVec(presenter._highlight.v0, [0, 0, 0]),
"The presenter highlight first vertex should be initially zeroed.");
ok(isApproxVec(presenter.highlight.v1, [0, 0, 0]),
ok(isApproxVec(presenter._highlight.v1, [0, 0, 0]),
"The presenter highlight second vertex should be initially zeroed.");
ok(isApproxVec(presenter.highlight.v2, [0, 0, 0]),
ok(isApproxVec(presenter._highlight.v2, [0, 0, 0]),
"The presenter highlight third vertex should be initially zeroed.");
ok(isApproxVec(presenter.highlight.v3, [0, 0, 0]),
ok(isApproxVec(presenter._highlight.v3, [0, 0, 0]),
"The presenter highlight fourth vertex should be initially zeroed.");
ok(presenter.transforms,
"The presenter transforms wasn't initialized properly.");
ok(isApproxVec(presenter.transforms.zoom, 1),
is(presenter.transforms.zoom, 1,
"The presenter transforms zoom should be initially 1.");
ok(isApproxVec(presenter.transforms.offset, [0, 0, 0]),
"The presenter transforms offset should be initially zeroed.");
@ -113,7 +112,7 @@ function testPresenter(presenter) {
"The presenter transforms translation wasn't modified as it should");
ok(isApproxVec(presenter.transforms.rotation, [5, 6, 7, 8]),
"The presenter transforms rotation wasn't modified as it should");
ok(presenter.redraw,
ok(presenter._redraw,
"The new transforms should have issued a redraw request.");
}

View File

@ -35,7 +35,7 @@ function test() {
let initialWidth = contentWindow.innerWidth;
let initialHeight = contentWindow.innerHeight;
let renderer = instance.presenter.renderer;
let renderer = instance.presenter._renderer;
let arcball = instance.controller.arcball;
ok(isApprox(contentWindow.innerWidth * ZOOM, renderer.width, 1),

View File

@ -7,6 +7,7 @@ Components.utils.import("resource:///modules/devtools/TiltGL.jsm", tempScope);
Components.utils.import("resource:///modules/devtools/TiltMath.jsm", tempScope);
Components.utils.import("resource:///modules/devtools/TiltUtils.jsm", tempScope);
Components.utils.import("resource:///modules/devtools/TiltVisualizer.jsm", tempScope);
Components.utils.import("resource:///modules/devtools/LayoutHelpers.jsm", tempScope);
let TiltGL = tempScope.TiltGL;
let EPSILON = tempScope.EPSILON;
let TiltMath = tempScope.TiltMath;
@ -16,6 +17,7 @@ let mat4 = tempScope.mat4;
let quat4 = tempScope.quat4;
let TiltUtils = tempScope.TiltUtils;
let TiltVisualizer = tempScope.TiltVisualizer;
let LayoutHelpers = tempScope.LayoutHelpers;
const DEFAULT_HTML = "data:text/html," +

View File

@ -0,0 +1,224 @@
/* ***** 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 GCLI Commands.
*
* 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):
* Victor Porof <vporof@mozilla.com> (original author)
*
* 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 ***** */
let EXPORTED_SYMBOLS = [ "GcliCommands" ];
Components.utils.import("resource:///modules/gcli.jsm");
Components.utils.import("resource:///modules/HUDService.jsm");
/**
* 'tilt' command
*/
gcli.addCommand({
name: 'tilt',
description: gcli.lookup("tiltDesc"),
manual: gcli.lookup("tiltManual")
});
/**
* 'tilt open' command
*/
gcli.addCommand({
name: 'tilt open',
description: gcli.lookup("tiltOpenDesc"),
manual: gcli.lookup("tiltOpenManual"),
params: [
{
name: "node",
type: "node",
defaultValue: null,
description: gcli.lookup("inspectNodeDesc"),
manual: gcli.lookup("inspectNodeManual")
}
],
exec: function(args, context) {
let chromeWindow = context.environment.chromeDocument.defaultView;
let InspectorUI = chromeWindow.InspectorUI;
let Tilt = chromeWindow.Tilt;
if (Tilt.currentInstance) {
Tilt.update(args.node);
} else {
let hudId = chromeWindow.HUDConsoleUI.getOpenHUD();
let hud = HUDService.getHudReferenceById(hudId);
if (hud && !hud.consolePanel) {
HUDService.deactivateHUDForContext(chromeWindow.gBrowser.selectedTab);
}
InspectorUI.openInspectorUI(args.node);
Tilt.initialize();
}
}
});
/**
* 'tilt translate' command
*/
gcli.addCommand({
name: 'tilt translate',
description: gcli.lookup("tiltTranslateDesc"),
manual: gcli.lookup("tiltTranslateManual"),
params: [
{
name: "x",
type: "number",
defaultValue: 0,
description: gcli.lookup("tiltTranslateXDesc"),
manual: gcli.lookup("tiltTranslateXManual")
},
{
name: "y",
type: "number",
defaultValue: 0,
description: gcli.lookup("tiltTranslateYDesc"),
manual: gcli.lookup("tiltTranslateYManual")
}
],
exec: function(args, context) {
let chromeWindow = context.environment.chromeDocument.defaultView;
let Tilt = chromeWindow.Tilt;
if (Tilt.currentInstance) {
Tilt.currentInstance.controller.arcball.translate([args.x, args.y]);
}
}
});
/**
* 'tilt rotate' command
*/
gcli.addCommand({
name: 'tilt rotate',
description: gcli.lookup("tiltRotateDesc"),
manual: gcli.lookup("tiltRotateManual"),
params: [
{
name: "x",
type: { name: 'number', min: -360, max: 360, step: 10 },
defaultValue: 0,
description: gcli.lookup("tiltRotateXDesc"),
manual: gcli.lookup("tiltRotateXManual")
},
{
name: "y",
type: { name: 'number', min: -360, max: 360, step: 10 },
defaultValue: 0,
description: gcli.lookup("tiltRotateYDesc"),
manual: gcli.lookup("tiltRotateYManual")
},
{
name: "z",
type: { name: 'number', min: -360, max: 360, step: 10 },
defaultValue: 0,
description: gcli.lookup("tiltRotateZDesc"),
manual: gcli.lookup("tiltRotateZManual")
}
],
exec: function(args, context) {
let chromeWindow = context.environment.chromeDocument.defaultView;
let Tilt = chromeWindow.Tilt;
if (Tilt.currentInstance) {
Tilt.currentInstance.controller.arcball.rotate([args.x, args.y, args.z]);
}
}
});
/**
* 'tilt zoom' command
*/
gcli.addCommand({
name: 'tilt zoom',
description: gcli.lookup("tiltZoomDesc"),
manual: gcli.lookup("tiltZoomManual"),
params: [
{
name: "zoom",
type: { name: 'number' },
description: gcli.lookup("tiltZoomAmountDesc"),
manual: gcli.lookup("tiltZoomAmountManual")
}
],
exec: function(args, context) {
let chromeWindow = context.environment.chromeDocument.defaultView;
let Tilt = chromeWindow.Tilt;
if (Tilt.currentInstance) {
Tilt.currentInstance.controller.arcball.zoom(-args.zoom);
}
}
});
/**
* 'tilt reset' command
*/
gcli.addCommand({
name: 'tilt reset',
description: gcli.lookup("tiltResetDesc"),
manual: gcli.lookup("tiltResetManual"),
exec: function(args, context) {
let chromeWindow = context.environment.chromeDocument.defaultView;
let Tilt = chromeWindow.Tilt;
if (Tilt.currentInstance) {
Tilt.currentInstance.controller.arcball.reset();
}
}
});
/**
* 'tilt close' command
*/
gcli.addCommand({
name: 'tilt close',
description: gcli.lookup("tiltCloseDesc"),
manual: gcli.lookup("tiltCloseManual"),
exec: function(args, context) {
let chromeWindow = context.environment.chromeDocument.defaultView;
let Tilt = chromeWindow.Tilt;
Tilt.destroy(Tilt.currentWindowId);
}
});

View File

@ -164,6 +164,7 @@ function loadCommands() {
let commandExports = {};
Cu.import("resource:///modules/GcliCommands.jsm", commandExports);
Cu.import("resource:///modules/GcliTiltCommands.jsm", commandExports);
return commandExports;
}

View File

@ -50,6 +50,7 @@ EXTRA_JS_MODULES = \
AutocompletePopup.jsm \
gcli.jsm \
GcliCommands.jsm \
GcliTiltCommands.jsm \
$(NULL)
EXTRA_PP_JS_MODULES = \

View File

@ -1103,7 +1103,6 @@ exports.testIncompleteMultiMatch = function() {
test.is(Status.ERROR, status);
test.is(-1, assignC.paramIndex);
test.ok(assignC.getPredictions().length > 0);
test.ok(assignC.getPredictions().length < 20); // could break ...
verifyPredictionsContains('tsv', assignC.getPredictions());
verifyPredictionsContains('tsr', assignC.getPredictions());
test.is(null, requ.commandAssignment.getValue());

View File

@ -213,11 +213,19 @@ can reach it easily. -->
<!ENTITY scratchpad.keycode "VK_F4">
<!ENTITY scratchpad.keytext "F4">
<!ENTITY inspectPanelTitle.label "HTML">
<!ENTITY inspectButton.label "Inspect">
<!ENTITY inspectButton.accesskey "I">
<!ENTITY inspectCloseButton.tooltiptext "Close Inspector">
<!ENTITY inspectorHTMLCopyInner.label "Copy Inner HTML">
<!ENTITY inspectorHTMLCopyInner.accesskey "I">
<!ENTITY inspectorHTMLCopyOuter.label "Copy Outer HTML">
<!ENTITY inspectorHTMLCopyOuter.accesskey "O">
<!ENTITY inspectorHTMLDelete.label "Delete Node">
<!ENTITY inspectorHTMLDelete.accesskey "D">
<!-- LOCALIZATION NOTE (inspect3DViewButton.label): This button shows an
- alternate view for the Inspector, creating a 3D visualization of the
- webpage. -->
@ -599,3 +607,15 @@ just addresses the organization to follow, e.g. "This site is run by " -->
<!ENTITY addonBarCloseButton.tooltip "Close Add-on Bar">
<!ENTITY toggleAddonBarCmd.key "/">
<!-- LOCALIZATION NOTE (htmlPanel.label): This is a label for a button that
activates the Web Developer->Inspect UI's HTML Tree Panel. -->
<!ENTITY htmlPanel.label "HTML">
<!-- LOCALIZATION NOTE (htmlPanel.tooltiptext): The text that appears when a user
hovers over the HTML panel's toolbar button. -->
<!ENTITY htmlPanel.tooltiptext "HTML panel">
<!-- LOCALIZATION NOTE (htmlPanel.accesskey): The key bound to the HTML panel's
toolbar button -->
<!ENTITY htmlPanel.accesskey "H">

View File

@ -56,6 +56,136 @@ inspectNodeDesc=CSS selector
# on what it does.
inspectNodeManual=A CSS selector for use with Document.querySelector which identifies a single element
# LOCALIZATION NOTE (tiltDesc) A very short description of the 'tilt'
# command. See tiltManual for a fuller description of what it does. This
# string is designed to be shown in a menu alongside the command name, which
# is why it should be as short as possible.
tiltDesc=Visualize the webpage in 3D
# LOCALIZATION NOTE (tiltManual) A fuller description of the 'tilt'
# command, displayed when the user asks for help on what it does.
tiltManual=Investigate the relationship between various parts of a webpage and their ancestors in a 3D environment
# LOCALIZATION NOTE (tiltOpenDesc) A very short description of the 'tilt inspect'
# command. See tiltOpenManual for a fuller description of what it does. This
# string is designed to be shown in a menu alongside the command name, which
# is why it should be as short as possible.
tiltOpenDesc=Open the Inspector 3D view
# LOCALIZATION NOTE (tiltOpenManual) A fuller description of the 'tilt translate'
# command, displayed when the user asks for help on what it does.
tiltOpenManual=Initialize the 3D page inspector and optionally highlight a node using a CSS selector
# LOCALIZATION NOTE (tiltTranslateDesc) A very short description of the 'tilt translate'
# command. See tiltTranslateManual for a fuller description of what it does. This
# string is designed to be shown in a menu alongside the command name, which
# is why it should be as short as possible.
tiltTranslateDesc=Move the webpage mesh
# LOCALIZATION NOTE (tiltTranslateManual) A fuller description of the 'tilt translate'
# command, displayed when the user asks for help on what it does.
tiltTranslateManual=Incrementally translate the webpage mesh in a certain direction
# LOCALIZATION NOTE (tiltTranslateXDesc) A very short string to describe the
# 'x' parameter to the 'tilt translate' command, which is displayed in a dialog
# when the user is using this command.
tiltTranslateXDesc=X (pixels)
# LOCALIZATION NOTE (tiltTranslateXManual) A fuller description of the 'x'
# parameter to the 'translate' command, displayed when the user asks for help
# on what it does.
tiltTranslateXManual=The ammount in pixels to translate the webpage mesh on the X axis
# LOCALIZATION NOTE (tiltTranslateYDesc) A very short string to describe the
# 'y' parameter to the 'tilt translate' command, which is displayed in a dialog
# when the user is using this command.
tiltTranslateYDesc=Y (pixels)
# LOCALIZATION NOTE (tiltTranslateYManual) A fuller description of the 'y'
# parameter to the 'translate' command, displayed when the user asks for help
# on what it does.
tiltTranslateYManual=The ammount in pixels to translate the webpage mesh on the Y axis
# LOCALIZATION NOTE (tiltRotateDesc) A very short description of the 'tilt rotate'
# command. See tiltRotateManual for a fuller description of what it does. This
# string is designed to be shown in a menu alongside the command name, which
# is why it should be as short as possible.
tiltRotateDesc=Spin the webpage mesh
# LOCALIZATION NOTE (tiltRotateManual) A fuller description of the 'tilt rotate'
# command, displayed when the user asks for help on what it does.
tiltRotateManual=Incrementally rotate the webpage mesh in a certain direction
# LOCALIZATION NOTE (tiltRotateXDesc) A very short string to describe the
# 'x' parameter to the 'tilt rotate' command, which is displayed in a dialog
# when the user is using this command.
tiltRotateXDesc=X (degrees)
# LOCALIZATION NOTE (tiltRotateXManual) A fuller description of the 'x'
# parameter to the 'rotate' command, displayed when the user asks for help
# on what it does.
tiltRotateXManual=The ammount in degrees to rotate the webpage mesh along the X axis
# LOCALIZATION NOTE (tiltRotateYDesc) A very short string to describe the
# 'y' parameter to the 'tilt rotate' command, which is displayed in a dialog
# when the user is using this command.
tiltRotateYDesc=Y (degrees)
# LOCALIZATION NOTE (tiltRotateYManual) A fuller description of the 'y'
# parameter to the 'rotate' command, displayed when the user asks for help
# on what it does.
tiltRotateYManual=The ammount in degrees to rotate the webpage mesh along the Y axis
# LOCALIZATION NOTE (tiltRotateZDesc) A very short string to describe the
# 'z' parameter to the 'tilt rotate' command, which is displayed in a dialog
# when the user is using this command.
tiltRotateZDesc=Z (degrees)
# LOCALIZATION NOTE (tiltRotateZManual) A fuller description of the 'z'
# parameter to the 'rotate' command, displayed when the user asks for help
# on what it does.
tiltRotateZManual=The ammount in degrees to rotate the webpage mesh along the Z axis
# LOCALIZATION NOTE (tiltZoomDesc) A very short description of the 'tilt zoom'
# command. See tiltZoomManual for a fuller description of what it does. This
# string is designed to be shown in a menu alongside the command name, which
# is why it should be as short as possible.
tiltZoomDesc=Move away or towards the webpage mesh
# LOCALIZATION NOTE (tiltZoomManual) A fuller description of the 'tilt zoom'
# command, displayed when the user asks for help on what it does.
tiltZoomManual=Incrementally move the webpage mesh in a certain direction along the Z axis
# LOCALIZATION NOTE (tiltZoomAmountDesc) A very short string to describe the
# 'zoom' parameter to the 'tilt zoom' command, which is displayed in a dialog
# when the user is using this command.
tiltZoomAmountDesc=Zoom (pixels)
# LOCALIZATION NOTE (tiltZoomAmmuntManual) A fuller description of the 'zoom'
# parameter to the 'zoom' command, displayed when the user asks for help
# on what it does.
tiltZoomAmountManual=The amount in pixels to translate the webpage mesh along the Z axis
# LOCALIZATION NOTE (tiltResetDesc) A very short description of the 'tilt reset'
# command. See tiltResetManual for a fuller description of what it does. This
# string is designed to be shown in a menu alongside the command name, which
# is why it should be as short as possible.
tiltResetDesc=Reset the translation, rotation and zoom
# LOCALIZATION NOTE (tiltResetManual) A fuller description of the 'tilt reset'
# command, displayed when the user asks for help on what it does.
tiltResetManual=Resets any transformations applied to the webpage mesh modelview matrix
# LOCALIZATION NOTE (tiltCloseDesc) A very short description of the 'tilt close'
# command. See tiltCloseManual for a fuller description of what it does. This
# string is designed to be shown in a menu alongside the command name, which
# is why it should be as short as possible.
tiltCloseDesc=Close the visualization if open
# LOCALIZATION NOTE (tiltCloseManual) A fuller description of the 'tilt close'
# command, displayed when the user asks for help on what it does.
tiltCloseManual=Close the visualization and switch back to the Inspector default highlighter
# LOCALIZATION NOTE (breakDesc) A very short string used to describe the
# function of the break command.
breakDesc=Manage breakpoints

View File

@ -20,20 +20,8 @@ breadcrumbs.siblings=Siblings
# 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
# LOCALIZATION NOTE (ruleView.*): Button label, accesskey and tooltip text
# associated with the Highlighter's CSS Rule View in the Style Sidebar.
ruleView.label=Rules
ruleView.accesskey=R
ruleView.tooltiptext=View and Edit CSS
ruleView.tooltiptext=View and Edit CSS

View File

@ -1992,10 +1992,6 @@ panel[dimmed="true"] {
border-top: 1px solid hsla(210, 8%, 5%, .65);
}
#inspector-toolbar[treepanel-open] {
padding-top: 0;
}
#devtools-side-splitter {
-moz-appearance: none;
border: 0;
@ -2011,15 +2007,6 @@ panel[dimmed="true"] {
background-color: -moz-Field;
}
/* Highlighter - toolbar resizer */
#inspector-top-resizer {
-moz-appearance: none;
cursor: n-resize;
background: none;
height: 4px;
}
/* Highlighter - Node Infobar */
/* Highlighter - Node Infobar - text */
@ -2032,6 +2019,10 @@ html|*#highlighter-nodeinfobar-id {
color: hsl(90, 79%, 52%);
}
html|*#highlighter-nodeinfobar-pseudo-classes {
color: hsl(20, 100%, 70%);
}
/* Highlighter - Node Infobar - box & arrow */
#highlighter-nodeinfobar {
@ -2136,11 +2127,19 @@ html|*#highlighter-nodeinfobar-id {
color: hsl(205,100%,70%);
}
.inspector-breadcrumbs-button[checked] > .inspector-breadcrumbs-pseudo-classes {
color: hsl(20, 100%, 70%);
}
.inspector-breadcrumbs-id,
.inspector-breadcrumbs-classes {
color: #8d99a6;
}
.inspector-breadcrumbs-pseudo-classes {
color: hsl(20, 100%, 85%);
}
/* Highlighter toolbar - breadcrumbs - LTR */
.inspector-breadcrumbs-button:-moz-locale-dir(ltr):first-of-type {
@ -2260,3 +2259,15 @@ html|*#highlighter-nodeinfobar-id {
.inspector-breadcrumbs-button:last-of-type[checked]:hover:active:-moz-locale-dir(rtl) {
-moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected-pressed.png") 1 13 2 13 fill stretch;
}
/* Highlighter toolbar - HTML Tree */
#inspector-tree-splitter {
-moz-appearance: none;
border-top: 1px solid black;
border-bottom-width: 0;
min-height: 3px;
height: 3px;
margin-bottom: -3px;
position: relative;
}

View File

@ -247,6 +247,29 @@ a {
-moz-appearance: treetwistyopen;
}
/**
* Animations
*/
.details[open] {
-moz-animation-duration: 0.25s;
-moz-animation-name: showblock;
}
@-moz-keyframes showblock {
from {
opacity: 0;
-moz-transform-origin: top;
-moz-transform: scaleY(0);
}
to {
opacity: 1;
-moz-transform-origin: top;
-moz-transform: scaleY(1);
}
}
/**
* Display helpers
*/

View File

@ -59,7 +59,7 @@ body {
overflow: auto;
font-family: Lucida Grande, sans-serif;
font-size: 11px;
border-top: 1px solid #BBB9BA;
padding-top: 5px;
}
h1 {

View File

@ -2739,12 +2739,6 @@ panel[dimmed="true"] {
padding-right: 18px; /* use -moz-padding-end when/if bug 631729 gets fixed */
}
#inspector-toolbar[treepanel-open] {
padding-top: 0;
padding-right: 0;
-moz-padding-end: 4px;
}
#devtools-side-splitter {
background-image: none !important;
border: 0;
@ -2760,15 +2754,6 @@ panel[dimmed="true"] {
background-color: -moz-Field;
}
/* Highlighter - toolbar resizer */
#inspector-top-resizer {
-moz-appearance: none;
cursor: n-resize;
background: none;
height: 4px;
}
/* Highlighter - Node Infobar */
/* Highlighter - Node Infobar - text */
@ -2781,6 +2766,10 @@ html|*#highlighter-nodeinfobar-id {
color: hsl(90, 79%, 52%);
}
html|*#highlighter-nodeinfobar-pseudo-classes {
color: hsl(20, 100%, 70%);
}
/* Highlighter - Node Infobar - box & arrow */
#highlighter-nodeinfobar {
@ -2879,11 +2868,19 @@ html|*#highlighter-nodeinfobar-id {
color: hsl(205,100%,70%);
}
.inspector-breadcrumbs-button[checked] > .inspector-breadcrumbs-pseudo-classes {
color: hsl(20, 100%, 70%);
}
.inspector-breadcrumbs-id,
.inspector-breadcrumbs-classes {
color: #8d99a6;
}
.inspector-breadcrumbs-pseudo-classes {
color: hsl(20, 100%, 85%);
}
/* Highlighter toolbar - breadcrumbs - LTR */
.inspector-breadcrumbs-button:-moz-locale-dir(ltr):first-of-type {
@ -3003,3 +3000,15 @@ html|*#highlighter-nodeinfobar-id {
.inspector-breadcrumbs-button:last-of-type[checked]:hover:active:-moz-locale-dir(rtl) {
-moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected-pressed.png") 1 13 2 13 fill stretch;
}
/* Highlighter toolbar - HTML Tree */
#inspector-tree-splitter {
-moz-appearance: none;
border-top: 1px solid black;
border-bottom-width: 0;
min-height: 3px;
height: 3px;
margin-bottom: -3px;
position: relative;
}

View File

@ -245,6 +245,29 @@ a {
-moz-appearance: treetwistyopen;
}
/**
* Animations
*/
.details[open] {
-moz-animation-duration: 0.25s;
-moz-animation-name: showblock;
}
@-moz-keyframes showblock {
from {
opacity: 0;
-moz-transform-origin: top;
-moz-transform: scaleY(0);
}
to {
opacity: 1;
-moz-transform-origin: top;
-moz-transform: scaleY(1);
}
}
/**
* Display helpers
*/

View File

@ -59,7 +59,7 @@ body {
overflow: auto;
font-family: Lucida Grande, sans-serif;
font-size: 11px;
border-top: 1px solid #BBB9BA;
padding-top: 5px;
}
h1 {

View File

@ -2687,10 +2687,6 @@ panel[dimmed="true"] {
border-top: 1px solid hsla(211,68%,6%,.65) !important;
}
#inspector-toolbar[treepanel-open] {
padding-top: 0;
}
#devtools-side-splitter {
border: 0;
-moz-border-start: 1px solid #242b33;
@ -2705,15 +2701,6 @@ panel[dimmed="true"] {
background-color: -moz-Field;
}
/* Highlighter - toolbar resizer */
#inspector-top-resizer {
-moz-appearance: none;
cursor: n-resize;
background: none;
height: 4px;
}
/* Highlighter - Node Infobar */
/* Highlighter - Node Infobar - text */
@ -2726,6 +2713,10 @@ html|*#highlighter-nodeinfobar-id {
color: hsl(90, 79%, 52%);
}
html|*#highlighter-nodeinfobar-pseudo-classes {
color: hsl(20, 100%, 70%);
}
/* Highlighter - Node Infobar - box & arrow */
#highlighter-nodeinfobar {
@ -2830,11 +2821,19 @@ html|*#highlighter-nodeinfobar-id {
color: hsl(200,100%,70%);
}
.inspector-breadcrumbs-button[checked] > .inspector-breadcrumbs-pseudo-classes {
color: hsl(20, 100%, 70%);
}
.inspector-breadcrumbs-id,
.inspector-breadcrumbs-classes {
color: #8d99a6;
}
.inspector-breadcrumbs-pseudo-classes {
color: hsl(20, 100%, 85%);
}
/* Highlighter toolbar - breadcrumbs - LTR */
.inspector-breadcrumbs-button:-moz-locale-dir(ltr):first-of-type {
@ -2954,3 +2953,15 @@ html|*#highlighter-nodeinfobar-id {
.inspector-breadcrumbs-button:last-of-type[checked]:hover:active:-moz-locale-dir(rtl) {
-moz-border-image: url("chrome://browser/skin/devtools/breadcrumbs/rtl-end-selected-pressed.png") 2 13 2 13 fill stretch;
}
/* Highlighter toolbar - HTML Tree */
#inspector-tree-splitter {
-moz-appearance: none;
border-top: 1px solid black;
border-bottom-width: 0;
min-height: 3px;
height: 3px;
margin-bottom: -3px;
position: relative;
}

View File

@ -249,6 +249,29 @@ a {
background-image: url("chrome://global/skin/tree/twisty-open.png");
}
/**
* Animations
*/
.details[open] {
-moz-animation-duration: 0.25s;
-moz-animation-name: showblock;
}
@-moz-keyframes showblock {
from {
opacity: 0;
-moz-transform-origin: top;
-moz-transform: scaleY(0);
}
to {
opacity: 1;
-moz-transform-origin: top;
-moz-transform: scaleY(1);
}
}
/**
* Display helpers
*/

View File

@ -59,6 +59,7 @@ body {
overflow: auto;
font-family: Lucida Grande, sans-serif;
font-size: 11px;
padding-top: 5px;
}
h1 {

View File

@ -754,7 +754,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
self.log.info("Can't trigger Breakpad, just killing process")
proc.kill()
def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath):
def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath, logger):
""" Look for timeout or crashes and return the status after the process terminates """
stackFixerProcess = None
stackFixerFunction = None
@ -788,6 +788,8 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
(line, didTimeout) = self.readWithTimeout(logsource, timeout)
while line != "" and not didTimeout:
if logger:
logger.log(line)
if "TEST-START" in line and "|" in line:
self.lastTestSeen = line.split("|")[1].strip()
if stackFixerFunction:
@ -877,7 +879,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
def runApp(self, testURL, env, app, profileDir, extraArgs,
runSSLTunnel = False, utilityPath = None,
xrePath = None, certPath = None,
xrePath = None, certPath = None, logger = None,
debuggerInfo = None, symbolsPath = None,
timeout = -1, maxTime = None):
"""
@ -936,7 +938,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
stderr = subprocess.STDOUT)
self.log.info("INFO | automation.py | Application pid: %d", proc.pid)
status = self.waitForFinish(proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath)
status = self.waitForFinish(proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath, logger)
self.log.info("INFO | automation.py | Application ran for: %s", str(datetime.now() - startTime))
# Do a final check for zombie child processes.

View File

@ -40,6 +40,7 @@ from __future__ import with_statement
import glob, logging, os, platform, shutil, subprocess, sys, tempfile, urllib2, zipfile
import re
from urlparse import urlparse
from operator import itemgetter
__all__ = [
"ZipFileReader",
@ -52,6 +53,7 @@ __all__ = [
"DEBUGGER_INFO",
"replaceBackSlashes",
"wrapCommand",
"ShutdownLeakLogger"
]
# Map of debugging programs to information about them, like default arguments
@ -450,3 +452,106 @@ def wrapCommand(cmd):
return ["arch", "-arch", "i386"] + cmd
# otherwise just execute the command normally
return cmd
class ShutdownLeakLogger(object):
"""
Parses the mochitest run log when running a debug build, assigns all leaked
DOM windows (that are still around after test suite shutdown, despite running
the GC) to the tests that created them and prints leak statistics.
"""
MAX_LEAK_COUNT = 120
def __init__(self, logger):
self.logger = logger
self.tests = []
self.leakedWindows = {}
self.leakedDocShells = set()
self.currentTest = None
self.seenShutdown = False
def log(self, line):
if line[2:11] == "DOMWINDOW":
self._logWindow(line)
elif line[2:10] == "DOCSHELL":
self._logDocShell(line)
elif line.startswith("TEST-START"):
fileName = line.split(" ")[-1].strip().replace("chrome://mochitests/content/browser/", "")
self.currentTest = {"fileName": fileName, "windows": set(), "docShells": set()}
elif line.startswith("INFO TEST-END"):
# don't track a test if no windows or docShells leaked
if self.currentTest["windows"] and self.currentTest["docShells"]:
self.tests.append(self.currentTest)
self.currentTest = None
elif line.startswith("INFO TEST-START | Shutdown"):
self.seenShutdown = True
def parse(self):
leakingTests = self._parseLeakingTests()
if leakingTests:
totalWindows = sum(len(test["leakedWindows"]) for test in leakingTests)
totalDocShells = sum(len(test["leakedDocShells"]) for test in leakingTests)
msgType = "INFO" if totalWindows + totalDocShells < self.MAX_LEAK_COUNT else "UNEXPECTED-FAIL"
self.logger.info("TEST-%s | ShutdownLeaks | leaked %d DOMWindow(s) and %d DocShell(s) until shutdown", msgType, totalWindows, totalDocShells)
for test in leakingTests:
self.logger.info("\n[%s]", test["fileName"])
for url, count in self._zipLeakedWindows(test["leakedWindows"]):
self.logger.info(" %d window(s) [url = %s]", count, url)
if test["leakedDocShells"]:
self.logger.info(" %d docShell(s)", len(test["leakedDocShells"]))
def _logWindow(self, line):
created = line[:2] == "++"
id = self._parseValue(line, "serial")
if self.currentTest:
windows = self.currentTest["windows"]
if created:
windows.add(id)
else:
windows.discard(id)
elif self.seenShutdown and not created:
self.leakedWindows[id] = self._parseValue(line, "url")
def _logDocShell(self, line):
created = line[:2] == "++"
id = self._parseValue(line, "id")
if self.currentTest:
docShells = self.currentTest["docShells"]
if created:
docShells.add(id)
else:
docShells.discard(id)
elif self.seenShutdown and not created:
self.leakedDocShells.add(id)
def _parseValue(self, line, name):
return re.search("\[%s = (.+?)\]" % name, line).group(1)
def _parseLeakingTests(self):
leakingTests = []
for test in self.tests:
test["leakedWindows"] = [self.leakedWindows[id] for id in test["windows"] if id in self.leakedWindows]
test["leakedDocShells"] = [id for id in test["docShells"] if id in self.leakedDocShells]
test["leakCount"] = len(test["leakedWindows"]) + len(test["leakedDocShells"])
if test["leakCount"]:
leakingTests.append(test)
return sorted(leakingTests, key=itemgetter("leakCount"), reverse=True)
def _zipLeakedWindows(self, leakedWindows):
counts = []
counted = set()
for url in leakedWindows:
if not url in counted:
counts.append((url, leakedWindows.count(url)))
counted.add(url)
return sorted(counts, key=itemgetter(1), reverse=True)

View File

@ -96,7 +96,7 @@ class RemoteAutomation(Automation):
return env
def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsDir):
def waitForFinish(self, proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsDir, logger):
# maxTime is used to override the default timeout, we should honor that
status = proc.wait(timeout = maxTime)

View File

@ -785,7 +785,8 @@ nsDocShell::nsDocShell():
// We're counting the number of |nsDocShells| to help find leaks
++gNumberOfDocShells;
if (!PR_GetEnv("MOZ_QUIET")) {
printf("++DOCSHELL %p == %ld\n", (void*) this, gNumberOfDocShells);
printf("++DOCSHELL %p == %ld [id = %ld]\n", (void*) this,
gNumberOfDocShells, mHistoryID);
}
#endif
}
@ -813,7 +814,8 @@ nsDocShell::~nsDocShell()
// We're counting the number of |nsDocShells| to help find leaks
--gNumberOfDocShells;
if (!PR_GetEnv("MOZ_QUIET")) {
printf("--DOCSHELL %p == %ld\n", (void*) this, gNumberOfDocShells);
printf("--DOCSHELL %p == %ld [id = %ld]\n", (void*) this,
gNumberOfDocShells, mHistoryID);
}
#endif
}

View File

@ -675,6 +675,12 @@ class Mochitest(object):
else:
timeout = 330.0 # default JS harness timeout is 300 seconds
# it's a debug build, we can parse leaked DOMWindows and docShells
if Automation.IS_DEBUG_BUILD:
logger = ShutdownLeakLogger(self.automation.log)
else:
logger = None
if options.vmwareRecording:
self.startVMwareRecording(options);
@ -688,6 +694,7 @@ class Mochitest(object):
certPath=options.certPath,
debuggerInfo=debuggerInfo,
symbolsPath=options.symbolsPath,
logger = logger,
timeout = timeout)
except KeyboardInterrupt:
self.automation.log.info("INFO | runtests.py | Received keyboard interrupt.\n");
@ -702,6 +709,10 @@ class Mochitest(object):
self.stopWebServer(options)
self.stopWebSocketServer(options)
processLeakLog(self.leak_report_file, options.leakThreshold)
if logger:
logger.parse()
self.automation.log.info("\nINFO | runtests.py | Running tests: end.")
if manifest is not None:

View File

@ -634,10 +634,15 @@
}
for each (let event in this.videoEvents)
this.video.removeEventListener(event, this, false);
for each(let element in this.controlListeners)
element.item.removeEventListener(element.event, element.func, false);
delete this.controlListeners;
this.video.removeEventListener("media-showStatistics", this._handleCustomEventsBound, false);
delete this._handleCustomEventsBound;
this.video.ownerDocument.removeEventListener("mozfullscreenchange", this._setFullscreenButtonStateBound, false);
delete this._setFullscreenButtonStateBound;
this.log("--- videocontrols terminated ---");
},
@ -931,6 +936,7 @@
togglePause : function () {
if (this.video.paused || this.video.ended) {
this._triggeredByControls = true;
this.hideClickToPlay();
this.video.play();
} else {
this.video.pause();
@ -975,7 +981,19 @@
this.fullscreenButton.removeAttribute("fullscreened");
},
handleClickToPlay : function () {
clickToPlayClickHandler : function(e) {
if (e.button != 0 || this.hasError())
return;
// Read defaultPrevented asynchronously, since Web content
// may want to consume the "click" event but will only
// receive it after us.
let self = this;
setTimeout(function clickToPlayCallback() {
if (!e.defaultPrevented)
self.togglePause();
}, 0);
},
hideClickToPlay : function () {
let videoHeight = this.video.clientHeight;
let videoWidth = this.video.clientWidth;
@ -990,7 +1008,6 @@
this.clickToPlay.removeAttribute("immediate");
}
this.clickToPlay.setAttribute("fadeout", "true");
this.togglePause();
},
setPlayButtonState : function(aPaused) {
@ -1330,47 +1347,36 @@
this.video.addEventListener(event, this, (event == "error") ? true : false);
var self = this;
this.muteButton.addEventListener("command", function() { self.toggleMute(); }, false);
this.playButton.addEventListener("command", function() { self.togglePause(); }, false);
this.fullscreenButton.addEventListener("command", function() { self.toggleFullscreen(); }, false );
this.clickToPlay.addEventListener("click", function clickToPlayClickHandler(e) {
if (e.button != 0 || self.hasError())
return;
// Read defaultPrevented asynchronously, since Web content
// may want to consume the "click" event but will only
// receive it after us.
setTimeout(function clickToPlayCallback() {
if (!e.defaultPrevented)
self.handleClickToPlay();
}, 0);
}, false);
this.controlsSpacer.addEventListener("click", function spacerClickHandler(e) {
if (e.button != 0 || self.hasError())
return;
// Read defaultPrevented asynchronously, since Web content
// may want to consume the "click" event but will only
// receive it after us (bug 693014).
setTimeout(function togglePauseCallback() {
if (!e.defaultPrevented)
self.togglePause();
}, 0);
}, false);
this.controlListeners = [];
if (!this.isAudioOnly) {
this.muteButton.addEventListener("mouseover", function(e) { self.onVolumeMouseInOut(e); }, false);
this.muteButton.addEventListener("mouseout", function(e) { self.onVolumeMouseInOut(e); }, false);
this.volumeStack.addEventListener("mouseover", function(e) { self.onVolumeMouseInOut(e); }, false);
this.volumeStack.addEventListener("mouseout", function(e) { self.onVolumeMouseInOut(e); }, false);
// Helper function to add an event listener to the given element
function addListener(elem, eventName, func) {
let boundFunc = func.bind(self);
self.controlListeners.push({ item: elem, event: eventName, func: boundFunc });
elem.addEventListener(eventName, boundFunc, false);
}
this.videocontrols.addEventListener("transitionend", function(e) { self.onTransitionEnd(e); }, false);
this._setFullscreenButtonStateBound = this.setFullscreenButtonState.bind(this);
this.video.ownerDocument.addEventListener("mozfullscreenchange", this._setFullscreenButtonStateBound, false);
addListener(this.muteButton, "command", this.toggleMute);
addListener(this.playButton, "command", this.togglePause);
addListener(this.fullscreenButton, "command", this.toggleFullscreen);
addListener(this.clickToPlay, "click", this.clickToPlayClickHandler);
addListener(this.controlsSpacer, "click", this.clickToPlayClickHandler);
if (!this.isAudioOnly) {
addListener(this.muteButton, "mouseover", this.onVolumeMouseInOut);
addListener(this.muteButton, "mouseout", this.onVolumeMouseInOut);
addListener(this.volumeStack, "mouseover", this.onVolumeMouseInOut);
addListener(this.volumeStack, "mouseout", this.onVolumeMouseInOut);
}
addListener(this.videocontrols, "transitionend", this.onTransitionEnd);
addListener(this.video.ownerDocument, "mozfullscreenchange", this.setFullscreenButtonState);
// Make the <video> element keyboard accessible.
this.video.setAttribute("tabindex", 0);
this.video.addEventListener("keypress", function (e) { self.keyHandler(e) }, false);
addListener(this.video, "keypress", this.keyHandler);
this.log("--- videocontrols initialized ---");
}

View File

@ -67,6 +67,7 @@ function BrowserRootActor(aConnection)
this._actorFactories = null;
this.onTabClosed = this.onTabClosed.bind(this);
this._onWindowCreated = this.onWindowCreated.bind(this);
windowMediator.addListener(this);
}
@ -75,6 +76,10 @@ BrowserRootActor.prototype = {
* Return a 'hello' packet as specified by the Remote Debugging Protocol.
*/
sayHello: function BRA_sayHello() {
// Create the tab actor for the selected tab right away so that it gets a
// chance to listen to onNewScript notifications.
this._preInitTabActor();
return { from: "root",
applicationType: "browser",
traits: [] };
@ -114,10 +119,6 @@ BrowserRootActor.prototype = {
while (e.hasMoreElements()) {
let win = e.getNext();
// Watch the window for tab closes so we can invalidate
// actors as needed.
this.watchWindow(win);
// List the tabs in this browser.
let selectedBrowser = win.getBrowser().selectedBrowser;
let browsers = win.getBrowser().browsers;
@ -178,16 +179,61 @@ BrowserRootActor.prototype = {
this.exitTabActor(aEvent.target.linkedBrowser);
},
/**
* Handle location changes, by preinitializing a tab actor.
*/
onWindowCreated: function BRA_onWindowCreated(evt) {
if (evt.target === this.browser.contentDocument) {
this._preInitTabActor();
}
},
/**
* Exit the tab actor of the specified tab.
*/
exitTabActor: function BRA_exitTabActor(aWindow) {
this.browser.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
let actor = this._tabActors.get(aWindow);
if (actor) {
actor.exit();
}
},
/**
* Create the tab actor in the selected tab right away so that it gets a
* chance to listen to onNewScript notifications.
*/
_preInitTabActor: function BRA__preInitTabActor() {
let actorPool = new ActorPool(this.conn);
// Walk over open browser windows.
let e = windowMediator.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
let win = e.getNext();
// Watch the window for tab closes so we can invalidate
// actors as needed.
this.watchWindow(win);
this.browser = win.getBrowser().selectedBrowser;
let actor = this._tabActors.get(this.browser);
if (actor) {
actor._detach();
}
actor = new BrowserTabActor(this.conn, this.browser);
actor.parentID = this.actorID;
this._tabActors.set(this.browser, actor);
actorPool.addActor(actor);
}
this._tabActorPool = actorPool;
this.conn.addActorPool(this._tabActorPool);
// Watch for globals being created in this tab.
this.browser.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
},
// nsIWindowMediatorListener
onWindowTitleChange: function BRA_onWindowTitleChange(aWindow, aTitle) { },
onOpenWindow: function BRA_onOpenWindow(aWindow) { },
@ -195,7 +241,7 @@ BrowserRootActor.prototype = {
if (aWindow.getBrowser) {
this.unwatchWindow(aWindow);
}
},
}
}
/**
@ -220,6 +266,7 @@ function BrowserTabActor(aConnection, aBrowser)
this._browser = aBrowser;
this._onWindowCreated = this.onWindowCreated.bind(this);
this._attach();
}
// XXX (bug 710213): BrowserTabActor attach/detach/exit/disconnect is a
@ -290,7 +337,7 @@ BrowserTabActor.prototype = {
this._pushContext();
// Watch for globals being created in this tab.
this.browser.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
this.browser.addEventListener("DOMWindowCreated", this._onWindowCreated, false);
this._attached = true;
},
@ -331,7 +378,7 @@ BrowserTabActor.prototype = {
return;
}
this.browser.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
this.browser.removeEventListener("DOMWindowCreated", this._onWindowCreated, false);
this._popContext();
@ -397,8 +444,7 @@ BrowserTabActor.prototype = {
url: this.browser.contentDocument.URL });
}
}
},
}
};
/**

View File

@ -99,12 +99,19 @@ ThreadActor.prototype = {
this._dbg = new Debugger();
}
// TODO: Remove this horrible hack when bug 723563 is fixed.
// Make sure that a chrome window is not added as a debuggee when opening
// the debugger in an empty tab or during tests.
if (aGlobal.location &&
(aGlobal.location.protocol == "about:" ||
aGlobal.location.protocol == "chrome:")) {
return;
}
this.dbg.addDebuggee(aGlobal);
this.dbg.uncaughtExceptionHook = this.uncaughtExceptionHook.bind(this);
this.dbg.onDebuggerStatement = this.onDebuggerStatement.bind(this);
this.dbg.onNewScript = this.onNewScript.bind(this);
// Keep the debugger disabled until a client attaches.
this.dbg.enabled = false;
},
/**

View File

@ -146,6 +146,7 @@ add_test(function() {
}, false);
info("Opening context menu on enabled extension item");
el.parentNode.ensureElementIsVisible(el);
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
});
@ -165,6 +166,7 @@ add_test(function() {
}, false);
info("Opening context menu on newly disabled extension item");
el.parentNode.ensureElementIsVisible(el);
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
});
@ -184,6 +186,7 @@ add_test(function() {
}, false);
info("Opening context menu on newly enabled extension item");
el.parentNode.ensureElementIsVisible(el);
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
});
@ -201,6 +204,7 @@ add_test(function() {
}, false);
info("Opening context menu on disabled extension item");
el.parentNode.ensureElementIsVisible(el);
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
});
@ -214,13 +218,14 @@ add_test(function() {
gContextMenu.addEventListener("popupshown", function() {
gContextMenu.removeEventListener("popupshown", arguments.callee, false);
check_contextmenu(true, true, false, false, false);
check_contextmenu(true, true, false, false, false);
gContextMenu.hidePopup();
run_next_test();
}, false);
info("Opening context menu on enabled theme item");
el.parentNode.ensureElementIsVisible(el);
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
});
@ -240,6 +245,7 @@ add_test(function() {
}, false);
info("Opening context menu on disabled theme item");
el.parentNode.ensureElementIsVisible(el);
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
});
@ -260,6 +266,7 @@ add_test(function() {
}, false);
info("Opening context menu on enabled LW theme item");
el.parentNode.ensureElementIsVisible(el);
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
});
@ -280,6 +287,7 @@ add_test(function() {
}, false);
info("Opening context menu on disabled LW theme item");
el.parentNode.ensureElementIsVisible(el);
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
});
@ -467,6 +475,7 @@ add_test(function() {
}, false);
info("Opening context menu on remote extension item");
el.parentNode.ensureElementIsVisible(el);
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);

View File

@ -13,6 +13,12 @@ function test() {
function check_load(aCallback) {
gBrowser.addEventListener("load", function(aEvent) {
// SeaMonkey needs to deal with intermediate "about:blank" document(s).
if (!aEvent.target.location) {
info("Ignoring about:blank load. (Expected (a few times) on SeaMonkey only.)");
return;
}
gBrowser.removeEventListener("load", arguments.callee, true);
// Let the load handler complete

View File

@ -77,7 +77,7 @@
/* margin left/right: make bar 8px wide (control width = 28, minus 2 * 10 margin) */
margin: 0 10px;
background-color: rgba(255,255,255,.5);
border-radius: 4px 4px;
border-radius: 2.5px;
}
.durationBox {
@ -102,7 +102,7 @@
/* margin left/right: 1/2 of scrubber thumb width, for overhang. */
margin: 10px 22px;
background-color: rgba(255,255,255,.5);
border-radius: 4px;
border-radius: 2.5px;
}
.bufferBar,
@ -122,12 +122,12 @@
* compositing gives it a different visual appearance.
*/
background-color: rgba(255,255,255,.5);
border-radius: 4px;
border-radius: 2.5px;
}
.progressBar .progress-bar {
background-color: white;
border-radius: 4px 0 0 4px;
border-radius: 2.5px;
}
/* .scale-slider is an element inside the <scale> implementation. */

View File

@ -79,7 +79,7 @@
/* margin left/right: make bar 8px wide (control width = 28, minus 2 * 10 margin) */
margin: 0 10px;
background-color: rgba(255,255,255,.5);
border-radius: 4px 4px;
border-radius: 2.5px;
}
.durationBox {
@ -104,7 +104,7 @@
/* margin left/right: 1/2 of scrubber thumb width, for overhang. */
margin: 10px 22px;
background-color: rgba(255,255,255,.5);
border-radius: 4px;
border-radius: 2.5px;
}
.bufferBar,
@ -127,13 +127,13 @@
* compositing gives it a different visual appearance.
*/
background-color: rgba(255,255,255,.5);
border-radius: 4px;
border-radius: 2.5px;
-moz-appearance: none;
}
.progressBar .progress-bar {
background-color: white;
border-radius: 4px 0 0 4px;
border-radius: 2.5px;
-moz-appearance: none;
}

View File

@ -972,8 +972,8 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
if (points.Length() > 0) {
pt = points[0];
}
pt.x = clamped(pt.x, 0, gAndroidBounds.width - 1);
pt.y = clamped(pt.y, 0, gAndroidBounds.height - 1);
pt.x = clamped(pt.x, 0, PR_MAX(gAndroidBounds.width - 1, 0));
pt.y = clamped(pt.y, 0, PR_MAX(gAndroidBounds.height - 1, 0));
nsWindow *target = win->FindWindowForPoint(pt);
#if 0
ALOG("MOTION_EVENT %f,%f -> %p (visible: %d children: %d)", pt.x, pt.y, (void*)target,