зеркало из https://github.com/mozilla/gecko-dev.git
Bug 650794 - Disable HTML panel and make it use registerTools API; r=msucan
--HG-- rename : browser/devtools/highlighter/insideOutBox.js => browser/devtools/highlighter/InsideOutBox.jsm
This commit is contained in:
Родитель
6874df2014
Коммит
5ec6c6a313
|
@ -232,7 +232,6 @@
|
|||
noautohide="true"
|
||||
titlebar="normal"
|
||||
close="true"
|
||||
onpopuphiding="InspectorUI.closeInspectorUI();"
|
||||
label="&inspectPanelTitle.label;">
|
||||
<hbox id="tree-panel-resizer-box" align="end">
|
||||
<spacer flex="1" />
|
||||
|
|
|
@ -125,6 +125,9 @@ InsideOutBoxView = {
|
|||
* The box object containing the InsideOutBox. Required to add/remove
|
||||
* children during box manipulation (toggling opened or closed).
|
||||
*/
|
||||
|
||||
var EXPORTED_SYMBOLS = ["InsideOutBox"];
|
||||
|
||||
function InsideOutBox(aView, aBox)
|
||||
{
|
||||
this.view = aView;
|
||||
|
@ -450,7 +453,7 @@ InsideOutBox.prototype =
|
|||
try {
|
||||
this.box.removeChild(this.rootObjectBox);
|
||||
} catch (exc) {
|
||||
InspectorUI._log("this.box.removeChild(this.rootObjectBox) FAILS " +
|
||||
this.view._log("this.box.removeChild(this.rootObjectBox) FAILS " +
|
||||
this.box + " must not contain " + this.rootObjectBox);
|
||||
}
|
||||
}
|
||||
|
@ -643,4 +646,18 @@ InsideOutBox.prototype =
|
|||
|
||||
return node;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clean up our mess.
|
||||
*/
|
||||
destroy: function IOBox_destroy()
|
||||
{
|
||||
delete this.view;
|
||||
delete this.box;
|
||||
delete this.rootObject;
|
||||
delete this.rootObjectBox;
|
||||
delete this.selectedObjectBox;
|
||||
delete this.highlightedObjectBox;
|
||||
delete this.scrollIntoView;
|
||||
}
|
||||
};
|
|
@ -46,6 +46,8 @@ include $(DEPTH)/config/autoconf.mk
|
|||
|
||||
EXTRA_JS_MODULES = \
|
||||
domplate.jsm \
|
||||
InsideOutBox.jsm \
|
||||
TreePanel.jsm \
|
||||
$(NULL)
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
|
|
|
@ -0,0 +1,694 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Mozilla Tree Panel.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Rob Campbell <rcampbell@mozilla.com> (original author)
|
||||
* Mihai Șucan <mihai.sucan@gmail.com>
|
||||
* Julian Viereck <jviereck@mozilla.com>
|
||||
* Paul Rouget <paul@mozilla.com>
|
||||
* Kyle Simpson <getify@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource:///modules/domplate.jsm");
|
||||
Cu.import("resource:///modules/InsideOutBox.jsm");
|
||||
Cu.import("resource:///modules/Services.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = ["TreePanel"];
|
||||
|
||||
/**
|
||||
* TreePanel
|
||||
* A container for the Inspector's HTML Tree Panel widget constructor function.
|
||||
* @param aContext nsIDOMWindow (xulwindow)
|
||||
* @param aIUI global InspectorUI object
|
||||
*/
|
||||
function TreePanel(aContext, aIUI) {
|
||||
this._init(aContext, aIUI);
|
||||
};
|
||||
|
||||
TreePanel.prototype = {
|
||||
showTextNodesWithWhitespace: false,
|
||||
id: "treepanel", // DO NOT LOCALIZE
|
||||
|
||||
/**
|
||||
* container.
|
||||
* @returns xul:panel element
|
||||
*/
|
||||
get container()
|
||||
{
|
||||
return this.document.getElementById("inspector-tree-panel");
|
||||
},
|
||||
|
||||
/**
|
||||
* Main TreePanel boot-strapping method. Initialize the TreePanel with the
|
||||
* originating context and the InspectorUI global.
|
||||
* @param aContext nsIDOMWindow (xulwindow)
|
||||
* @param aIUI global InspectorUI object
|
||||
*/
|
||||
_init: function TP__init(aContext, aIUI)
|
||||
{
|
||||
this.IUI = aIUI;
|
||||
this.window = aContext;
|
||||
this.document = this.window.document;
|
||||
|
||||
domplateUtils.setDOM(this.window);
|
||||
|
||||
let isOpen = this.isOpen.bind(this);
|
||||
|
||||
this.registrationObject = {
|
||||
id: this.id,
|
||||
label: this.IUI.strings.GetStringFromName("htmlPanel.label"),
|
||||
tooltiptext: this.IUI.strings.GetStringFromName("htmlPanel.tooltiptext"),
|
||||
accesskey: this.IUI.strings.GetStringFromName("htmlPanel.accesskey"),
|
||||
context: this,
|
||||
get isOpen() isOpen(),
|
||||
show: this.open,
|
||||
hide: this.close,
|
||||
onSelect: this.select,
|
||||
panel: this.container,
|
||||
unregister: this.destroy,
|
||||
};
|
||||
this.editingEvents = {};
|
||||
|
||||
this._boundClose = this.close.bind(this);
|
||||
this.container.addEventListener("popuphiding", this._boundClose, false);
|
||||
|
||||
// Register the HTML panel with the highlighter
|
||||
this.IUI.registerTool(this.registrationObject);
|
||||
},
|
||||
|
||||
/**
|
||||
* Initialization function for the TreePanel.
|
||||
*/
|
||||
initializeIFrame: function TP_initializeIFrame()
|
||||
{
|
||||
if (!this.initializingTreePanel || this.treeLoaded) {
|
||||
return;
|
||||
}
|
||||
this.treeBrowserDocument = this.treeIFrame.contentDocument;
|
||||
this.treePanelDiv = this.treeBrowserDocument.createElement("div");
|
||||
this.treeBrowserDocument.body.appendChild(this.treePanelDiv);
|
||||
this.treePanelDiv.ownerPanel = this;
|
||||
this.ioBox = new InsideOutBox(this, this.treePanelDiv);
|
||||
this.ioBox.createObjectBox(this.IUI.win.document.documentElement);
|
||||
this.treeLoaded = true;
|
||||
this.treeIFrame.addEventListener("click", this.onTreeClick.bind(this), false);
|
||||
this.treeIFrame.addEventListener("dblclick", this.onTreeDblClick.bind(this), false);
|
||||
delete this.initializingTreePanel;
|
||||
Services.obs.notifyObservers(null,
|
||||
this.window.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, null);
|
||||
if (this.IUI.selection)
|
||||
this.select(this.IUI.selection, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the inspector's tree panel and initialize it.
|
||||
*/
|
||||
open: function TP_open()
|
||||
{
|
||||
if (this.initializingTreePanel && !this.treeLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.initializingTreePanel = true;
|
||||
this.container.hidden = false;
|
||||
|
||||
this.treeIFrame = this.document.getElementById("inspector-tree-iframe");
|
||||
if (!this.treeIFrame) {
|
||||
let resizerBox = this.document.getElementById("tree-panel-resizer-box");
|
||||
this.treeIFrame = this.document.createElement("iframe");
|
||||
this.treeIFrame.setAttribute("id", "inspector-tree-iframe");
|
||||
this.treeIFrame.setAttribute("flex", "1");
|
||||
this.treeIFrame.setAttribute("type", "content");
|
||||
this.treeIFrame = this.container.insertBefore(this.treeIFrame, resizerBox);
|
||||
}
|
||||
|
||||
let self = this;
|
||||
this.container.addEventListener("popupshown", function treePanelShown() {
|
||||
self.container.removeEventListener("popupshown",
|
||||
treePanelShown, false);
|
||||
|
||||
self.treeIFrame.addEventListener("load",
|
||||
function loadedInitializeTreePanel() {
|
||||
self.treeIFrame.removeEventListener("load",
|
||||
loadedInitializeTreePanel, true);
|
||||
self.initializeIFrame();
|
||||
}, true);
|
||||
|
||||
let src = self.treeIFrame.getAttribute("src");
|
||||
if (src != "chrome://browser/content/inspector.html") {
|
||||
self.treeIFrame.setAttribute("src",
|
||||
"chrome://browser/content/inspector.html");
|
||||
} else {
|
||||
self.treeIFrame.contentWindow.location.reload();
|
||||
}
|
||||
}, 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);
|
||||
},
|
||||
|
||||
/**
|
||||
* Close the TreePanel.
|
||||
*/
|
||||
close: function TP_close()
|
||||
{
|
||||
if (this.treePanelDiv) {
|
||||
this.treePanelDiv.ownerPanel = null;
|
||||
let parent = this.treePanelDiv.parentNode;
|
||||
parent.removeChild(this.treePanelDiv);
|
||||
delete this.treePanelDiv;
|
||||
delete this.treeBrowserDocument;
|
||||
}
|
||||
|
||||
this.treeLoaded = false;
|
||||
this.container.hidePopup();
|
||||
},
|
||||
|
||||
/**
|
||||
* Is the TreePanel open?
|
||||
* @returns boolean
|
||||
*/
|
||||
isOpen: function TP_isOpen()
|
||||
{
|
||||
return this.treeLoaded && this.container.state == "open";
|
||||
},
|
||||
|
||||
/**
|
||||
* Create the ObjectBox for the given object.
|
||||
* @param object nsIDOMNode
|
||||
* @param isRoot boolean - Is this the root object?
|
||||
* @returns InsideOutBox
|
||||
*/
|
||||
createObjectBox: function TP_createObjectBox(object, isRoot)
|
||||
{
|
||||
let tag = domplateUtils.getNodeTag(object);
|
||||
if (tag)
|
||||
return tag.replace({object: object}, this.treeBrowserDocument);
|
||||
},
|
||||
|
||||
getParentObject: function TP_getParentObject(node)
|
||||
{
|
||||
let parentNode = node ? node.parentNode : null;
|
||||
|
||||
if (!parentNode) {
|
||||
// Documents have no parentNode; Attr, Document, DocumentFragment, Entity,
|
||||
// and Notation. top level windows have no parentNode
|
||||
if (node && node == this.window.Node.DOCUMENT_NODE) {
|
||||
// document type
|
||||
if (node.defaultView) {
|
||||
let embeddingFrame = node.defaultView.frameElement;
|
||||
if (embeddingFrame)
|
||||
return embeddingFrame.parentNode;
|
||||
}
|
||||
}
|
||||
// a Document object without a parentNode or window
|
||||
return null; // top level has no parent
|
||||
}
|
||||
|
||||
if (parentNode.nodeType == this.window.Node.DOCUMENT_NODE) {
|
||||
if (parentNode.defaultView) {
|
||||
return parentNode.defaultView.frameElement;
|
||||
}
|
||||
// parent is document element, but no window at defaultView.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!parentNode.localName)
|
||||
return null;
|
||||
|
||||
return parentNode;
|
||||
},
|
||||
|
||||
getChildObject: function TP_getChildObject(node, index, previousSibling)
|
||||
{
|
||||
if (!node)
|
||||
return null;
|
||||
|
||||
if (node.contentDocument) {
|
||||
// then the node is a frame
|
||||
if (index == 0) {
|
||||
return node.contentDocument.documentElement; // the node's HTMLElement
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (node instanceof this.window.GetSVGDocument) {
|
||||
let svgDocument = node.getSVGDocument();
|
||||
if (svgDocument) {
|
||||
// then the node is a frame
|
||||
if (index == 0) {
|
||||
return svgDocument.documentElement; // the node's SVGElement
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
let child = null;
|
||||
if (previousSibling) // then we are walking
|
||||
child = this.getNextSibling(previousSibling);
|
||||
else
|
||||
child = this.getFirstChild(node);
|
||||
|
||||
if (this.showTextNodesWithWhitespace)
|
||||
return child;
|
||||
|
||||
for (; child; child = this.getNextSibling(child)) {
|
||||
if (!domplateUtils.isWhitespaceText(child))
|
||||
return child;
|
||||
}
|
||||
|
||||
return null; // we have no children worth showing.
|
||||
},
|
||||
|
||||
getFirstChild: function TP_getFirstChild(node)
|
||||
{
|
||||
this.treeWalker = node.ownerDocument.createTreeWalker(node,
|
||||
this.window.NodeFilter.SHOW_ALL, null, false);
|
||||
return this.treeWalker.firstChild();
|
||||
},
|
||||
|
||||
getNextSibling: function TP_getNextSibling(node)
|
||||
{
|
||||
let next = this.treeWalker.nextSibling();
|
||||
|
||||
if (!next)
|
||||
delete this.treeWalker;
|
||||
|
||||
return next;
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Event Handling
|
||||
|
||||
/**
|
||||
* Handle click events in the html tree panel.
|
||||
* @param aEvent
|
||||
* The mouse event.
|
||||
*/
|
||||
onTreeClick: function TP_onTreeClick(aEvent)
|
||||
{
|
||||
let node;
|
||||
let target = aEvent.target;
|
||||
let hitTwisty = false;
|
||||
if (this.hasClass(target, "twisty")) {
|
||||
node = this.getRepObject(aEvent.target.nextSibling);
|
||||
hitTwisty = true;
|
||||
} else {
|
||||
node = this.getRepObject(aEvent.target);
|
||||
}
|
||||
|
||||
if (node) {
|
||||
if (hitTwisty) {
|
||||
this.ioBox.toggleObject(node);
|
||||
} else {
|
||||
if (this.IUI.inspecting) {
|
||||
this.IUI.stopInspecting(true);
|
||||
} else {
|
||||
this.IUI.select(node, true, false);
|
||||
this.IUI.highlighter.highlightNode(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle double-click events in the html tree panel.
|
||||
* (double-clicking an attribute value allows it to be edited)
|
||||
* @param aEvent
|
||||
* The mouse event.
|
||||
*/
|
||||
onTreeDblClick: function TP_onTreeDblClick(aEvent)
|
||||
{
|
||||
// if already editing an attribute value, double-clicking elsewhere
|
||||
// in the tree is the same as a click, which dismisses the editor
|
||||
if (this.editingContext)
|
||||
this.closeEditor();
|
||||
|
||||
let target = aEvent.target;
|
||||
|
||||
if (this.hasClass(target, "nodeValue")) {
|
||||
let repObj = this.getRepObject(target);
|
||||
let attrName = target.getAttribute("data-attributeName");
|
||||
let attrVal = target.innerHTML;
|
||||
|
||||
this.editAttributeValue(target, repObj, attrName, attrVal);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts the editor for an attribute value.
|
||||
* @param aAttrObj
|
||||
* The DOM object representing the attribute value in the HTML Tree
|
||||
* @param aRepObj
|
||||
* The original DOM (target) object being inspected/edited
|
||||
* @param aAttrName
|
||||
* The name of the attribute being edited
|
||||
* @param aAttrVal
|
||||
* The current value of the attribute being edited
|
||||
*/
|
||||
editAttributeValue:
|
||||
function TP_editAttributeValue(aAttrObj, aRepObj, aAttrName, aAttrVal)
|
||||
{
|
||||
let editor = this.treeBrowserDocument.getElementById("attribute-editor");
|
||||
let editorInput =
|
||||
this.treeBrowserDocument.getElementById("attribute-editor-input");
|
||||
let attrDims = aAttrObj.getBoundingClientRect();
|
||||
// figure out actual viewable viewport dimensions (sans scrollbars)
|
||||
let viewportWidth = this.treeBrowserDocument.documentElement.clientWidth;
|
||||
let viewportHeight = this.treeBrowserDocument.documentElement.clientHeight;
|
||||
|
||||
// saves the editing context for use when the editor is saved/closed
|
||||
this.editingContext = {
|
||||
attrObj: aAttrObj,
|
||||
repObj: aRepObj,
|
||||
attrName: aAttrName
|
||||
};
|
||||
|
||||
// highlight attribute-value node in tree while editing
|
||||
this.addClass(aAttrObj, "editingAttributeValue");
|
||||
|
||||
// show the editor
|
||||
this.addClass(editor, "editing");
|
||||
|
||||
// offset the editor below the attribute-value node being edited
|
||||
let editorVeritcalOffset = 2;
|
||||
|
||||
// keep the editor comfortably within the bounds of the viewport
|
||||
let editorViewportBoundary = 5;
|
||||
|
||||
// outer editor is sized based on the <input> box inside it
|
||||
editorInput.style.width = Math.min(attrDims.width, viewportWidth -
|
||||
editorViewportBoundary) + "px";
|
||||
editorInput.style.height = Math.min(attrDims.height, viewportHeight -
|
||||
editorViewportBoundary) + "px";
|
||||
let editorDims = editor.getBoundingClientRect();
|
||||
|
||||
// calculate position for the editor according to the attribute node
|
||||
let editorLeft = attrDims.left + this.treeIFrame.contentWindow.scrollX -
|
||||
// center the editor against the attribute value
|
||||
((editorDims.width - attrDims.width) / 2);
|
||||
let editorTop = attrDims.top + this.treeIFrame.contentWindow.scrollY +
|
||||
attrDims.height + editorVeritcalOffset;
|
||||
|
||||
// but, make sure the editor stays within the visible viewport
|
||||
editorLeft = Math.max(0, Math.min(
|
||||
(this.treeIFrame.contentWindow.scrollX +
|
||||
viewportWidth - editorDims.width),
|
||||
editorLeft)
|
||||
);
|
||||
editorTop = Math.max(0, Math.min(
|
||||
(this.treeIFrame.contentWindow.scrollY +
|
||||
viewportHeight - editorDims.height),
|
||||
editorTop)
|
||||
);
|
||||
|
||||
// position the editor
|
||||
editor.style.left = editorLeft + "px";
|
||||
editor.style.top = editorTop + "px";
|
||||
|
||||
// set and select the text
|
||||
editorInput.value = aAttrVal;
|
||||
editorInput.select();
|
||||
|
||||
// listen for editor specific events
|
||||
this.bindEditorEvent(editor, "click", function(aEvent) {
|
||||
aEvent.stopPropagation();
|
||||
});
|
||||
this.bindEditorEvent(editor, "dblclick", function(aEvent) {
|
||||
aEvent.stopPropagation();
|
||||
});
|
||||
this.bindEditorEvent(editor, "keypress",
|
||||
this.handleEditorKeypress.bind(this));
|
||||
|
||||
// event notification
|
||||
Services.obs.notifyObservers(null, this.window.INSPECTOR_NOTIFICATIONS.EDITOR_OPENED,
|
||||
null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle binding an event handler for the editor.
|
||||
* (saves the callback for easier unbinding later)
|
||||
* @param aEditor
|
||||
* The DOM object for the editor
|
||||
* @param aEventName
|
||||
* The name of the event to listen for
|
||||
* @param aEventCallback
|
||||
* The callback to bind to the event (and also to save for later
|
||||
* unbinding)
|
||||
*/
|
||||
bindEditorEvent:
|
||||
function TP_bindEditorEvent(aEditor, aEventName, aEventCallback)
|
||||
{
|
||||
this.editingEvents[aEventName] = aEventCallback;
|
||||
aEditor.addEventListener(aEventName, aEventCallback, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle unbinding an event handler from the editor.
|
||||
* (unbinds the previously bound and saved callback)
|
||||
* @param aEditor
|
||||
* The DOM object for the editor
|
||||
* @param aEventName
|
||||
* The name of the event being listened for
|
||||
*/
|
||||
unbindEditorEvent: function TP_unbindEditorEvent(aEditor, aEventName)
|
||||
{
|
||||
aEditor.removeEventListener(aEventName, this.editingEvents[aEventName],
|
||||
false);
|
||||
this.editingEvents[aEventName] = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle keypress events in the editor.
|
||||
* @param aEvent
|
||||
* The keyboard event.
|
||||
*/
|
||||
handleEditorKeypress: function TP_handleEditorKeypress(aEvent)
|
||||
{
|
||||
if (aEvent.which == this.window.KeyEvent.DOM_VK_RETURN) {
|
||||
this.saveEditor();
|
||||
} else if (aEvent.keyCode == this.window.KeyEvent.DOM_VK_ESCAPE) {
|
||||
this.closeEditor();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Close the editor and cleanup.
|
||||
*/
|
||||
closeEditor: function TP_closeEditor()
|
||||
{
|
||||
let editor = this.treeBrowserDocument.getElementById("attribute-editor");
|
||||
let editorInput =
|
||||
this.treeBrowserDocument.getElementById("attribute-editor-input");
|
||||
|
||||
// remove highlight from attribute-value node in tree
|
||||
this.removeClass(this.editingContext.attrObj, "editingAttributeValue");
|
||||
|
||||
// hide editor
|
||||
this.removeClass(editor, "editing");
|
||||
|
||||
// stop listening for editor specific events
|
||||
this.unbindEditorEvent(editor, "click");
|
||||
this.unbindEditorEvent(editor, "dblclick");
|
||||
this.unbindEditorEvent(editor, "keypress");
|
||||
|
||||
// clean up after the editor
|
||||
editorInput.value = "";
|
||||
editorInput.blur();
|
||||
this.editingContext = null;
|
||||
this.editingEvents = {};
|
||||
|
||||
// event notification
|
||||
Services.obs.notifyObservers(null, this.window.INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED,
|
||||
null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Commit the edits made in the editor, then close it.
|
||||
*/
|
||||
saveEditor: function TP_saveEditor()
|
||||
{
|
||||
let editorInput =
|
||||
this.treeBrowserDocument.getElementById("attribute-editor-input");
|
||||
|
||||
// set the new attribute value on the original target DOM element
|
||||
this.editingContext.repObj.setAttribute(this.editingContext.attrName,
|
||||
editorInput.value);
|
||||
|
||||
// update the HTML tree attribute value
|
||||
this.editingContext.attrObj.innerHTML = editorInput.value;
|
||||
|
||||
this.IUI.isDirty = true;
|
||||
|
||||
// event notification
|
||||
Services.obs.notifyObservers(null, this.window.INSPECTOR_NOTIFICATIONS.EDITOR_SAVED,
|
||||
null);
|
||||
|
||||
this.closeEditor();
|
||||
},
|
||||
|
||||
/**
|
||||
* Simple tree select method.
|
||||
* @param aNode the DOM node in the content document to select.
|
||||
* @param aScroll boolean scroll to the visible node?
|
||||
*/
|
||||
select: function TP_select(aNode, aScroll)
|
||||
{
|
||||
if (this.ioBox)
|
||||
this.ioBox.select(aNode, true, true, aScroll);
|
||||
},
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//// Utility functions
|
||||
|
||||
/**
|
||||
* Does the given object have a class attribute?
|
||||
* @param aNode
|
||||
* the DOM node.
|
||||
* @param aClass
|
||||
* The class string.
|
||||
* @returns boolean
|
||||
*/
|
||||
hasClass: function TP_hasClass(aNode, aClass)
|
||||
{
|
||||
if (!(aNode instanceof this.window.Element))
|
||||
return false;
|
||||
return aNode.classList.contains(aClass);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the class name to the given object.
|
||||
* @param aNode
|
||||
* the DOM node.
|
||||
* @param aClass
|
||||
* The class string.
|
||||
*/
|
||||
addClass: function TP_addClass(aNode, aClass)
|
||||
{
|
||||
if (aNode instanceof this.window.Element)
|
||||
aNode.classList.add(aClass);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the class name from the given object
|
||||
* @param aNode
|
||||
* the DOM node.
|
||||
* @param aClass
|
||||
* The class string.
|
||||
*/
|
||||
removeClass: function TP_removeClass(aNode, aClass)
|
||||
{
|
||||
if (aNode instanceof this.window.Element)
|
||||
aNode.classList.remove(aClass);
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the "repObject" from the HTML panel's domplate-constructed DOM node.
|
||||
* In this system, a "repObject" is the Object being Represented by the box
|
||||
* object. It is the "real" object that we're building our facade around.
|
||||
*
|
||||
* @param element
|
||||
* The element in the HTML panel the user clicked.
|
||||
* @returns either a real node or null
|
||||
*/
|
||||
getRepObject: function TP_getRepObject(element)
|
||||
{
|
||||
let target = null;
|
||||
for (let child = element; child; child = child.parentNode) {
|
||||
if (this.hasClass(child, "repTarget"))
|
||||
target = child;
|
||||
|
||||
if (child.repObject) {
|
||||
if (!target && this.hasClass(child.repObject, "repIgnore"))
|
||||
break;
|
||||
else
|
||||
return child.repObject;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Destructor function. Cleanup.
|
||||
*/
|
||||
destroy: function TP_destroy()
|
||||
{
|
||||
if (this.isOpen()) {
|
||||
this.close();
|
||||
}
|
||||
|
||||
domplateUtils.setDOM(null);
|
||||
|
||||
delete this.treeWalker;
|
||||
|
||||
if (this.treePanelDiv) {
|
||||
this.treePanelDiv.ownerPanel = null;
|
||||
let parent = this.treePanelDiv.parentNode;
|
||||
parent.removeChild(this.treePanelDiv);
|
||||
delete this.treePanelDiv;
|
||||
delete this.treeBrowserDocument;
|
||||
}
|
||||
|
||||
if (this.treeIFrame) {
|
||||
this.treeIFrame.removeEventListener("dblclick", this.onTreeDblClick, false);
|
||||
this.treeIFrame.removeEventListener("click", this.onTreeClick, false);
|
||||
let parent = this.treeIFrame.parentNode;
|
||||
parent.removeChild(this.treeIFrame);
|
||||
delete this.treeIFrame;
|
||||
}
|
||||
|
||||
if (this.ioBox) {
|
||||
this.ioBox.destroy();
|
||||
delete this.ioBox;
|
||||
}
|
||||
|
||||
this.container.removeEventListener("popuphiding", this._boundClose, false);
|
||||
delete this._boundClose;
|
||||
}
|
||||
};
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
* Mihai Șucan <mihai.sucan@gmail.com>
|
||||
* Julian Viereck <jviereck@mozilla.com>
|
||||
* Paul Rouget <paul@mozilla.com>
|
||||
* Kyle Simpson <ksimpson@mozilla.com>
|
||||
* Kyle Simpson <ksimpson@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
|
||||
|
@ -43,8 +43,6 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
#endif
|
||||
|
||||
#include insideOutBox.js
|
||||
|
||||
const INSPECTOR_INVISIBLE_ELEMENTS = {
|
||||
"head": true,
|
||||
"base": true,
|
||||
|
@ -72,6 +70,9 @@ const INSPECTOR_NOTIFICATIONS = {
|
|||
// Fires once the Inspector is closed.
|
||||
CLOSED: "inspector-closed",
|
||||
|
||||
// Fires when the Tree Panel is opened and initialized.
|
||||
TREEPANELREADY: "inspector-treepanel-ready",
|
||||
|
||||
// Event notifications for the attribute-value editor
|
||||
EDITOR_OPENED: "inspector-editor-opened",
|
||||
EDITOR_CLOSED: "inspector-editor-closed",
|
||||
|
@ -554,9 +555,8 @@ var InspectorUI = {
|
|||
browser: null,
|
||||
tools: {},
|
||||
toolEvents: {},
|
||||
showTextNodesWithWhitespace: false,
|
||||
inspecting: false,
|
||||
treeLoaded: false,
|
||||
treePanelEnabled: true,
|
||||
get enabled()
|
||||
{
|
||||
return gPrefService.getBoolPref("devtools.inspector.enabled");
|
||||
|
@ -571,7 +571,7 @@ var InspectorUI = {
|
|||
*/
|
||||
toggleInspectorUI: function IUI_toggleInspectorUI(aEvent)
|
||||
{
|
||||
if (this.isTreePanelOpen) {
|
||||
if (this.isInspectorOpen) {
|
||||
this.closeInspectorUI();
|
||||
} else {
|
||||
this.openInspectorUI();
|
||||
|
@ -592,13 +592,13 @@ var InspectorUI = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Is the tree panel open?
|
||||
* Is the inspector UI open? Simply check if the toolbar is visible or not.
|
||||
*
|
||||
* @returns boolean
|
||||
*/
|
||||
get isTreePanelOpen()
|
||||
get isInspectorOpen()
|
||||
{
|
||||
return this.treePanel && this.treePanel.state == "open";
|
||||
return this.toolbar && !this.toolbar.hidden && this.highlighter;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -610,176 +610,6 @@ var InspectorUI = {
|
|||
return doc.documentElement ? doc.documentElement.lastElementChild : null;
|
||||
},
|
||||
|
||||
initializeTreePanel: function IUI_initializeTreePanel()
|
||||
{
|
||||
this.treeBrowserDocument = this.treeIFrame.contentDocument;
|
||||
this.treePanelDiv = this.treeBrowserDocument.createElement("div");
|
||||
this.treeBrowserDocument.body.appendChild(this.treePanelDiv);
|
||||
this.treePanelDiv.ownerPanel = this;
|
||||
this.ioBox = new InsideOutBox(this, this.treePanelDiv);
|
||||
this.ioBox.createObjectBox(this.win.document.documentElement);
|
||||
this.treeLoaded = true;
|
||||
this.editingContext = null;
|
||||
this.editingEvents = {};
|
||||
|
||||
// initialize the highlighter
|
||||
this.initializeHighlighter();
|
||||
},
|
||||
|
||||
/**
|
||||
* Open the inspector's tree panel and initialize it.
|
||||
*/
|
||||
openTreePanel: function IUI_openTreePanel()
|
||||
{
|
||||
if (!this.treePanel) {
|
||||
this.treePanel = document.getElementById("inspector-tree-panel");
|
||||
this.treePanel.hidden = false;
|
||||
}
|
||||
|
||||
this.treeIFrame = document.getElementById("inspector-tree-iframe");
|
||||
if (!this.treeIFrame) {
|
||||
let resizerBox = document.getElementById("tree-panel-resizer-box");
|
||||
this.treeIFrame = document.createElement("iframe");
|
||||
this.treeIFrame.setAttribute("id", "inspector-tree-iframe");
|
||||
this.treeIFrame.setAttribute("flex", "1");
|
||||
this.treeIFrame.setAttribute("type", "content");
|
||||
this.treeIFrame.setAttribute("onclick", "InspectorUI.onTreeClick(event)");
|
||||
this.treeIFrame.setAttribute("ondblclick", "InspectorUI.onTreeDblClick(event);");
|
||||
this.treeIFrame = this.treePanel.insertBefore(this.treeIFrame, resizerBox);
|
||||
}
|
||||
|
||||
this.treePanel.addEventListener("popupshown", function treePanelShown() {
|
||||
InspectorUI.treePanel.removeEventListener("popupshown",
|
||||
treePanelShown, false);
|
||||
|
||||
InspectorUI.treeIFrame.addEventListener("load",
|
||||
function loadedInitializeTreePanel() {
|
||||
InspectorUI.treeIFrame.removeEventListener("load",
|
||||
loadedInitializeTreePanel, true);
|
||||
InspectorUI.initializeTreePanel();
|
||||
}, true);
|
||||
|
||||
let src = InspectorUI.treeIFrame.getAttribute("src");
|
||||
if (src != "chrome://browser/content/inspector.html") {
|
||||
InspectorUI.treeIFrame.setAttribute("src",
|
||||
"chrome://browser/content/inspector.html");
|
||||
} else {
|
||||
InspectorUI.treeIFrame.contentWindow.location.reload();
|
||||
}
|
||||
|
||||
}, false);
|
||||
|
||||
const panelWidthRatio = 7 / 8;
|
||||
const panelHeightRatio = 1 / 5;
|
||||
|
||||
let width = parseInt(this.win.outerWidth * panelWidthRatio);
|
||||
let height = parseInt(this.win.outerHeight * panelHeightRatio);
|
||||
let y = Math.min(window.screen.availHeight - height, this.win.innerHeight);
|
||||
|
||||
this.treePanel.openPopup(this.browser, "overlap", 0, 0,
|
||||
false, false);
|
||||
|
||||
this.treePanel.moveTo(80, y);
|
||||
this.treePanel.sizeTo(width, height);
|
||||
},
|
||||
|
||||
createObjectBox: function IUI_createObjectBox(object, isRoot)
|
||||
{
|
||||
let tag = this.domplateUtils.getNodeTag(object);
|
||||
if (tag)
|
||||
return tag.replace({object: object}, this.treeBrowserDocument);
|
||||
},
|
||||
|
||||
getParentObject: function IUI_getParentObject(node)
|
||||
{
|
||||
let parentNode = node ? node.parentNode : null;
|
||||
|
||||
if (!parentNode) {
|
||||
// Documents have no parentNode; Attr, Document, DocumentFragment, Entity,
|
||||
// and Notation. top level windows have no parentNode
|
||||
if (node && node == Node.DOCUMENT_NODE) {
|
||||
// document type
|
||||
if (node.defaultView) {
|
||||
let embeddingFrame = node.defaultView.frameElement;
|
||||
if (embeddingFrame)
|
||||
return embeddingFrame.parentNode;
|
||||
}
|
||||
}
|
||||
// a Document object without a parentNode or window
|
||||
return null; // top level has no parent
|
||||
}
|
||||
|
||||
if (parentNode.nodeType == Node.DOCUMENT_NODE) {
|
||||
if (parentNode.defaultView) {
|
||||
return parentNode.defaultView.frameElement;
|
||||
}
|
||||
// parent is document element, but no window at defaultView.
|
||||
return null;
|
||||
}
|
||||
if (!parentNode.localName) {
|
||||
return null;
|
||||
}
|
||||
return parentNode;
|
||||
},
|
||||
|
||||
getChildObject: function IUI_getChildObject(node, index, previousSibling)
|
||||
{
|
||||
if (!node)
|
||||
return null;
|
||||
|
||||
if (node.contentDocument) {
|
||||
// then the node is a frame
|
||||
if (index == 0) {
|
||||
return node.contentDocument.documentElement; // the node's HTMLElement
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (node instanceof GetSVGDocument) {
|
||||
let svgDocument = node.getSVGDocument();
|
||||
if (svgDocument) {
|
||||
// then the node is a frame
|
||||
if (index == 0) {
|
||||
return svgDocument.documentElement; // the node's SVGElement
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
let child = null;
|
||||
if (previousSibling) // then we are walking
|
||||
child = this.getNextSibling(previousSibling);
|
||||
else
|
||||
child = this.getFirstChild(node);
|
||||
|
||||
if (this.showTextNodesWithWhitespace)
|
||||
return child;
|
||||
|
||||
for (; child; child = this.getNextSibling(child)) {
|
||||
if (!this.domplateUtils.isWhitespaceText(child))
|
||||
return child;
|
||||
}
|
||||
|
||||
return null; // we have no children worth showing.
|
||||
},
|
||||
|
||||
getFirstChild: function IUI_getFirstChild(node)
|
||||
{
|
||||
this.treeWalker = node.ownerDocument.createTreeWalker(node,
|
||||
NodeFilter.SHOW_ALL, null, false);
|
||||
return this.treeWalker.firstChild();
|
||||
},
|
||||
|
||||
getNextSibling: function IUI_getNextSibling(node)
|
||||
{
|
||||
let next = this.treeWalker.nextSibling();
|
||||
|
||||
if (!next)
|
||||
delete this.treeWalker;
|
||||
|
||||
return next;
|
||||
},
|
||||
|
||||
/**
|
||||
* Open inspector UI and HTML tree. Add listeners for document scrolling,
|
||||
* resize, tabContainer.TabSelect and others. If a node is provided, then
|
||||
|
@ -791,11 +621,12 @@ var InspectorUI = {
|
|||
openInspectorUI: function IUI_openInspectorUI(aNode)
|
||||
{
|
||||
// InspectorUI is already up and running. Lock a node if asked (via context).
|
||||
if (this.treeLoaded && this.highlighter && aNode) {
|
||||
if (this.isInspectorOpen && aNode) {
|
||||
this.inspectNode(aNode);
|
||||
this.stopInspecting();
|
||||
return;
|
||||
}
|
||||
|
||||
// Observer used to inspect the specified element from content after the
|
||||
// inspector UI has been opened.
|
||||
function inspectObserver(aElement) {
|
||||
|
@ -805,6 +636,7 @@ var InspectorUI = {
|
|||
this.inspectNode(aElement);
|
||||
this.stopInspecting();
|
||||
};
|
||||
|
||||
var boundInspectObserver = inspectObserver.bind(this, aNode);
|
||||
|
||||
if (aNode) {
|
||||
|
@ -821,17 +653,20 @@ var InspectorUI = {
|
|||
|
||||
this.initTools();
|
||||
|
||||
if (!this.domplate) {
|
||||
Cu.import("resource:///modules/domplate.jsm", this);
|
||||
this.domplateUtils.setDOM(window);
|
||||
if (!this.TreePanel && this.treePanelEnabled) {
|
||||
Cu.import("resource:///modules/TreePanel.jsm", this);
|
||||
this.treePanel = new this.TreePanel(window, this);
|
||||
}
|
||||
|
||||
this.openTreePanel();
|
||||
|
||||
this.toolbar.hidden = false;
|
||||
this.inspectCmd.setAttribute("checked", true);
|
||||
this.inspectMenuitem.setAttribute("checked", true);
|
||||
|
||||
this.isDirty = false;
|
||||
|
||||
gBrowser.addProgressListener(InspectorProgressListener);
|
||||
|
||||
// initialize the highlighter
|
||||
this.initializeHighlighter();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -885,11 +720,13 @@ var InspectorUI = {
|
|||
if (selectedNode) {
|
||||
this.inspectNode(selectedNode);
|
||||
}
|
||||
this.isDirty = InspectorStore.getValue(this.winID, "isDirty");
|
||||
} else {
|
||||
// First time inspecting, set state to no selection + live inspection.
|
||||
InspectorStore.addStore(this.winID);
|
||||
InspectorStore.setValue(this.winID, "selectedNode", null);
|
||||
InspectorStore.setValue(this.winID, "inspecting", true);
|
||||
InspectorStore.setValue(this.winID, "isDirty", this.isDirty);
|
||||
this.win.addEventListener("pagehide", this, true);
|
||||
}
|
||||
},
|
||||
|
@ -908,8 +745,8 @@ var InspectorUI = {
|
|||
{
|
||||
// if currently editing an attribute value, closing the
|
||||
// highlighter/HTML panel dismisses the editor
|
||||
if (this.editingContext)
|
||||
this.closeEditor();
|
||||
if (this.treePanel && this.treePanel.editingContext)
|
||||
this.treePanel.closeEditor();
|
||||
|
||||
if (this.closing || !this.win || !this.browser) {
|
||||
return;
|
||||
|
@ -930,6 +767,7 @@ var InspectorUI = {
|
|||
this.selection);
|
||||
}
|
||||
InspectorStore.setValue(this.winID, "inspecting", this.inspecting);
|
||||
InspectorStore.setValue(this.winID, "isDirty", this.isDirty);
|
||||
}
|
||||
|
||||
if (InspectorStore.isEmpty()) {
|
||||
|
@ -948,44 +786,18 @@ var InspectorUI = {
|
|||
this.highlighter = null;
|
||||
}
|
||||
|
||||
if (this.treePanelDiv) {
|
||||
this.treePanelDiv.ownerPanel = null;
|
||||
let parent = this.treePanelDiv.parentNode;
|
||||
parent.removeChild(this.treePanelDiv);
|
||||
delete this.treePanelDiv;
|
||||
delete this.treeBrowserDocument;
|
||||
}
|
||||
|
||||
if (this.treeIFrame) {
|
||||
let parent = this.treeIFrame.parentNode;
|
||||
parent.removeChild(this.treeIFrame);
|
||||
delete this.treeIFrame;
|
||||
}
|
||||
delete this.ioBox;
|
||||
|
||||
if (this.domplate) {
|
||||
this.domplateUtils.setDOM(null);
|
||||
delete this.domplate;
|
||||
delete this.HTMLTemplates;
|
||||
delete this.domplateUtils;
|
||||
}
|
||||
|
||||
this.inspectCmd.setAttribute("checked", false);
|
||||
this.inspectMenuitem.setAttribute("checked", false);
|
||||
this.browser = this.win = null; // null out references to browser and window
|
||||
this.winID = null;
|
||||
this.selection = null;
|
||||
this.treeLoaded = false;
|
||||
this.closing = false;
|
||||
this.isDirty = false;
|
||||
|
||||
this.treePanel.addEventListener("popuphidden", function treePanelHidden() {
|
||||
this.removeEventListener("popuphidden", treePanelHidden, false);
|
||||
|
||||
InspectorUI.closing = false;
|
||||
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.CLOSED, null);
|
||||
}, false);
|
||||
|
||||
this.treePanel.hidePopup();
|
||||
delete this.treePanel;
|
||||
delete this.stylePanel;
|
||||
delete this.toolbar;
|
||||
delete this.TreePanel;
|
||||
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.CLOSED, null);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -996,10 +808,10 @@ var InspectorUI = {
|
|||
{
|
||||
// if currently editing an attribute value, starting
|
||||
// "live inspection" mode closes the editor
|
||||
if (this.editingContext)
|
||||
this.closeEditor();
|
||||
if (this.treePanel && this.treePanel.editingContext)
|
||||
this.treePanel.closeEditor();
|
||||
|
||||
document.getElementById("inspector-inspect-toolbutton").checked = true;
|
||||
this.inspectToolbutton.checked = true;
|
||||
this.attachPageListeners();
|
||||
this.inspecting = true;
|
||||
this.toolsDim(true);
|
||||
|
@ -1018,7 +830,7 @@ var InspectorUI = {
|
|||
return;
|
||||
}
|
||||
|
||||
document.getElementById("inspector-inspect-toolbutton").checked = false;
|
||||
this.inspectToolbutton.checked = false;
|
||||
this.detachPageListeners();
|
||||
this.inspecting = false;
|
||||
this.toolsDim(false);
|
||||
|
@ -1036,15 +848,15 @@ var InspectorUI = {
|
|||
* node to inspect
|
||||
* @param forceUpdate
|
||||
* force an update?
|
||||
* @param aScroll
|
||||
* force scroll?
|
||||
* @param aScroll boolean
|
||||
* scroll the tree panel?
|
||||
*/
|
||||
select: function IUI_select(aNode, forceUpdate, aScroll)
|
||||
{
|
||||
// if currently editing an attribute value, using the
|
||||
// highlighter dismisses the editor
|
||||
if (this.editingContext)
|
||||
this.closeEditor();
|
||||
if (this.treePanel && this.treePanel.editingContext)
|
||||
this.treePanel.closeEditor();
|
||||
|
||||
if (!aNode)
|
||||
aNode = this.defaultSelection;
|
||||
|
@ -1054,10 +866,9 @@ var InspectorUI = {
|
|||
if (!this.inspecting) {
|
||||
this.highlighter.highlightNode(this.selection);
|
||||
}
|
||||
this.ioBox.select(this.selection, true, true, aScroll);
|
||||
}
|
||||
|
||||
this.toolsSelect();
|
||||
this.toolsSelect(aScroll);
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1093,7 +904,7 @@ var InspectorUI = {
|
|||
switch (event.type) {
|
||||
case "TabSelect":
|
||||
winID = this.getWindowID(gBrowser.selectedBrowser.contentWindow);
|
||||
if (this.isTreePanelOpen && winID != this.winID) {
|
||||
if (this.isInspectorOpen && winID != this.winID) {
|
||||
this.closeInspectorUI(true);
|
||||
inspectorClosed = true;
|
||||
}
|
||||
|
@ -1148,265 +959,6 @@ var InspectorUI = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle click events in the html tree panel.
|
||||
* @param aEvent
|
||||
* The mouse event.
|
||||
*/
|
||||
onTreeClick: function IUI_onTreeClick(aEvent)
|
||||
{
|
||||
// if currently editing an attribute value, clicking outside
|
||||
// the editor dismisses the editor
|
||||
if (this.editingContext) {
|
||||
this.closeEditor();
|
||||
|
||||
// clicking outside the editor ONLY closes the editor
|
||||
// so, cancel the rest of the processing of this event
|
||||
aEvent.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
let node;
|
||||
let target = aEvent.target;
|
||||
let hitTwisty = false;
|
||||
if (this.hasClass(target, "twisty")) {
|
||||
node = this.getRepObject(aEvent.target.nextSibling);
|
||||
hitTwisty = true;
|
||||
} else {
|
||||
node = this.getRepObject(aEvent.target);
|
||||
}
|
||||
|
||||
if (node) {
|
||||
if (hitTwisty) {
|
||||
this.ioBox.toggleObject(node);
|
||||
} else {
|
||||
if (this.inspecting) {
|
||||
this.toolsSelect();
|
||||
this.stopInspecting(true);
|
||||
} else {
|
||||
this.select(node, true, false);
|
||||
this.highlighter.highlightNode(node);
|
||||
this.toolsSelect();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle double-click events in the html tree panel.
|
||||
* (double-clicking an attribute value allows it to be edited)
|
||||
* @param aEvent
|
||||
* The mouse event.
|
||||
*/
|
||||
onTreeDblClick: function IUI_onTreeDblClick(aEvent)
|
||||
{
|
||||
// if already editing an attribute value, double-clicking elsewhere
|
||||
// in the tree is the same as a click, which dismisses the editor
|
||||
if (this.editingContext)
|
||||
this.closeEditor();
|
||||
|
||||
let target = aEvent.target;
|
||||
if (this.hasClass(target, "nodeValue")) {
|
||||
let repObj = this.getRepObject(target);
|
||||
let attrName = target.getAttribute("data-attributeName");
|
||||
let attrVal = target.innerHTML;
|
||||
|
||||
this.editAttributeValue(target, repObj, attrName, attrVal);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts the editor for an attribute value.
|
||||
* @param aAttrObj
|
||||
* The DOM object representing the attribute value in the HTML Tree
|
||||
* @param aRepObj
|
||||
* The original DOM (target) object being inspected/edited
|
||||
* @param aAttrName
|
||||
* The name of the attribute being edited
|
||||
* @param aAttrVal
|
||||
* The current value of the attribute being edited
|
||||
*/
|
||||
editAttributeValue:
|
||||
function IUI_editAttributeValue(aAttrObj, aRepObj, aAttrName, aAttrVal)
|
||||
{
|
||||
let editor = this.treeBrowserDocument.getElementById("attribute-editor");
|
||||
let editorInput =
|
||||
this.treeBrowserDocument.getElementById("attribute-editor-input");
|
||||
let attrDims = aAttrObj.getBoundingClientRect();
|
||||
// figure out actual viewable viewport dimensions (sans scrollbars)
|
||||
let viewportWidth = this.treeBrowserDocument.documentElement.clientWidth;
|
||||
let viewportHeight = this.treeBrowserDocument.documentElement.clientHeight;
|
||||
|
||||
// saves the editing context for use when the editor is saved/closed
|
||||
this.editingContext = {
|
||||
attrObj: aAttrObj,
|
||||
repObj: aRepObj,
|
||||
attrName: aAttrName
|
||||
};
|
||||
|
||||
// highlight attribute-value node in tree while editing
|
||||
this.addClass(aAttrObj, "editingAttributeValue");
|
||||
|
||||
// show the editor
|
||||
this.addClass(editor, "editing");
|
||||
|
||||
// offset the editor below the attribute-value node being edited
|
||||
let editorVeritcalOffset = 2;
|
||||
|
||||
// keep the editor comfortably within the bounds of the viewport
|
||||
let editorViewportBoundary = 5;
|
||||
|
||||
// outer editor is sized based on the <input> box inside it
|
||||
editorInput.style.width = Math.min(attrDims.width, viewportWidth -
|
||||
editorViewportBoundary) + "px";
|
||||
editorInput.style.height = Math.min(attrDims.height, viewportHeight -
|
||||
editorViewportBoundary) + "px";
|
||||
let editorDims = editor.getBoundingClientRect();
|
||||
|
||||
// calculate position for the editor according to the attribute node
|
||||
let editorLeft = attrDims.left + this.treeIFrame.contentWindow.scrollX -
|
||||
// center the editor against the attribute value
|
||||
((editorDims.width - attrDims.width) / 2);
|
||||
let editorTop = attrDims.top + this.treeIFrame.contentWindow.scrollY +
|
||||
attrDims.height + editorVeritcalOffset;
|
||||
|
||||
// but, make sure the editor stays within the visible viewport
|
||||
editorLeft = Math.max(0, Math.min(
|
||||
(this.treeIFrame.contentWindow.scrollX +
|
||||
viewportWidth - editorDims.width),
|
||||
editorLeft)
|
||||
);
|
||||
editorTop = Math.max(0, Math.min(
|
||||
(this.treeIFrame.contentWindow.scrollY +
|
||||
viewportHeight - editorDims.height),
|
||||
editorTop)
|
||||
);
|
||||
|
||||
// position the editor
|
||||
editor.style.left = editorLeft + "px";
|
||||
editor.style.top = editorTop + "px";
|
||||
|
||||
// set and select the text
|
||||
editorInput.value = aAttrVal;
|
||||
editorInput.select();
|
||||
|
||||
// listen for editor specific events
|
||||
this.bindEditorEvent(editor, "click", function(aEvent) {
|
||||
aEvent.stopPropagation();
|
||||
});
|
||||
this.bindEditorEvent(editor, "dblclick", function(aEvent) {
|
||||
aEvent.stopPropagation();
|
||||
});
|
||||
this.bindEditorEvent(editor, "keypress",
|
||||
this.handleEditorKeypress.bind(this));
|
||||
|
||||
// event notification
|
||||
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.EDITOR_OPENED,
|
||||
null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle binding an event handler for the editor.
|
||||
* (saves the callback for easier unbinding later)
|
||||
* @param aEditor
|
||||
* The DOM object for the editor
|
||||
* @param aEventName
|
||||
* The name of the event to listen for
|
||||
* @param aEventCallback
|
||||
* The callback to bind to the event (and also to save for later
|
||||
* unbinding)
|
||||
*/
|
||||
bindEditorEvent:
|
||||
function IUI_bindEditorEvent(aEditor, aEventName, aEventCallback)
|
||||
{
|
||||
this.editingEvents[aEventName] = aEventCallback;
|
||||
aEditor.addEventListener(aEventName, aEventCallback, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle unbinding an event handler from the editor.
|
||||
* (unbinds the previously bound and saved callback)
|
||||
* @param aEditor
|
||||
* The DOM object for the editor
|
||||
* @param aEventName
|
||||
* The name of the event being listened for
|
||||
*/
|
||||
unbindEditorEvent: function IUI_unbindEditorEvent(aEditor, aEventName)
|
||||
{
|
||||
aEditor.removeEventListener(aEventName, this.editingEvents[aEventName],
|
||||
false);
|
||||
this.editingEvents[aEventName] = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle keypress events in the editor.
|
||||
* @param aEvent
|
||||
* The keyboard event.
|
||||
*/
|
||||
handleEditorKeypress: function IUI_handleEditorKeypress(aEvent)
|
||||
{
|
||||
if (aEvent.which == KeyEvent.DOM_VK_RETURN) {
|
||||
this.saveEditor();
|
||||
} else if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE) {
|
||||
this.closeEditor();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Close the editor and cleanup.
|
||||
*/
|
||||
closeEditor: function IUI_closeEditor()
|
||||
{
|
||||
let editor = this.treeBrowserDocument.getElementById("attribute-editor");
|
||||
let editorInput =
|
||||
this.treeBrowserDocument.getElementById("attribute-editor-input");
|
||||
|
||||
// remove highlight from attribute-value node in tree
|
||||
this.removeClass(this.editingContext.attrObj, "editingAttributeValue");
|
||||
|
||||
// hide editor
|
||||
this.removeClass(editor, "editing");
|
||||
|
||||
// stop listening for editor specific events
|
||||
this.unbindEditorEvent(editor, "click");
|
||||
this.unbindEditorEvent(editor, "dblclick");
|
||||
this.unbindEditorEvent(editor, "keypress");
|
||||
|
||||
// clean up after the editor
|
||||
editorInput.value = "";
|
||||
editorInput.blur();
|
||||
this.editingContext = null;
|
||||
this.editingEvents = {};
|
||||
|
||||
// event notification
|
||||
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED,
|
||||
null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Commit the edits made in the editor, then close it.
|
||||
*/
|
||||
saveEditor: function IUI_saveEditor()
|
||||
{
|
||||
let editorInput =
|
||||
this.treeBrowserDocument.getElementById("attribute-editor-input");
|
||||
|
||||
// set the new attribute value on the original target DOM element
|
||||
this.editingContext.repObj.setAttribute(this.editingContext.attrName,
|
||||
editorInput.value);
|
||||
|
||||
// update the HTML tree attribute value
|
||||
this.editingContext.attrObj.innerHTML = editorInput.value;
|
||||
|
||||
this.isDirty = true;
|
||||
|
||||
// event notification
|
||||
Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.EDITOR_SAVED,
|
||||
null);
|
||||
|
||||
this.closeEditor();
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach event listeners to content window and child windows to enable
|
||||
* highlighting and click to stop inspection.
|
||||
|
@ -1511,47 +1063,6 @@ var InspectorUI = {
|
|||
return [borderTop + paddingTop, borderLeft + paddingLeft];
|
||||
},
|
||||
|
||||
/**
|
||||
* Does the given object have a class attribute?
|
||||
* @param aNode
|
||||
* the DOM node.
|
||||
* @param aClass
|
||||
* The class string.
|
||||
* @returns boolean
|
||||
*/
|
||||
hasClass: function IUI_hasClass(aNode, aClass)
|
||||
{
|
||||
if (!(aNode instanceof Element))
|
||||
return false;
|
||||
return aNode.classList.contains(aClass);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add the class name to the given object.
|
||||
* @param aNode
|
||||
* the DOM node.
|
||||
* @param aClass
|
||||
* The class string.
|
||||
*/
|
||||
addClass: function IUI_addClass(aNode, aClass)
|
||||
{
|
||||
if (aNode instanceof Element)
|
||||
aNode.classList.add(aClass);
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the class name from the given object
|
||||
* @param aNode
|
||||
* the DOM node.
|
||||
* @param aClass
|
||||
* The class string.
|
||||
*/
|
||||
removeClass: function IUI_removeClass(aNode, aClass)
|
||||
{
|
||||
if (aNode instanceof Element)
|
||||
aNode.classList.remove(aClass);
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the unique ID of a window object.
|
||||
*
|
||||
|
@ -1574,32 +1085,6 @@ var InspectorUI = {
|
|||
return util.currentInnerWindowID;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the "repObject" from the HTML panel's domplate-constructed DOM node.
|
||||
* In this system, a "repObject" is the Object being Represented by the box
|
||||
* object. It is the "real" object that we're building our facade around.
|
||||
*
|
||||
* @param element
|
||||
* The element in the HTML panel the user clicked.
|
||||
* @returns either a real node or null
|
||||
*/
|
||||
getRepObject: function IUI_getRepObject(element)
|
||||
{
|
||||
let target = null;
|
||||
for (let child = element; child; child = child.parentNode) {
|
||||
if (this.hasClass(child, "repTarget"))
|
||||
target = child;
|
||||
|
||||
if (child.repObject) {
|
||||
if (!target && this.hasClass(child.repObject, "repIgnore"))
|
||||
break;
|
||||
else
|
||||
return child.repObject;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
* text message to send to the log
|
||||
|
@ -1808,12 +1293,14 @@ var InspectorUI = {
|
|||
/**
|
||||
* For each tool in the tools collection select the current node that is
|
||||
* selected in the highlighter
|
||||
* @param aScroll boolean
|
||||
* Do you want to scroll the treepanel?
|
||||
*/
|
||||
toolsSelect: function IUI_toolsSelect()
|
||||
toolsSelect: function IUI_toolsSelect(aScroll)
|
||||
{
|
||||
this.toolsDo(function IUI_toolsOnSelect(aTool) {
|
||||
if (aTool.isOpen) {
|
||||
aTool.onSelect.call(aTool.context, InspectorUI.selection);
|
||||
aTool.onSelect.call(aTool.context, InspectorUI.selection, aScroll);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -1991,7 +1478,7 @@ var InspectorProgressListener = {
|
|||
function IPL_onStateChange(aProgress, aRequest, aFlag, aStatus)
|
||||
{
|
||||
// Remove myself if the Inspector is no longer open.
|
||||
if (!InspectorUI.isTreePanelOpen) {
|
||||
if (!InspectorUI.isInspectorOpen) {
|
||||
gBrowser.removeProgressListener(InspectorProgressListener);
|
||||
return;
|
||||
}
|
||||
|
@ -2089,10 +1576,14 @@ var InspectorProgressListener = {
|
|||
/////////////////////////////////////////////////////////////////////////
|
||||
//// Initializers
|
||||
|
||||
XPCOMUtils.defineLazyGetter(InspectorUI, "inspectCmd", function () {
|
||||
XPCOMUtils.defineLazyGetter(InspectorUI, "inspectMenuitem", function () {
|
||||
return document.getElementById("Tools:Inspect");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(InspectorUI, "inspectToolbutton", function () {
|
||||
return document.getElementById("inspector-inspect-toolbutton");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(InspectorUI, "strings", function () {
|
||||
return Services.strings.
|
||||
createBundle("chrome://browser/locale/inspector.properties");
|
||||
|
|
|
@ -61,5 +61,7 @@ _BROWSER_FILES = \
|
|||
browser_inspector_bug_566084_location_changed.js \
|
||||
$(NULL)
|
||||
|
||||
# browser_inspector_treePanel_click.js \
|
||||
|
||||
libs:: $(_BROWSER_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
|
||||
|
|
|
@ -17,7 +17,7 @@ function runInspectorTests() {
|
|||
is(para.textContent, "init", "paragraph content is correct");
|
||||
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting");
|
||||
ok(InspectorUI.isTreePanelOpen, "Inspector Panel is open");
|
||||
ok(InspectorUI.isInspectorOpen, "Inspector is open");
|
||||
|
||||
InspectorUI.isDirty = true;
|
||||
|
||||
|
@ -56,7 +56,7 @@ function onPageLoad() {
|
|||
is(para.textContent, "test2", "paragraph content is correct");
|
||||
|
||||
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
|
||||
ok(!InspectorUI.isTreePanelOpen, "Inspector Panel is not open");
|
||||
ok(!InspectorUI.isInspectorOpen, "Inspector Panel is not open");
|
||||
|
||||
testEnd();
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ function locationTest2() {
|
|||
is(para.textContent, "init", "paragraph content is correct");
|
||||
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting");
|
||||
ok(InspectorUI.isTreePanelOpen, "Inspector Panel is open");
|
||||
ok(InspectorUI.isInspectorOpen, "Inspector Panel is open");
|
||||
|
||||
notificationBox.addEventListener("AlertActive", alertActive2, false);
|
||||
|
||||
|
@ -102,7 +102,6 @@ function alertActive2() {
|
|||
|
||||
function testEnd() {
|
||||
notificationBox = null;
|
||||
InspectorUI.isDirty = false;
|
||||
gBrowser.removeCurrentTab();
|
||||
executeSoon(finish);
|
||||
}
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*
|
||||
*
|
||||
* Contributor(s):
|
||||
* Rob Campbell <rcampbell@mozilla.com>
|
||||
* Mihai Sucan <mihai.sucan@gmail.com>
|
||||
* Kyle Simpson <ksimpson@mozilla.com>
|
||||
* Kyle Simpson <ksimpson@mozilla.com>
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
|
@ -25,19 +25,26 @@ function setupEditorTests()
|
|||
div.setAttribute("id", "foobar");
|
||||
div.setAttribute("class", "barbaz");
|
||||
doc.body.appendChild(div);
|
||||
|
||||
Services.obs.addObserver(runEditorTests, INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
|
||||
Services.obs.addObserver(setupHTMLPanel, INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
InspectorUI.toggleInspectorUI();
|
||||
}
|
||||
|
||||
function setupHTMLPanel()
|
||||
{
|
||||
Services.obs.removeObserver(setupHTMLPanel, INSPECTOR_NOTIFICATIONS.OPENED);
|
||||
Services.obs.addObserver(runEditorTests, INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
|
||||
InspectorUI.treePanel.open();
|
||||
}
|
||||
|
||||
function runEditorTests()
|
||||
{
|
||||
Services.obs.removeObserver(runEditorTests, INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
Services.obs.removeObserver(runEditorTests, INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
|
||||
InspectorUI.stopInspecting();
|
||||
|
||||
|
||||
// setup generator for async test steps
|
||||
editorTestSteps = doEditorTestSteps();
|
||||
|
||||
|
||||
// add step listeners
|
||||
Services.obs.addObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_OPENED, false);
|
||||
Services.obs.addObserver(doNextStep, INSPECTOR_NOTIFICATIONS.EDITOR_CLOSED, false);
|
||||
|
@ -49,16 +56,17 @@ function runEditorTests()
|
|||
|
||||
function doEditorTestSteps()
|
||||
{
|
||||
let editor = InspectorUI.treeBrowserDocument.getElementById("attribute-editor");
|
||||
let editorInput = InspectorUI.treeBrowserDocument.getElementById("attribute-editor-input");
|
||||
let treePanel = InspectorUI.treePanel;
|
||||
let editor = treePanel.treeBrowserDocument.getElementById("attribute-editor");
|
||||
let editorInput = treePanel.treeBrowserDocument.getElementById("attribute-editor-input");
|
||||
|
||||
// Step 1: grab and test the attribute-value nodes in the HTML panel, then open editor
|
||||
let attrValNode_id = InspectorUI.treeBrowserDocument.querySelectorAll(".nodeValue.editable[data-attributeName='id']")[0];
|
||||
let attrValNode_class = InspectorUI.treeBrowserDocument.querySelectorAll(".nodeValue.editable[data-attributeName='class']")[0];
|
||||
let attrValNode_id = treePanel.treeBrowserDocument.querySelectorAll(".nodeValue.editable[data-attributeName='id']")[0];
|
||||
let attrValNode_class = treePanel.treeBrowserDocument.querySelectorAll(".nodeValue.editable[data-attributeName='class']")[0];
|
||||
|
||||
is(attrValNode_id.innerHTML, "foobar", "Step 1: we have the correct `id` attribute-value node in the HTML panel");
|
||||
is(attrValNode_class.innerHTML, "barbaz", "we have the correct `class` attribute-value node in the HTML panel");
|
||||
|
||||
|
||||
// double-click the `id` attribute-value node to open the editor
|
||||
executeSoon(function() {
|
||||
// firing 2 clicks right in a row to simulate a double-click
|
||||
|
@ -69,7 +77,7 @@ function doEditorTestSteps()
|
|||
|
||||
|
||||
// Step 2: validate editing session, enter new attribute value into editor, and save input
|
||||
ok(InspectorUI.editingContext, "Step 2: editor session started");
|
||||
ok(InspectorUI.treePanel.editingContext, "Step 2: editor session started");
|
||||
|
||||
let editorVisible = editor.classList.contains("editing");
|
||||
ok(editorVisible, "editor popup visible");
|
||||
|
@ -88,13 +96,13 @@ function doEditorTestSteps()
|
|||
let attrValNodeHighlighted = attrValNode_id.classList.contains("editingAttributeValue");
|
||||
ok(attrValNodeHighlighted, "`id` attribute-value node is editor-highlighted");
|
||||
|
||||
is(InspectorUI.editingContext.repObj, div, "editor session has correct reference to div");
|
||||
is(InspectorUI.editingContext.attrObj, attrValNode_id, "editor session has correct reference to `id` attribute-value node in HTML panel");
|
||||
is(InspectorUI.editingContext.attrName, "id", "editor session knows correct attribute-name");
|
||||
is(treePanel.editingContext.repObj, div, "editor session has correct reference to div");
|
||||
is(treePanel.editingContext.attrObj, attrValNode_id, "editor session has correct reference to `id` attribute-value node in HTML panel");
|
||||
is(treePanel.editingContext.attrName, "id", "editor session knows correct attribute-name");
|
||||
|
||||
editorInput.value = "Hello World";
|
||||
editorInput.focus();
|
||||
|
||||
|
||||
// hit <enter> to save the inputted value
|
||||
executeSoon(function() {
|
||||
EventUtils.synthesizeKey("VK_RETURN", {}, attrValNode_id.ownerDocument.defaultView);
|
||||
|
@ -106,7 +114,7 @@ function doEditorTestSteps()
|
|||
|
||||
|
||||
// Step 3: validate that the previous editing session saved correctly, then open editor on `class` attribute value
|
||||
ok(!InspectorUI.editingContext, "Step 3: editor session ended");
|
||||
ok(!treePanel.editingContext, "Step 3: editor session ended");
|
||||
editorVisible = editor.classList.contains("editing");
|
||||
ok(!editorVisible, "editor popup hidden");
|
||||
attrValNodeHighlighted = attrValNode_id.classList.contains("editingAttributeValue");
|
||||
|
@ -124,16 +132,16 @@ function doEditorTestSteps()
|
|||
|
||||
|
||||
// Step 4: enter value into editor, then hit <escape> to discard it
|
||||
ok(InspectorUI.editingContext, "Step 4: editor session started");
|
||||
ok(treePanel.editingContext, "Step 4: editor session started");
|
||||
editorVisible = editor.classList.contains("editing");
|
||||
ok(editorVisible, "editor popup visible");
|
||||
|
||||
is(InspectorUI.editingContext.attrObj, attrValNode_class, "editor session has correct reference to `class` attribute-value node in HTML panel");
|
||||
is(InspectorUI.editingContext.attrName, "class", "editor session knows correct attribute-name");
|
||||
|
||||
is(treePanel.editingContext.attrObj, attrValNode_class, "editor session has correct reference to `class` attribute-value node in HTML panel");
|
||||
is(treePanel.editingContext.attrName, "class", "editor session knows correct attribute-name");
|
||||
|
||||
editorInput.value = "Hello World";
|
||||
editorInput.focus();
|
||||
|
||||
|
||||
// hit <escape> to discard the inputted value
|
||||
executeSoon(function() {
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", {}, attrValNode_class.ownerDocument.defaultView);
|
||||
|
@ -143,7 +151,7 @@ function doEditorTestSteps()
|
|||
|
||||
|
||||
// Step 5: validate that the previous editing session discarded correctly, then open editor on `id` attribute value again
|
||||
ok(!InspectorUI.editingContext, "Step 5: editor session ended");
|
||||
ok(!treePanel.editingContext, "Step 5: editor session ended");
|
||||
editorVisible = editor.classList.contains("editing");
|
||||
ok(!editorVisible, "editor popup hidden");
|
||||
is(div.getAttribute("class"), "barbaz", "`class` attribute-value *not* updated");
|
||||
|
@ -159,15 +167,15 @@ function doEditorTestSteps()
|
|||
|
||||
|
||||
// Step 6: validate that editor opened again, then test double-click inside of editor (should do nothing)
|
||||
ok(InspectorUI.editingContext, "Step 6: editor session started");
|
||||
ok(treePanel.editingContext, "Step 6: editor session started");
|
||||
editorVisible = editor.classList.contains("editing");
|
||||
ok(editorVisible, "editor popup visible");
|
||||
|
||||
|
||||
// double-click on the editor input box
|
||||
executeSoon(function() {
|
||||
// firing 2 clicks right in a row to simulate a double-click
|
||||
EventUtils.synthesizeMouse(editorInput, 2, 2, {clickCount: 2}, editorInput.ownerDocument.defaultView);
|
||||
|
||||
|
||||
// since the previous double-click is supposed to do nothing,
|
||||
// wait a brief moment, then move on to the next step
|
||||
executeSoon(function() {
|
||||
|
@ -178,12 +186,12 @@ function doEditorTestSteps()
|
|||
yield; // End of Step 6
|
||||
|
||||
|
||||
// Step 7: validate that editing session is still correct, then enter a value and try a click
|
||||
// Step 7: validate that editing session is still correct, then enter a value and try a click
|
||||
// outside of editor (should cancel the editing session)
|
||||
ok(InspectorUI.editingContext, "Step 7: editor session still going");
|
||||
ok(treePanel.editingContext, "Step 7: editor session still going");
|
||||
editorVisible = editor.classList.contains("editing");
|
||||
ok(editorVisible, "editor popup still visible");
|
||||
|
||||
|
||||
editorInput.value = "all your base are belong to us";
|
||||
|
||||
// single-click the `class` attribute-value node
|
||||
|
@ -195,12 +203,12 @@ function doEditorTestSteps()
|
|||
|
||||
|
||||
// Step 8: validate that the editor was closed and that the editing was not saved
|
||||
ok(!InspectorUI.editingContext, "Step 8: editor session ended");
|
||||
ok(!treePanel.editingContext, "Step 8: editor session ended");
|
||||
editorVisible = editor.classList.contains("editing");
|
||||
ok(!editorVisible, "editor popup hidden");
|
||||
is(div.getAttribute("id"), "Hello World", "`id` attribute-value *not* updated");
|
||||
is(attrValNode_id.innerHTML, "Hello World", "attribute-value node in HTML panel *not* updated");
|
||||
|
||||
|
||||
// End of Step 8
|
||||
|
||||
// end of all steps, so clean up
|
||||
|
|
|
@ -43,7 +43,6 @@ let div1;
|
|||
let div2;
|
||||
let iframe1;
|
||||
let iframe2;
|
||||
let highlighterFrame;
|
||||
|
||||
function createDocument()
|
||||
{
|
||||
|
@ -99,7 +98,6 @@ function runIframeTests()
|
|||
Services.obs.addObserver(performTestComparisons1,
|
||||
INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
|
||||
|
||||
highlighterFrame = InspectorUI.highlighter.iframe;
|
||||
executeSoon(moveMouseOver.bind(this, div1));
|
||||
}
|
||||
|
||||
|
|
|
@ -68,16 +68,27 @@ function startInspectorTests()
|
|||
function runInspectorTests()
|
||||
{
|
||||
Services.obs.removeObserver(runInspectorTests,
|
||||
INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
INSPECTOR_NOTIFICATIONS.OPENED);
|
||||
Services.obs.addObserver(treePanelTests,
|
||||
INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
|
||||
|
||||
ok(InspectorUI.toolbar, "we have the toolbar.");
|
||||
ok(!InspectorUI.toolbar.hidden, "toolbar is visible");
|
||||
ok(InspectorUI.inspecting, "Inspector is inspecting");
|
||||
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
|
||||
ok(InspectorUI.highlighter, "Highlighter is up");
|
||||
|
||||
InspectorUI.treePanel.open();
|
||||
}
|
||||
|
||||
function treePanelTests()
|
||||
{
|
||||
Services.obs.removeObserver(treePanelTests,
|
||||
INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
|
||||
Services.obs.addObserver(runContextMenuTest,
|
||||
INSPECTOR_NOTIFICATIONS.CLOSED, false);
|
||||
|
||||
ok(!InspectorUI.toolbar.hidden, "toolbar is visible");
|
||||
let iframe = document.getElementById("inspector-tree-iframe");
|
||||
is(InspectorUI.treeIFrame, iframe, "Inspector IFrame matches");
|
||||
ok(InspectorUI.inspecting, "Inspector is inspecting");
|
||||
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
|
||||
ok(InspectorUI.highlighter, "Highlighter is up");
|
||||
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
|
||||
|
||||
executeSoon(function() {
|
||||
InspectorUI.closeInspectorUI();
|
||||
|
@ -110,7 +121,7 @@ function inspectNodesFromContextTest()
|
|||
Services.obs.addObserver(openInspectorForContextTest, INSPECTOR_NOTIFICATIONS.CLOSED, false);
|
||||
ok(!InspectorUI.inspecting, "Inspector is not actively highlighting");
|
||||
is(InspectorUI.selection, salutation, "Inspector is highlighting salutation");
|
||||
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
|
||||
ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is closed");
|
||||
// TODO: These tests depend on the style inspector patches.
|
||||
todo(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open");
|
||||
executeSoon(function() {
|
||||
|
@ -162,9 +173,9 @@ function finishInspectorTests()
|
|||
INSPECTOR_NOTIFICATIONS.CLOSED);
|
||||
|
||||
ok(!InspectorUI.highlighter, "Highlighter is gone");
|
||||
ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is closed");
|
||||
ok(!InspectorUI.treePanel, "Inspector Tree Panel is closed");
|
||||
ok(!InspectorUI.inspecting, "Inspector is not inspecting");
|
||||
ok(InspectorUI.toolbar.hidden, "toolbar is hidden");
|
||||
ok(!InspectorUI.toolbar, "toolbar is hidden");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
|
|
|
@ -61,7 +61,7 @@ function inspectorUIOpen1()
|
|||
|
||||
// Make sure the inspector is open.
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting");
|
||||
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
|
||||
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
|
||||
ok(!InspectorStore.isEmpty(), "InspectorStore is not empty");
|
||||
is(InspectorStore.length, 1, "InspectorStore.length = 1");
|
||||
|
||||
|
@ -87,7 +87,7 @@ function inspectorTabOpen2()
|
|||
{
|
||||
// Make sure the inspector is closed.
|
||||
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
|
||||
ok(!InspectorUI.isPanelOpen, "Inspector Tree Panel is closed");
|
||||
ok(!InspectorUI.treePanel, "Inspector Tree Panel is closed");
|
||||
is(InspectorStore.length, 1, "InspectorStore.length = 1");
|
||||
|
||||
// Activate the inspector again.
|
||||
|
@ -105,7 +105,7 @@ function inspectorUIOpen2()
|
|||
|
||||
// Make sure the inspector is open.
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting");
|
||||
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
|
||||
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
|
||||
is(InspectorStore.length, 2, "InspectorStore.length = 2");
|
||||
|
||||
// Disable highlighting.
|
||||
|
@ -127,7 +127,23 @@ function inspectorFocusTab1()
|
|||
|
||||
// Make sure the inspector is still open.
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting");
|
||||
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
|
||||
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
|
||||
is(InspectorStore.length, 2, "InspectorStore.length = 2");
|
||||
is(InspectorUI.selection, div, "selection matches the div element");
|
||||
|
||||
Services.obs.addObserver(inspectorOpenTreePanelTab1,
|
||||
INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
|
||||
|
||||
InspectorUI.treePanel.open();
|
||||
}
|
||||
|
||||
function inspectorOpenTreePanelTab1()
|
||||
{
|
||||
Services.obs.removeObserver(inspectorOpenTreePanelTab1,
|
||||
INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
|
||||
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting");
|
||||
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
|
||||
is(InspectorStore.length, 2, "InspectorStore.length = 2");
|
||||
is(InspectorUI.selection, div, "selection matches the div element");
|
||||
|
||||
|
@ -144,7 +160,40 @@ function inspectorFocusTab2()
|
|||
|
||||
// Make sure the inspector is still open.
|
||||
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
|
||||
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
|
||||
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
|
||||
is(InspectorStore.length, 2, "InspectorStore.length = 2");
|
||||
isnot(InspectorUI.selection, div, "selection does not match the div element");
|
||||
|
||||
// Switch back to tab 1.
|
||||
Services.obs.addObserver(inspectorSecondFocusTab1,
|
||||
INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
|
||||
gBrowser.selectedTab = tab1;
|
||||
}
|
||||
|
||||
function inspectorSecondFocusTab1()
|
||||
{
|
||||
Services.obs.removeObserver(inspectorSecondFocusTab1,
|
||||
INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
|
||||
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting");
|
||||
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
|
||||
is(InspectorStore.length, 2, "InspectorStore.length = 2");
|
||||
is(InspectorUI.selection, div, "selection matches the div element");
|
||||
|
||||
// Switch back to tab 2.
|
||||
Services.obs.addObserver(inspectorSecondFocusTab2,
|
||||
INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
gBrowser.selectedTab = tab2;
|
||||
}
|
||||
|
||||
function inspectorSecondFocusTab2()
|
||||
{
|
||||
Services.obs.removeObserver(inspectorSecondFocusTab2,
|
||||
INSPECTOR_NOTIFICATIONS.OPENED);
|
||||
|
||||
// Make sure the inspector is still open.
|
||||
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
|
||||
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
|
||||
is(InspectorStore.length, 2, "InspectorStore.length = 2");
|
||||
isnot(InspectorUI.selection, div, "selection does not match the div element");
|
||||
|
||||
|
@ -161,7 +210,7 @@ function inspectorTabUnload1(evt)
|
|||
|
||||
// Make sure the Inspector is still open and that the state is correct.
|
||||
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
|
||||
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
|
||||
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
|
||||
is(InspectorStore.length, 1, "InspectorStore.length = 1");
|
||||
|
||||
InspectorUI.closeInspectorUI();
|
||||
|
|
|
@ -17,7 +17,7 @@ function test() {
|
|||
waitForFocus(setupTest, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,<div><p></p></div>";
|
||||
content.location = 'data:text/html,<div style="width: 200px; height: 200px"><p></p></div>';
|
||||
|
||||
function setupTest() {
|
||||
node1 = doc.querySelector("div");
|
||||
|
@ -28,28 +28,32 @@ function test() {
|
|||
|
||||
function runTests() {
|
||||
Services.obs.removeObserver(runTests, INSPECTOR_NOTIFICATIONS.OPENED);
|
||||
testNode1();
|
||||
Services.obs.addObserver(testNode1, INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
|
||||
InspectorUI.select(node1, true, true, true);
|
||||
InspectorUI.openTreePanel();
|
||||
}
|
||||
|
||||
function testNode1() {
|
||||
let box = InspectorUI.ioBox.createObjectBox(node1);
|
||||
box.click();
|
||||
executeSoon(function() {
|
||||
is(InspectorUI.selection, node1, "selection matches node");
|
||||
is(InspectorUI.highlighter.node, node1, "selection matches node");
|
||||
testNode2();
|
||||
});
|
||||
dump("testNode1\n");
|
||||
Services.obs.removeObserver(testNode1, INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
|
||||
is(InspectorUI.selection, node1, "selection matches node");
|
||||
is(InspectorUI.highlighter.node, node1, "selection matches node");
|
||||
testNode2();
|
||||
}
|
||||
|
||||
function testNode2() {
|
||||
let box = InspectorUI.ioBox.createObjectBox(node2);
|
||||
box.click();
|
||||
executeSoon(function() {
|
||||
is(InspectorUI.selection, node2, "selection matches node");
|
||||
is(InspectorUI.highlighter.node, node2, "selection matches node");
|
||||
Services.obs.addObserver(finishUp, INSPECTOR_NOTIFICATIONS.CLOSED, false);
|
||||
InspectorUI.closeInspectorUI();
|
||||
});
|
||||
dump("testNode2\n")
|
||||
Services.obs.addObserver(testHighlightingNode2, INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
|
||||
InspectorUI.treePanelSelect("node2");
|
||||
}
|
||||
|
||||
function testHighlightingNode2() {
|
||||
dump("testHighlightingNode2\n")
|
||||
Services.obs.removeObserver(testHighlightingNode2, INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
|
||||
is(InspectorUI.selection, node2, "selection matches node");
|
||||
is(InspectorUI.highlighter.node, node2, "selection matches node");
|
||||
Services.obs.addObserver(finishUp, INSPECTOR_NOTIFICATIONS.CLOSED, false);
|
||||
InspectorUI.closeInspectorUI();
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
|
|
|
@ -71,10 +71,19 @@ function xhr_onReadyStateChange() {
|
|||
function inspectorOpened()
|
||||
{
|
||||
Services.obs.removeObserver(inspectorOpened,
|
||||
INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
INSPECTOR_NOTIFICATIONS.OPENED);
|
||||
|
||||
Services.obs.addObserver(treePanelOpened, INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false);
|
||||
InspectorUI.treePanel.open();
|
||||
}
|
||||
|
||||
function treePanelOpened()
|
||||
{
|
||||
Services.obs.removeObserver(treePanelOpened,
|
||||
INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
|
||||
|
||||
ok(InspectorUI.inspecting, "Inspector is highlighting");
|
||||
ok(InspectorUI.isTreePanelOpen, "Inspector Tree Panel is open");
|
||||
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
|
||||
InspectorUI.stopInspecting();
|
||||
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
|
||||
|
||||
|
@ -91,8 +100,8 @@ function inspectorOpened()
|
|||
ok(iframeDiv, "Found the div element inside the iframe");
|
||||
InspectorUI.inspectNode(iframeDiv);
|
||||
|
||||
ok(InspectorUI.treePanelDiv, "InspectorUI.treePanelDiv is available");
|
||||
is(InspectorUI.treePanelDiv.innerHTML.replace(/^\s+|\s+$/mg, ''),
|
||||
ok(InspectorUI.treePanel.treePanelDiv, "InspectorUI.treePanelDiv is available");
|
||||
is(InspectorUI.treePanel.treePanelDiv.innerHTML.replace(/^\s+|\s+$/mg, ''),
|
||||
expectedResult, "treePanelDiv.innerHTML is correct");
|
||||
expectedResult = null;
|
||||
|
||||
|
@ -107,7 +116,7 @@ function inspectorClosed()
|
|||
INSPECTOR_NOTIFICATIONS.CLOSED, false);
|
||||
|
||||
ok(!InspectorUI.inspecting, "Inspector is not highlighting");
|
||||
ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is not open");
|
||||
ok(!InspectorUI.treePanel, "Inspector Tree Panel is not open");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
browser.jar:
|
||||
* content/browser/inspector.html (highlighter/inspector.html)
|
||||
content/browser/NetworkPanel.xhtml (webconsole/NetworkPanel.xhtml)
|
||||
* content/browser/scratchpad.xul (scratchpad/scratchpad.xul)
|
||||
* content/browser/scratchpad.js (scratchpad/scratchpad.js)
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is HUDService code.
|
||||
# The Original Code is Scratchpad Build Code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Mozilla Corporation.
|
||||
#
|
||||
# Portions created by the Initial Developer are Copyright (C) 2010
|
||||
# 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):
|
||||
|
@ -44,9 +44,7 @@ VPATH = @srcdir@
|
|||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
ifneq (mobile,$(MOZ_BUILD_APP))
|
||||
DIRS += test
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -7,3 +7,18 @@ confirmNavigationAway.buttonLeaveAccesskey=L
|
|||
confirmNavigationAway.buttonStay=Stay on Page
|
||||
confirmNavigationAway.buttonStayAccesskey=S
|
||||
|
||||
# LOCALIZATION NOTE (htmlPanel): Used in the Inspector tool's openInspectorUI
|
||||
# method when registering the HTML panel.
|
||||
|
||||
# LOCALIZATION NOTE (htmlPanel.label): A button label that appears on the
|
||||
# InspectorUI's toolbar.
|
||||
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
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче