summaryrefslogtreecommitdiffstats
path: root/WebCore/inspector/front-end/ElementsTreeOutline.js
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/inspector/front-end/ElementsTreeOutline.js')
-rw-r--r--WebCore/inspector/front-end/ElementsTreeOutline.js189
1 files changed, 144 insertions, 45 deletions
diff --git a/WebCore/inspector/front-end/ElementsTreeOutline.js b/WebCore/inspector/front-end/ElementsTreeOutline.js
index a035e7d..d38a7bb 100644
--- a/WebCore/inspector/front-end/ElementsTreeOutline.js
+++ b/WebCore/inspector/front-end/ElementsTreeOutline.js
@@ -43,6 +43,7 @@ WebInspector.ElementsTreeOutline = function() {
this.focusedDOMNode = null;
this.element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true);
+ this.element.addEventListener("keydown", this._keyDown.bind(this), true);
}
WebInspector.ElementsTreeOutline.prototype = {
@@ -191,8 +192,11 @@ WebInspector.ElementsTreeOutline.prototype = {
return element;
},
- handleKeyEvent: function(event)
+ _keyDown: function(event)
{
+ if (event.target !== this.treeOutline.element)
+ return;
+
var selectedElement = this.selectedTreeElement;
if (!selectedElement)
return;
@@ -201,12 +205,13 @@ WebInspector.ElementsTreeOutline.prototype = {
event.keyCode === WebInspector.KeyboardShortcut.KeyCodes.Delete) {
selectedElement.remove();
event.preventDefault();
+ event.stopPropagation();
return;
}
// On Enter or Return start editing the first attribute
// or create a new attribute on the selected element.
- if (event.keyIdentifier === "Enter") {
+ if (isEnterKey(event)) {
if (this._editing)
return;
@@ -214,10 +219,9 @@ WebInspector.ElementsTreeOutline.prototype = {
// prevent a newline from being immediately inserted
event.preventDefault();
+ event.stopPropagation();
return;
}
-
- TreeOutline.prototype.handleKeyEvent.call(this, event);
},
_onmousedown: function(event)
@@ -331,15 +335,8 @@ WebInspector.ElementsTreeElement.prototype = {
if (x) {
this.updateSelection();
this.listItemElement.addStyleClass("hovered");
- if (this._canAddAttributes)
- this._pendingToggleNewAttribute = setTimeout(this.toggleNewAttributeButton.bind(this, true), 500);
} else {
this.listItemElement.removeStyleClass("hovered");
- if (this._pendingToggleNewAttribute) {
- clearTimeout(this._pendingToggleNewAttribute);
- delete this._pendingToggleNewAttribute;
- }
- this.toggleNewAttributeButton(false);
}
}
},
@@ -360,34 +357,10 @@ WebInspector.ElementsTreeElement.prototype = {
tooltipText = WebInspector.UIString("%d × %d pixels (Natural: %d × %d pixels)", properties.offsetWidth, properties.offsetHeight, properties.naturalWidth, properties.naturalHeight);
callback(tooltipText);
}
- var objectProxy = new WebInspector.ObjectProxy(node.id);
+ var objectProxy = new WebInspector.ObjectProxy(node.injectedScriptId, node.id);
WebInspector.ObjectProxy.getPropertiesAsync(objectProxy, ["naturalHeight", "naturalWidth", "offsetHeight", "offsetWidth"], createTooltipThenCallback);
},
- toggleNewAttributeButton: function(visible)
- {
- function removeAddAttributeSpan()
- {
- if (this._addAttributeElement && this._addAttributeElement.parentNode)
- this._addAttributeElement.parentNode.removeChild(this._addAttributeElement);
- delete this._addAttributeElement;
-
- this.updateSelection();
- }
-
- if (!this._addAttributeElement && visible && !this._editing) {
- var span = document.createElement("span");
- span.className = "add-attribute webkit-html-attribute-name";
- span.textContent = " ?=\"\"";
- span.addEventListener("dblclick", removeAddAttributeSpan.bind(this), false);
- this._addAttributeElement = span;
-
- var tag = this.listItemElement.getElementsByClassName("webkit-html-tag")[0];
- this._insertInLastAttributePosition(tag, span);
- } else if (!visible && this._addAttributeElement)
- removeAddAttributeSpan.call(this);
- },
-
updateSelection: function()
{
var listItemElement = this.listItemElement;
@@ -421,7 +394,7 @@ WebInspector.ElementsTreeElement.prototype = {
this.listItemElement.addStyleClass("hovered");
}
- this._updateTitle();
+ this.updateTitle();
this._preventFollowingLinksOnDoubleClick();
},
@@ -630,6 +603,8 @@ WebInspector.ElementsTreeElement.prototype = {
contextMenu.appendSeparator();
// Add node-related actions.
+ contextMenu.appendItem(WebInspector.UIString("Edit as HTML"), this._editAsHTML.bind(this));
+ contextMenu.appendItem(WebInspector.UIString("Copy as HTML"), this._copyHTML.bind(this));
contextMenu.appendItem(WebInspector.UIString("Delete Node"), this.remove.bind(this));
},
@@ -646,7 +621,6 @@ WebInspector.ElementsTreeElement.prototype = {
var listItem = this._listItemNode;
if (this._canAddAttributes) {
- this.toggleNewAttributeButton(false);
var attribute = listItem.getElementsByClassName("webkit-html-attribute")[0];
if (attribute)
return this._startEditingAttribute(attribute, attribute.getElementsByClassName("webkit-html-attribute-value")[0]);
@@ -746,6 +720,60 @@ WebInspector.ElementsTreeElement.prototype = {
return true;
},
+ _startEditingAsHTML: function(commitCallback, initialValue)
+ {
+ if (this._htmlEditElement && WebInspector.isBeingEdited(this._htmlEditElement))
+ return true;
+
+ this._editing = true;
+
+ this._htmlEditElement = document.createElement("div");
+ this._htmlEditElement.className = "source-code elements-tree-editor";
+ this._htmlEditElement.textContent = initialValue;
+
+ // Hide header items.
+ var child = this.listItemElement.firstChild;
+ while (child) {
+ child.style.display = "none";
+ child = child.nextSibling;
+ }
+ // Hide children item.
+ if (this._childrenListNode)
+ this._childrenListNode.style.display = "none";
+ // Append editor.
+ this.listItemElement.appendChild(this._htmlEditElement);
+
+ this.updateSelection();
+
+ function commit()
+ {
+ commitCallback(this._htmlEditElement.textContent);
+ dispose.call(this);
+ }
+
+ function dispose()
+ {
+ delete this._editing;
+
+ // Remove editor.
+ this.listItemElement.removeChild(this._htmlEditElement);
+ delete this._htmlEditElement;
+ // Unhide children item.
+ if (this._childrenListNode)
+ this._childrenListNode.style.removeProperty("display");
+ // Unhide header items.
+ var child = this.listItemElement.firstChild;
+ while (child) {
+ child.style.removeProperty("display");
+ child = child.nextSibling;
+ }
+
+ this.updateSelection();
+ }
+
+ WebInspector.startEditing(this._htmlEditElement, commit.bind(this), dispose.bind(this), null, true);
+ },
+
_attributeEditingCommitted: function(element, newText, oldText, attributeName, moveDirection)
{
delete this._editing;
@@ -829,20 +857,22 @@ WebInspector.ElementsTreeElement.prototype = {
textNode.nodeValue = newText;
- // No need to call _updateTitle here, it will be called after the nodeValue is committed.
+ // Need to restore attributes / node structure.
+ this.updateTitle();
},
_editingCancelled: function(element, context)
{
delete this._editing;
- // No need to call _updateTitle here, the editing code will revert to the original text.
+ // Need to restore attributes structure.
+ this.updateTitle();
},
- _updateTitle: function()
+ updateTitle: function()
{
// If we are editing, return early to prevent canceling the edit.
- // After editing is committed _updateTitle will be called.
+ // After editing is committed updateTitle will be called.
if (this._editing)
return;
@@ -863,6 +893,40 @@ WebInspector.ElementsTreeElement.prototype = {
this.createTooltipForImageNode(this.representedObject, callback);
},
+ _rewriteAttrHref: function(node, hrefValue)
+ {
+ if (!hrefValue || hrefValue.indexOf("://") > 0)
+ return hrefValue;
+
+ var match;
+ var documentURL;
+ for (var frameOwnerCandidate = node; frameOwnerCandidate; frameOwnerCandidate = frameOwnerCandidate.parentNode) {
+ if (frameOwnerCandidate.documentURL) {
+ documentURL = frameOwnerCandidate.documentURL;
+ break;
+ }
+ }
+ if (documentURL) {
+ match = documentURL.match(WebInspector.URLRegExp);
+ if (match) {
+ var path = hrefValue;
+ if (path.charAt(0) !== "/") {
+ var documentPath = match[4] || "/";
+ path = documentPath.substring(0, documentPath.lastIndexOf("/")) + "/" + path;
+ }
+ return match[1] + "://" + match[2] + (match[3] ? (":" + match[3]) : "") + path;
+ }
+ }
+
+ // documentURL not found or has bad value
+ for (var url in WebInspector.resourceURLMap) {
+ match = url.match(WebInspector.URLRegExp);
+ if (match && match[4] === hrefValue)
+ return url;
+ }
+ return hrefValue;
+ },
+
_nodeTitleInfo: function(node, hasChildren, linkify, tooltipText)
{
var info = {title: "", hasChildren: hasChildren};
@@ -883,7 +947,7 @@ WebInspector.ElementsTreeElement.prototype = {
var value = attr.value;
if (linkify && (attr.name === "src" || attr.name === "href")) {
var value = value.replace(/([\/;:\)\]\}])/g, "$1\u200B");
- info.title += linkify(attr.value, value, "webkit-html-attribute-value", node.nodeName.toLowerCase() == "a", tooltipText);
+ info.title += linkify(this._rewriteAttrHref(node, attr.value), value, "webkit-html-attribute-value", node.nodeName.toLowerCase() == "a", tooltipText);
} else {
var value = value.escapeHTML();
value = value.replace(/([\/;:\)\]\}])/g, "$1​");
@@ -915,7 +979,7 @@ WebInspector.ElementsTreeElement.prototype = {
var newNode = document.createElement("span");
newNode.textContent = node.textContent;
- var javascriptSyntaxHighlighter = new WebInspector.JavaScriptSourceSyntaxHighlighter(null, null);
+ var javascriptSyntaxHighlighter = new WebInspector.DOMSyntaxHighlighter("text/javascript");
javascriptSyntaxHighlighter.syntaxHighlightNode(newNode);
info.title = "<span class=\"webkit-html-text-node webkit-html-js-node\">" + newNode.innerHTML.replace(/^[\n\r]*/, "").replace(/\s*$/, "") + "</span>";
@@ -923,7 +987,7 @@ WebInspector.ElementsTreeElement.prototype = {
var newNode = document.createElement("span");
newNode.textContent = node.textContent;
- var cssSyntaxHighlighter = new WebInspector.CSSSourceSyntaxHighlighter(null, null);
+ var cssSyntaxHighlighter = new WebInspector.DOMSyntaxHighlighter("text/css");
cssSyntaxHighlighter.syntaxHighlightNode(newNode);
info.title = "<span class=\"webkit-html-text-node webkit-html-css-node\">" + newNode.innerHTML.replace(/^[\n\r]*/, "").replace(/\s*$/, "") + "</span>";
@@ -985,6 +1049,41 @@ WebInspector.ElementsTreeElement.prototype = {
var callId = WebInspector.Callback.wrap(removeNodeCallback);
InspectorBackend.removeNode(callId, this.representedObject.id);
+ },
+
+ _editAsHTML: function()
+ {
+ var treeOutline = this.treeOutline;
+ var node = this.representedObject;
+ var wasExpanded = this.expanded;
+
+ function selectNode(nodeId)
+ {
+ if (!nodeId)
+ return;
+
+ // Select it and expand if necessary. We force tree update so that it processes dom events and is up to date.
+ WebInspector.panels.elements.updateModifiedNodes();
+
+ WebInspector.updateFocusedNode(nodeId);
+ if (wasExpanded) {
+ var newTreeItem = treeOutline.findTreeElement(WebInspector.domAgent.nodeForId(nodeId));
+ if (newTreeItem)
+ newTreeItem.expand();
+ }
+ }
+
+ function commitChange(value)
+ {
+ InjectedScriptAccess.get(node.injectedScriptId).setOuterHTML(node.id, value, wasExpanded, selectNode.bind(this));
+ }
+
+ InjectedScriptAccess.get(node.injectedScriptId).getNodePropertyValue(node.id, "outerHTML", this._startEditingAsHTML.bind(this, commitChange));
+ },
+
+ _copyHTML: function()
+ {
+ InspectorBackend.copyNode(this.representedObject.id);
}
}