Bug 848731 - Deleting nodes or container frames now resets the markup, highlighter, css views accordingly. r=paul

This commit is contained in:
Patrick Brosset 2013-10-01 08:14:07 -04:00
Родитель e5197f8a17
Коммит e2c6feedd7
7 изменённых файлов: 273 добавлений и 125 удалений

Просмотреть файл

@ -102,6 +102,7 @@ HTMLBreadcrumbs.prototype = {
this.selection.on("new-node-front", this.update);
this.selection.on("pseudoclass", this.updateSelectors);
this.selection.on("attribute-changed", this.updateSelectors);
this.inspector.on("markupmutation", this.update);
this.update();
},
@ -349,6 +350,7 @@ HTMLBreadcrumbs.prototype = {
this.selection.off("new-node-front", this.update);
this.selection.off("pseudoclass", this.updateSelectors);
this.selection.off("attribute-changed", this.updateSelectors);
this.inspector.off("markupmutation", this.update);
this.container.removeEventListener("underflow", this.onscrollboxreflow, false);
this.container.removeEventListener("overflow", this.onscrollboxreflow, false);
@ -611,7 +613,7 @@ HTMLBreadcrumbs.prototype = {
/**
* Update the breadcrumbs display when a new node is selected.
*/
update: function BC_update()
update: function BC_update(reason)
{
this.inspector.hideNodeMenu();
@ -632,7 +634,8 @@ HTMLBreadcrumbs.prototype = {
let idx = this.indexOf(this.selection.nodeFront);
// Is the node already displayed in the breadcrumbs?
if (idx > -1) {
// (and there are no mutations that need re-display of the crumbs)
if (idx > -1 && reason !== "markupmutation") {
// Yes. We select it.
this.setCursor(idx);
} else {
@ -666,7 +669,7 @@ HTMLBreadcrumbs.prototype = {
doneUpdating(this.selection.nodeFront);
this.selectionGuardEnd(err);
});
},
}
}
XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () {

Просмотреть файл

@ -432,7 +432,9 @@ InspectorPanel.prototype = {
},
/**
* When a node is deleted, select its parent node.
* When a node is deleted, select its parent node or the defaultNode if no
* parent is found (may happen when deleting an iframe inside which the
* node was selected).
*/
onDetached: function InspectorPanel_onDetached(event, parentNode) {
this.cancelLayoutChange();

Просмотреть файл

@ -4,6 +4,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {Cu, Ci} = require("chrome");
let EventEmitter = require("devtools/shared/event-emitter");
@ -76,32 +78,38 @@ Selection.prototype = {
let pseudoChange = false;
let detached = false;
let parentNode = null;
for (let m of mutations) {
if (!attributeChange && m.type == "attributes") {
attributeChange = true;
}
if (m.type == "childList") {
if (!detached && this.isNode() && !this.isConnected()) {
parentNode = m.target;
if (!detached && !this.isConnected()) {
if (this.isNode()) {
parentNode = m.target;
}
detached = true;
}
}
if (m.type == "pseudoClassLock"){
if (m.type == "pseudoClassLock") {
pseudoChange = true;
}
}
if (attributeChange)
// Fire our events depending on what changed in the mutations array
if (attributeChange) {
this.emit("attribute-changed");
if (pseudoChange)
}
if (pseudoChange) {
this.emit("pseudoclass");
}
if (detached) {
this.emit("detached", parentNode ? parentNode.rawNode() : null);
this.emit("detached-front", parentNode);
}
},
destroy: function SN_destroy() {
destroy: function() {
this.setNode(null);
this.setWalker(null);
},
@ -117,7 +125,7 @@ Selection.prototype = {
},
// Not remote-safe
setNode: function SN_setNode(value, reason="unknown") {
setNode: function(value, reason="unknown") {
if (value) {
value = this._walker.frontForRawNode(value);
}
@ -168,13 +176,13 @@ Selection.prototype = {
return this._nodeFront;
},
isRoot: function SN_isRootNode() {
isRoot: function() {
return this.isNode() &&
this.isConnected() &&
this._nodeFront.isDocumentElement;
},
isNode: function SN_isNode() {
isNode: function() {
if (!this._nodeFront) {
return false;
}
@ -188,11 +196,11 @@ Selection.prototype = {
return true;
},
isLocal: function SN_nsLocal() {
isLocal: function() {
return !!this._node;
},
isConnected: function SN_isConnected() {
isConnected: function() {
let node = this._nodeFront;
if (!node || !node.actorID) {
return false;
@ -220,58 +228,58 @@ Selection.prototype = {
return false;
},
isHTMLNode: function SN_isHTMLNode() {
isHTMLNode: function() {
let xhtml_ns = "http://www.w3.org/1999/xhtml";
return this.isNode() && this.node.namespaceURI == xhtml_ns;
},
// Node type
isElementNode: function SN_isElementNode() {
isElementNode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.ELEMENT_NODE;
},
isAttributeNode: function SN_isAttributeNode() {
isAttributeNode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.ATTRIBUTE_NODE;
},
isTextNode: function SN_isTextNode() {
isTextNode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.TEXT_NODE;
},
isCDATANode: function SN_isCDATANode() {
isCDATANode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.CDATA_SECTION_NODE;
},
isEntityRefNode: function SN_isEntityRefNode() {
isEntityRefNode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.ENTITY_REFERENCE_NODE;
},
isEntityNode: function SN_isEntityNode() {
isEntityNode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.ENTITY_NODE;
},
isProcessingInstructionNode: function SN_isProcessingInstructionNode() {
isProcessingInstructionNode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.PROCESSING_INSTRUCTION_NODE;
},
isCommentNode: function SN_isCommentNode() {
isCommentNode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.PROCESSING_INSTRUCTION_NODE;
},
isDocumentNode: function SN_isDocumentNode() {
isDocumentNode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.DOCUMENT_NODE;
},
isDocumentTypeNode: function SN_isDocumentTypeNode() {
isDocumentTypeNode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.DOCUMENT_TYPE_NODE;
},
isDocumentFragmentNode: function SN_isDocumentFragmentNode() {
isDocumentFragmentNode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.DOCUMENT_FRAGMENT_NODE;
},
isNotationNode: function SN_isNotationNode() {
isNotationNode: function() {
return this.isNode() && this.nodeFront.nodeType == Ci.nsIDOMNode.NOTATION_NODE;
},
}
};

Просмотреть файл

@ -16,6 +16,8 @@ support-files = head.js
[browser_inspector_bug_831693_search_suggestions.html]
[browser_inspector_bug_835722_infobar_reappears.js]
[browser_inspector_bug_840156_destroy_after_navigation.js]
[browser_inspector_bug_848731_reset_selection_on_delete.js]
[browser_inspector_bug_848731_reset_selection_on_delete.html]
[browser_inspector_changes.js]
[browser_inspector_cmd_inspect.html]
[browser_inspector_cmd_inspect.js]

Просмотреть файл

@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>node delete - reset selection - test</title>
</head>
<body>
<ul id="deleteChildren">
<li id="deleteManually">Delete me via the inspector</li>
<li id="deleteAutomatically">Delete me via javascript</li>
</ul>
<iframe id="deleteIframe" src="data:text/html,%3C!DOCTYPE%20html%3E%3Chtml%20lang%3D%22en%22%3E%3Cbody%3E%3Cp%20id%3D%22deleteInIframe%22%3EDelete my container iframe%3C%2Fp%3E%3C%2Fbody%3E%3C%2Fhtml%3E"></iframe>
</body>
</html>

Просмотреть файл

@ -0,0 +1,140 @@
/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Test that when nodes are being deleted in the page, the current selection
// and therefore the markup view, css rule view, computed view, font view,
// box model view, and breadcrumbs, reset accordingly to show the right node
const TEST_PAGE = "http://mochi.test:8888/browser/browser/devtools/inspector/test/browser_inspector_bug_848731_reset_selection_on_delete.html";
function test() {
let inspector, toolbox;
waitForExplicitFinish();
// Create a tab, load test HTML, wait for load and start the tests
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function onload() {
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
waitForFocus(function() {
openInspector((aInspector, aToolbox) => {
inspector = aInspector;
toolbox = aToolbox;
startTests();
});
}, content);
}, true);
content.location = TEST_PAGE;
function startTests() {
testManuallyDeleteSelectedNode();
}
function getContainerForRawNode(rawNode) {
let front = inspector.markup.walker.frontForRawNode(rawNode);
let container = inspector.markup.getContainer(front);
return container;
}
// 1 - select a node, right click, hit delete, verify that its parent is selected
// and that all other tools are fine
function testManuallyDeleteSelectedNode() {
// Select our div
let div = content.document.getElementById("deleteManually");
inspector.selection.setNode(div);
inspector.once("inspector-updated", () => {
is(inspector.selection.node, div);
// Get the node container in the markup view
let container = getContainerForRawNode(div);
// Simulate right-click
EventUtils.synthesizeMouse(container.tagLine, 2, 2,
{type: "contextmenu", button: 2}, inspector.panelWin);
// And react to the popup shown event
let contextMenu = inspector.panelDoc.getElementById("inspectorPopupSet");
contextMenu.addEventListener("popupshown", function contextShown() {
contextMenu.removeEventListener("popupshown", contextShown, false);
// Click on the delete sub-menu item
inspector.panelDoc.getElementById("node-menu-delete").click();
// Once updated, make sure eveything is in place, and move on
inspector.once("inspector-updated", () => {
let parent = content.document.getElementById("deleteChildren");
assertNodeSelectedAndPanelsUpdated(parent, "ul#deleteChildren");
testAutomaticallyDeleteSelectedNode();
});
}, false);
});
}
// 2 - select a node, delete it via javascript, verify the same things as 1
function testAutomaticallyDeleteSelectedNode() {
// Select our second div
let div = content.document.getElementById("deleteAutomatically");
inspector.selection.setNode(div);
inspector.once("inspector-updated", () => {
is(inspector.selection.node, div);
// Now remove that div via javascript
let parent = content.document.getElementById("deleteChildren");
parent.removeChild(div);
// Once updated, make sure eveything is in place, and move on
inspector.once("inspector-updated", () => {
assertNodeSelectedAndPanelsUpdated(parent, "ul#deleteChildren");
testDeleteSelectedNodeContainerFrame();
});
});
}
// 3 - select a node inside an iframe, delete the iframe via javascript, verify that the default node is selected
// and that all other tools are fine
function testDeleteSelectedNodeContainerFrame() {
// Select our third test element, inside the iframe
let iframe = content.document.getElementById("deleteIframe");
let div = iframe.contentDocument.getElementById("deleteInIframe");
inspector.selection.setNode(div);
inspector.once("inspector-updated", () => {
is(inspector.selection.node, div);
// Now remove that parent iframe via javascript
let parent = content.document.body;
parent.removeChild(iframe);
// Once updated, make sure eveything is in place, and move on
inspector.once("inspector-updated", () => {
assertNodeSelectedAndPanelsUpdated(parent, "body");
endTests();
});
});
}
function endTests() {
executeSoon(() => {
toolbox.destroy();
toolbox = inspector = null;
gBrowser.removeCurrentTab();
finish();
});
}
function assertNodeSelectedAndPanelsUpdated(node, crumbLabel) {
// Right node selected?
is(inspector.selection.nodeFront, getNodeFront(node),
"The right node is selected");
// breadcrumbs updated?
let breadcrumbs = inspector.panelDoc.getElementById("inspector-breadcrumbs");
is(breadcrumbs.querySelector("button[checked=true]").textContent, crumbLabel,
"The right breadcrumb is selected");
// Highlighter is shown?
ok(!inspector.highlighter.isHidden(), "The highlighter is shown");
}
}

Просмотреть файл

@ -28,7 +28,9 @@ Cu.import("resource://gre/modules/Services.jsm");
loader.lazyGetter(this, "DOMParser", function() {
return Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
});
loader.lazyGetter(this, "AutocompletePopup", () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
loader.lazyGetter(this, "AutocompletePopup", () => {
return require("devtools/shared/autocomplete-popup").AutocompletePopup
});
/**
* Vocabulary for the purposes of this file:
@ -48,8 +50,7 @@ loader.lazyGetter(this, "AutocompletePopup", () => require("devtools/shared/auto
* @param iframe aFrame
* An iframe in which the caller has kindly loaded markup-view.xhtml.
*/
function MarkupView(aInspector, aFrame, aControllerWindow)
{
function MarkupView(aInspector, aFrame, aControllerWindow) {
this._inspector = aInspector;
this.walker = this._inspector.walker;
this._frame = aFrame;
@ -101,8 +102,7 @@ exports.MarkupView = MarkupView;
MarkupView.prototype = {
_selectedContainer: null,
template: function MT_template(aName, aDest, aOptions={stack: "markup-view.xhtml"})
{
template: function(aName, aDest, aOptions={stack: "markup-view.xhtml"}) {
let node = this.doc.getElementById("template-" + aName).cloneNode(true);
node.removeAttribute("id");
template(node, aDest, aOptions);
@ -113,8 +113,7 @@ MarkupView.prototype = {
* Get the MarkupContainer object for a given node, or undefined if
* none exists.
*/
getContainer: function MT_getContainer(aNode)
{
getContainer: function(aNode) {
return this._containers.get(aNode);
},
@ -148,8 +147,7 @@ MarkupView.prototype = {
/**
* Highlight the inspector selected node.
*/
_onNewSelection: function MT__onNewSelection()
{
_onNewSelection: function() {
let done = this._inspector.updating("markup-view");
if (this._inspector.selection.isNode()) {
this.showNode(this._inspector.selection.nodeFront, true).then(() => {
@ -166,8 +164,7 @@ MarkupView.prototype = {
* Create a TreeWalker to find the next/previous
* node for selection.
*/
_selectionWalker: function MT__seletionWalker(aStart)
{
_selectionWalker: function(aStart) {
let walker = this.doc.createTreeWalker(
aStart || this._elt,
Ci.nsIDOMNodeFilter.SHOW_ELEMENT,
@ -187,8 +184,7 @@ MarkupView.prototype = {
/**
* Key handling.
*/
_onKeyDown: function MT__KeyDown(aEvent)
{
_onKeyDown: function(aEvent) {
let handled = true;
// Ignore keystrokes that originated in editors.
@ -286,8 +282,7 @@ MarkupView.prototype = {
* Delete a node from the DOM.
* This is an undoable action.
*/
deleteNode: function MC__deleteNode(aNode)
{
deleteNode: function(aNode) {
if (aNode.isDocumentElement ||
aNode.nodeType == Ci.nsIDOMNode.DOCUMENT_TYPE_NODE) {
return;
@ -315,7 +310,7 @@ MarkupView.prototype = {
/**
* If an editable item is focused, select its container.
*/
_onFocus: function MC__onFocus(aEvent) {
_onFocus: function(aEvent) {
let parent = aEvent.target;
while (!parent.container) {
parent = parent.parentNode;
@ -334,8 +329,7 @@ MarkupView.prototype = {
* @param aIgnoreFocus aIgnoreFocus
* If falsy, keyboard focus will be moved to the container too.
*/
navigate: function MT__navigate(aContainer, aIgnoreFocus)
{
navigate: function(aContainer, aIgnoreFocus) {
if (!aContainer) {
return;
}
@ -362,8 +356,7 @@ MarkupView.prototype = {
* Whether the newly imported node should be flashed
* @returns MarkupContainer The MarkupContainer object for this element.
*/
importNode: function MT_importNode(aNode, aFlashNode)
{
importNode: function(aNode, aFlashNode) {
if (!aNode) {
return null;
}
@ -395,8 +388,7 @@ MarkupView.prototype = {
/**
* Mutation observer used for included nodes.
*/
_mutationObserver: function MT__mutationObserver(aMutations)
{
_mutationObserver: function(aMutations) {
for (let mutation of aMutations) {
let type = mutation.type;
let target = mutation.target;
@ -437,8 +429,7 @@ MarkupView.prototype = {
* Given a list of mutations returned by the mutation observer, flash the
* corresponding containers to attract attention.
*/
_flashMutatedNodes: function MT_flashMutatedNodes(aMutations)
{
_flashMutatedNodes: function(aMutations) {
let addedOrEditedContainers = new Set();
let removedContainers = new Set();
@ -481,8 +472,7 @@ MarkupView.prototype = {
* Make sure the given node's parents are expanded and the
* node is scrolled on to screen.
*/
showNode: function MT_showNode(aNode, centered)
{
showNode: function(aNode, centered) {
let container = this.importNode(aNode);
let parent = aNode;
while ((parent = parent.parentNode())) {
@ -501,8 +491,7 @@ MarkupView.prototype = {
/**
* Expand the container's children.
*/
_expandContainer: function MT__expandContainer(aContainer)
{
_expandContainer: function(aContainer) {
return this._updateChildren(aContainer, {expand: true}).then(() => {
aContainer.expanded = true;
});
@ -511,8 +500,7 @@ MarkupView.prototype = {
/**
* Expand the node's children.
*/
expandNode: function MT_expandNode(aNode)
{
expandNode: function(aNode) {
let container = this._containers.get(aNode);
this._expandContainer(container);
},
@ -522,8 +510,7 @@ MarkupView.prototype = {
*
* @param aContainer The container to expand.
*/
_expandAll: function MT_expandAll(aContainer)
{
_expandAll: function(aContainer) {
return this._expandContainer(aContainer).then(() => {
let child = aContainer.children.firstChild;
let promises = [];
@ -541,8 +528,7 @@ MarkupView.prototype = {
* @param aContainer The node to expand, or null
* to start from the top.
*/
expandAll: function MT_expandAll(aNode)
{
expandAll: function(aNode) {
aNode = aNode || this._rootNode;
return this._expandAll(this._containers.get(aNode));
},
@ -550,14 +536,12 @@ MarkupView.prototype = {
/**
* Collapse the node's children.
*/
collapseNode: function MT_collapseNode(aNode)
{
collapseNode: function(aNode) {
let container = this._containers.get(aNode);
container.expanded = false;
},
setNodeExpanded: function(aNode, aExpanded)
{
setNodeExpanded: function(aNode, aExpanded) {
if (aExpanded) {
this.expandNode(aNode);
} else {
@ -568,8 +552,7 @@ MarkupView.prototype = {
/**
* Mark the given node selected.
*/
markNodeAsSelected: function MT_markNodeAsSelected(aNode)
{
markNodeAsSelected: function(aNode) {
let container = this._containers.get(aNode);
if (this._selectedContainer === container) {
return false;
@ -589,8 +572,7 @@ MarkupView.prototype = {
* Make sure that every ancestor of the selection are updated
* and included in the list of visible children.
*/
_ensureVisible: function(node)
{
_ensureVisible: function(node) {
while (node) {
let container = this._containers.get(node);
let parent = node.parentNode();
@ -608,8 +590,7 @@ MarkupView.prototype = {
/**
* Unmark selected node (no node selected).
*/
unmarkSelectedNode: function MT_unmarkSelectedNode()
{
unmarkSelectedNode: function() {
if (this._selectedContainer) {
this._selectedContainer.selected = false;
this._selectedContainer = null;
@ -619,8 +600,7 @@ MarkupView.prototype = {
/**
* Called when the markup panel initiates a change on a node.
*/
nodeChanged: function MT_nodeChanged(aNode)
{
nodeChanged: function(aNode) {
if (aNode === this._inspector.selection.nodeFront) {
this._inspector.change("markupview");
}
@ -667,8 +647,7 @@ MarkupView.prototype = {
* @return a promise that will be resolved when the children are ready
* (which may be immediately).
*/
_updateChildren: function(aContainer, options)
{
_updateChildren: function(aContainer, options) {
let expand = options && options.expand;
let flash = options && options.flash;
@ -772,8 +751,7 @@ MarkupView.prototype = {
/**
* Return a list of the children to display for this container.
*/
_getVisibleChildren: function MV__getVisibleChildren(aContainer, aCentered)
{
_getVisibleChildren: function(aContainer, aCentered) {
let maxChildren = aContainer.maxChildren || this.maxChildren;
if (maxChildren == -1) {
maxChildren = undefined;
@ -788,8 +766,7 @@ MarkupView.prototype = {
/**
* Tear down the markup panel.
*/
destroy: function MT_destroy()
{
destroy: function() {
gDevTools.off("pref-changed", this._handlePrefChange);
this.undo.destroy();
@ -802,18 +779,23 @@ MarkupView.prototype = {
delete this._boundFocus;
if (this._boundUpdatePreview) {
this._frame.contentWindow.removeEventListener("scroll", this._boundUpdatePreview, true);
this._frame.contentWindow.removeEventListener("scroll",
this._boundUpdatePreview, true);
delete this._boundUpdatePreview;
}
if (this._boundResizePreview) {
this._frame.contentWindow.removeEventListener("resize", this._boundResizePreview, true);
this._frame.contentWindow.removeEventListener("overflow", this._boundResizePreview, true);
this._frame.contentWindow.removeEventListener("underflow", this._boundResizePreview, true);
this._frame.contentWindow.removeEventListener("resize",
this._boundResizePreview, true);
this._frame.contentWindow.removeEventListener("overflow",
this._boundResizePreview, true);
this._frame.contentWindow.removeEventListener("underflow",
this._boundResizePreview, true);
delete this._boundResizePreview;
}
this._frame.contentWindow.removeEventListener("keydown", this._boundKeyDown, false);
this._frame.contentWindow.removeEventListener("keydown",
this._boundKeyDown, false);
delete this._boundKeyDown;
this._inspector.selection.off("new-node-front", this._boundOnNewSelection);
@ -830,8 +812,7 @@ MarkupView.prototype = {
/**
* Initialize the preview panel.
*/
_initPreview: function MT_initPreview()
{
_initPreview: function() {
if (!Services.prefs.getBoolPref("devtools.inspector.markupPreview")) {
return;
}
@ -845,21 +826,23 @@ MarkupView.prototype = {
this._previewWidth = this._preview.getBoundingClientRect().width;
this._boundResizePreview = this._resizePreview.bind(this);
this._frame.contentWindow.addEventListener("resize", this._boundResizePreview, true);
this._frame.contentWindow.addEventListener("overflow", this._boundResizePreview, true);
this._frame.contentWindow.addEventListener("underflow", this._boundResizePreview, true);
this._frame.contentWindow.addEventListener("resize",
this._boundResizePreview, true);
this._frame.contentWindow.addEventListener("overflow",
this._boundResizePreview, true);
this._frame.contentWindow.addEventListener("underflow",
this._boundResizePreview, true);
this._boundUpdatePreview = this._updatePreview.bind(this);
this._frame.contentWindow.addEventListener("scroll", this._boundUpdatePreview, true);
this._frame.contentWindow.addEventListener("scroll",
this._boundUpdatePreview, true);
this._updatePreview();
},
/**
* Move the preview viewbox.
*/
_updatePreview: function MT_updatePreview()
{
_updatePreview: function() {
let win = this._frame.contentWindow;
if (win.scrollMaxY == 0) {
@ -876,7 +859,8 @@ MarkupView.prototype = {
let scrollTo
if (height >= win.innerHeight) {
scrollTo = -(height - win.innerHeight) * (win.scrollY / win.scrollMaxY);
this._previewBar.setAttribute("style", "height:" + height + "px;transform:translateY(" + scrollTo + "px)");
this._previewBar.setAttribute("style", "height:" + height +
"px;transform:translateY(" + scrollTo + "px)");
} else {
this._previewBar.setAttribute("style", "height:100%");
}
@ -886,14 +870,14 @@ MarkupView.prototype = {
let height = ~~(win.innerHeight * ratio) + "px";
let top = ~~(win.scrollY * ratio) + "px";
this._viewbox.setAttribute("style", "height:" + height + ";transform: translateY(" + top + ")");
this._viewbox.setAttribute("style", "height:" + height +
";transform: translateY(" + top + ")");
},
/**
* Hide the preview while resizing, to avoid slowness.
*/
_resizePreview: function MT_resizePreview()
{
_resizePreview: function() {
let win = this._frame.contentWindow;
this._previewBar.classList.add("hide");
win.clearTimeout(this._resizePreviewTimeout);
@ -1122,12 +1106,14 @@ MarkupContainer.prototype = {
this.highlighter.classList.add("theme-bg-darker");
}
if (this.closeTagLine) {
this.closeTagLine.querySelector(".highlighter").classList.add("theme-bg-darker");
this.closeTagLine.querySelector(".highlighter").classList.add(
"theme-bg-darker");
}
} else {
this.highlighter.classList.remove("theme-bg-darker");
if (this.closeTagLine) {
this.closeTagLine.querySelector(".highlighter").classList.remove("theme-bg-darker");
this.closeTagLine.querySelector(".highlighter").classList.remove(
"theme-bg-darker");
}
}
},
@ -1204,8 +1190,7 @@ RootContainer.prototype = {
/**
* Creates an editor for simple nodes.
*/
function GenericEditor(aContainer, aNode)
{
function GenericEditor(aContainer, aNode) {
this.elt = aContainer.doc.createElement("span");
this.elt.className = "editor";
this.elt.textContent = aNode.nodeName;
@ -1217,8 +1202,7 @@ function GenericEditor(aContainer, aNode)
* @param MarkupContainer aContainer The container owning this editor.
* @param DOMNode aNode The node being edited.
*/
function DoctypeEditor(aContainer, aNode)
{
function DoctypeEditor(aContainer, aNode) {
this.elt = aContainer.doc.createElement("span");
this.elt.className = "editor comment";
this.elt.textContent = '<!DOCTYPE ' + aNode.name +
@ -1235,8 +1219,7 @@ function DoctypeEditor(aContainer, aNode)
* @param DOMNode aNode The node being edited.
* @param string aTemplate The template id to use to build the editor.
*/
function TextEditor(aContainer, aNode, aTemplate)
{
function TextEditor(aContainer, aNode, aTemplate) {
this.node = aNode;
this._selected = false;
@ -1282,8 +1265,7 @@ TextEditor.prototype = {
this.update();
},
update: function TE_update()
{
update: function() {
if (!this.selected || !this.node.incompleteValue) {
let text = this.node.shortValue;
// XXX: internationalize the elliding
@ -1312,8 +1294,7 @@ TextEditor.prototype = {
* @param MarkupContainer aContainer The container owning this editor.
* @param Element aNode The node being edited.
*/
function ElementEditor(aContainer, aNode)
{
function ElementEditor(aContainer, aNode) {
this.doc = aContainer.doc;
this.undo = aContainer.undo;
this.template = aContainer.markup.template.bind(aContainer.markup);
@ -1386,8 +1367,7 @@ ElementEditor.prototype = {
/**
* Update the state of the editor from the node.
*/
update: function EE_update(parseColors=true)
{
update: function(parseColors=true) {
let attrs = this.node.attributes;
if (!attrs) {
return;
@ -1420,8 +1400,7 @@ ElementEditor.prototype = {
return this.node.startModifyingAttributes();
},
_createAttribute: function EE_createAttribute(aAttr, aBefore = null)
{
_createAttribute: function(aAttr, aBefore = null) {
// Create the template editor, which will save some variables here.
let data = {
attrName: aAttr.name,
@ -1497,7 +1476,6 @@ ElementEditor.prototype = {
}
});
// Figure out where we should place the attribute.
let before = aBefore;
if (aAttr.name == "id") {
@ -1539,8 +1517,7 @@ ElementEditor.prototype = {
* set of attributes, used to place new attributes where the
* user put them.
*/
_applyAttributes: function EE__applyAttributes(aValue, aAttrNode, aDoMods, aUndoMods)
{
_applyAttributes: function(aValue, aAttrNode, aDoMods, aUndoMods) {
let attrs = parseAttributeValues(aValue, this.doc);
for (let attr of attrs) {
// Create an attribute editor next to the current attribute if needed.
@ -1554,8 +1531,7 @@ ElementEditor.prototype = {
* Saves the current state of the given attribute into an attribute
* modification list.
*/
_saveAttribute: function(aName, aUndoMods)
{
_saveAttribute: function(aName, aUndoMods) {
let node = this.node;
if (node.hasAttribute(aName)) {
let oldValue = node.getAttribute(aName);
@ -1568,7 +1544,7 @@ ElementEditor.prototype = {
/**
* Called when the tag name editor has is done editing.
*/
onTagEdit: function EE_onTagEdit(aVal, aCommit) {
onTagEdit: function(aVal, aCommit) {
if (!aCommit || aVal == this.rawNode.tagName) {
return;
}
@ -1623,7 +1599,8 @@ ElementEditor.prototype = {
};
function nodeDocument(node) {
return node.ownerDocument || (node.nodeType == Ci.nsIDOMNode.DOCUMENT_NODE ? node : null);
return node.ownerDocument ||
(node.nodeType == Ci.nsIDOMNode.DOCUMENT_NODE ? node : null);
}
function truncateString(str, maxLength) {
@ -1648,10 +1625,12 @@ function truncateString(str, maxLength) {
function parseAttributeValues(attr, doc) {
attr = attr.trim();
let parse = DOMParser.parseFromString;
// Handle bad user inputs by appending a " or ' if it fails to parse without them.
let el = DOMParser.parseFromString("<div " + attr + "></div>", "text/html").body.childNodes[0] ||
DOMParser.parseFromString("<div " + attr + "\"></div>", "text/html").body.childNodes[0] ||
DOMParser.parseFromString("<div " + attr + "'></div>", "text/html").body.childNodes[0];
let el = parse("<div " + attr + "></div>", "text/html").body.childNodes[0] ||
parse("<div " + attr + "\"></div>", "text/html").body.childNodes[0] ||
parse("<div " + attr + "'></div>", "text/html").body.childNodes[0];
let div = doc.createElement("div");
let attributes = [];