Diff
Modified: trunk/Source/WebCore/ChangeLog (90459 => 90460)
--- trunk/Source/WebCore/ChangeLog 2011-07-06 15:25:27 UTC (rev 90459)
+++ trunk/Source/WebCore/ChangeLog 2011-07-06 15:25:40 UTC (rev 90460)
@@ -1,3 +1,36 @@
+2011-07-06 Pavel Feldman <[email protected]>
+
+ Web Inspector: implement drag'n'drop in the elements panel for reordering nodes.
+ https://bugs.webkit.org/show_bug.cgi?id=63990
+
+ Reviewed by Yury Semikhatsky.
+
+ * inspector/Inspector.json:
+ * inspector/InspectorDOMAgent.cpp:
+ (WebCore::InspectorDOMAgent::moveTo):
+ * inspector/InspectorDOMAgent.h:
+ * inspector/front-end/DOMAgent.js:
+ (WebInspector.DOMNode.prototype._removeChild):
+ (WebInspector.DOMNode.prototype.ownerDocumentElement):
+ (WebInspector.DOMNode.prototype.moveTo):
+ (WebInspector.DOMAgent.prototype._childNodeRemoved):
+ * inspector/front-end/ElementsTreeOutline.js:
+ (WebInspector.ElementsTreeOutline):
+ (WebInspector.ElementsTreeOutline.prototype._ondragstart):
+ (WebInspector.ElementsTreeOutline.prototype._ondragover):
+ (WebInspector.ElementsTreeOutline.prototype._ondragleave):
+ (WebInspector.ElementsTreeOutline.prototype._isValidDragSourceOrTarget):
+ (WebInspector.ElementsTreeOutline.prototype._ondragend.callback):
+ (WebInspector.ElementsTreeOutline.prototype._ondragend):
+ (WebInspector.ElementsTreeOutline.prototype._clearDragOverTreeElementMarker):
+ (WebInspector.ElementsTreeOutline.prototype.populateContextMenu.focusElement):
+ (WebInspector.ElementsTreeOutline.prototype.populateContextMenu):
+ (WebInspector.ElementsTreeElement.prototype.onattach):
+ * inspector/front-end/inspector.css:
+ (.outline-disclosure li.elements-drag-over .selection):
+ * inspector/front-end/treeoutline.js:
+ (TreeOutline.prototype.treeElementFromEvent):
+
2011-07-06 Andras Becsi <[email protected]>
Fix "warning: a `;' might be needed at the end of action code"
Modified: trunk/Source/WebCore/inspector/Inspector.json (90459 => 90460)
--- trunk/Source/WebCore/inspector/Inspector.json 2011-07-06 15:25:27 UTC (rev 90459)
+++ trunk/Source/WebCore/inspector/Inspector.json 2011-07-06 15:25:40 UTC (rev 90460)
@@ -1015,6 +1015,18 @@
{ "name": "attributes", "type": "array", "items": { "type": "Attributes" }, "description": "Attribute holders for the requested nodes." }
],
"description": "Returns attributes for the specified nodes."
+ },
+ {
+ "name": "moveTo",
+ "parameters": [
+ { "name": "nodeId", "type": "integer", "description": "Id of the node to drop." },
+ { "name": "targetNodeId", "type": "integer", "description": "Id of the node to drop into." },
+ { "name": "anchorNodeId", "type": "integer", "optional": true, "description": "Drop node before given one." }
+ ],
+ "returns": [
+ { "name": "nodeId", "type": "integer", "description": "New id of the moved node." }
+ ],
+ "description": "Moves node into the new container, places it before the given anchor."
}
],
"events": [
Modified: trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp (90459 => 90460)
--- trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp 2011-07-06 15:25:27 UTC (rev 90459)
+++ trunk/Source/WebCore/inspector/InspectorDOMAgent.cpp 2011-07-06 15:25:40 UTC (rev 90460)
@@ -1032,6 +1032,36 @@
m_client->hideHighlight();
}
+void InspectorDOMAgent::moveTo(ErrorString* error, int nodeId, int targetNodeId, const int* const anchorNodeId, int* newNodeId)
+{
+ Element* element = assertElement(error, nodeId);
+ if (!element)
+ return;
+
+ Element* targetElement = assertElement(error, targetNodeId);
+ if (!targetElement)
+ return;
+
+ Element* anchorElement = 0;
+ if (anchorNodeId && *anchorNodeId) {
+ anchorElement = assertElement(error, *anchorNodeId);
+ if (!anchorElement)
+ return;
+ if (anchorElement->parentNode() != targetElement) {
+ *error = "Anchor node must be child of the target node.";
+ return;
+ }
+ }
+
+ ExceptionCode ec = 0;
+ bool success = targetElement->insertBefore(element, anchorElement, ec);
+ if (ec || !success) {
+ *error = "Could not drop node.";
+ return;
+ }
+ *newNodeId = pushNodePathToFrontend(element);
+}
+
void InspectorDOMAgent::resolveNode(ErrorString* error, int nodeId, const String* const objectGroup, RefPtr<InspectorObject>* result)
{
String objectGroupName = objectGroup ? *objectGroup : "";
Modified: trunk/Source/WebCore/inspector/InspectorDOMAgent.h (90459 => 90460)
--- trunk/Source/WebCore/inspector/InspectorDOMAgent.h 2011-07-06 15:25:27 UTC (rev 90459)
+++ trunk/Source/WebCore/inspector/InspectorDOMAgent.h 2011-07-06 15:25:40 UTC (rev 90460)
@@ -136,6 +136,8 @@
void hideNodeHighlight(ErrorString* error) { hideHighlight(error); }
void highlightFrame(ErrorString*, const String& frameId);
void hideFrameHighlight(ErrorString* error) { hideHighlight(error); }
+ void moveTo(ErrorString*, int nodeId, int targetNodeId, const int* const anchorNodeId, int* newNodeId);
+
Node* highlightedNode() const { return m_highlightedNode.get(); }
// Methods called from the InspectorInstrumentation.
Modified: trunk/Source/WebCore/inspector/front-end/DOMAgent.js (90459 => 90460)
--- trunk/Source/WebCore/inspector/front-end/DOMAgent.js 2011-07-06 15:25:27 UTC (rev 90459)
+++ trunk/Source/WebCore/inspector/front-end/DOMAgent.js 2011-07-06 15:25:40 UTC (rev 90460)
@@ -259,7 +259,7 @@
return node;
},
- removeChild_: function(node)
+ _removeChild: function(node)
{
this.children.splice(this.children.indexOf(node), 1);
node.parentNode = null;
@@ -315,6 +315,11 @@
while (node.parentNode && !node.parentNode.documentURL)
node = node.parentNode;
return node;
+ },
+
+ moveTo: function(targetNode, anchorNode, callback)
+ {
+ DOMAgent.moveTo(this.id, targetNode.id, anchorNode ? anchorNode.id : undefined, callback);
}
}
@@ -535,7 +540,7 @@
{
var parent = this._idToDOMNode[parentId];
var node = this._idToDOMNode[nodeId];
- parent.removeChild_(node);
+ parent._removeChild(node);
this.dispatchEventToListeners(WebInspector.DOMAgent.Events.NodeRemoved, {node:node, parent:parent});
delete this._idToDOMNode[nodeId];
if (Preferences.nativeInstrumentationEnabled)
Modified: trunk/Source/WebCore/inspector/front-end/ElementsTreeOutline.js (90459 => 90460)
--- trunk/Source/WebCore/inspector/front-end/ElementsTreeOutline.js 2011-07-06 15:25:27 UTC (rev 90459)
+++ trunk/Source/WebCore/inspector/front-end/ElementsTreeOutline.js 2011-07-06 15:25:40 UTC (rev 90460)
@@ -33,6 +33,10 @@
this.element.addEventListener("mousedown", this._onmousedown.bind(this), false);
this.element.addEventListener("mousemove", this._onmousemove.bind(this), false);
this.element.addEventListener("mouseout", this._onmouseout.bind(this), false);
+ this.element.addEventListener("dragstart", this._ondragstart.bind(this), false);
+ this.element.addEventListener("dragover", this._ondragover.bind(this), false);
+ this.element.addEventListener("dragleave", this._ondragleave.bind(this), false);
+ this.element.addEventListener("dragend", this._ondragend.bind(this), false);
TreeOutline.call(this, this.element);
@@ -258,17 +262,143 @@
WebInspector.highlightDOMNode(0);
},
+ _ondragstart: function(event)
+ {
+ var treeElement = this._treeElementFromEvent(event);
+ if (!treeElement)
+ return false;
+
+ if (!this._isValidDragSourceOrTarget(treeElement))
+ return false;
+
+ if (treeElement.representedObject.nodeName() === "BODY" || treeElement.representedObject.nodeName() === "HEAD")
+ return false;
+
+ event.dataTransfer.setData("text/plain", treeElement.listItemElement.textContent);
+ event.dataTransfer.effectAllowed = "copy";
+ this._nodeBeingDragged = treeElement.representedObject;
+
+ WebInspector.highlightDOMNode(0);
+
+ return true;
+ },
+
+ _ondragover: function(event)
+ {
+ this._clearDragOverTreeElementMarker();
+
+ if (!this._nodeBeingDragged)
+ return;
+
+ var treeElement = this._treeElementFromEvent(event);
+ if (!this._isValidDragSourceOrTarget(treeElement))
+ return;
+
+ var node = treeElement.representedObject;
+ while (node) {
+ if (node === this._nodeBeingDragged)
+ return;
+ node = node.parentNode;
+ }
+
+ treeElement.updateSelection();
+ treeElement.listItemElement.addStyleClass("elements-drag-over");
+ this._dragOverTreeElement = treeElement;
+ },
+
+ _ondragleave: function(event)
+ {
+ this._clearDragOverTreeElementMarker();
+
+ if (!this._nodeBeingDragged)
+ return;
+
+ var treeElement = this._treeElementFromEvent(event);
+ if (!this._isValidDragSourceOrTarget(treeElement))
+ return false;
+
+ var node = treeElement.representedObject;
+ while (node) {
+ if (node === this._nodeBeingDragged)
+ return;
+ node = node.parentNode;
+ }
+
+ treeElement.updateSelection();
+ treeElement.listItemElement.addStyleClass("elements-drag-over");
+ this._dragOverTreeElement = treeElement;
+ },
+
+ _isValidDragSourceOrTarget: function(treeElement)
+ {
+ if (!treeElement)
+ return false;
+
+ var node = treeElement.representedObject;
+ if (!(node instanceof WebInspector.DOMNode))
+ return false;
+
+ if (node.nodeType() !== Node.ELEMENT_NODE)
+ return false;
+
+ if (!node.parentNode || node.parentNode.nodeType() !== Node.ELEMENT_NODE)
+ return false;
+
+ return true;
+ },
+
+ _ondragend: function(event)
+ {
+ if (this._nodeBeingDragged && this._dragOverTreeElement) {
+ var parentNode;
+ var anchorNode;
+
+ if (this._dragOverTreeElement._elementCloseTag) {
+ // Drop onto closing tag -> insert as last child.
+ parentNode = this._dragOverTreeElement.representedObject;
+ } else {
+ var dragTargetNode = this._dragOverTreeElement.representedObject;
+ parentNode = dragTargetNode.parentNode;
+ anchorNode = dragTargetNode;
+ }
+
+ function callback(error, newNodeId)
+ {
+ if (error)
+ return;
+
+ WebInspector.panels.elements.updateModifiedNodes();
+ var newNode = WebInspector.domAgent.nodeForId(newNodeId);
+ if (newNode)
+ this.focusedDOMNode = newNode;
+ }
+ this._nodeBeingDragged.moveTo(parentNode, anchorNode, callback.bind(this));
+ }
+
+ this._clearDragOverTreeElementMarker();
+ delete this._nodeBeingDragged;
+ },
+
+ _clearDragOverTreeElementMarker: function()
+ {
+ if (this._dragOverTreeElement) {
+ this._dragOverTreeElement.updateSelection();
+ this._dragOverTreeElement.listItemElement.removeStyleClass("elements-drag-over");
+ delete this._dragOverTreeElement;
+ }
+ },
+
populateContextMenu: function(contextMenu, event)
{
- var listItem = event.target.enclosingNodeOrSelfWithNodeName("LI");
- if (!listItem || !listItem.treeElement)
+ var treeElement = this._treeElementFromEvent(event);
+ if (!treeElement)
return false;
var populated;
if (this.showInElementsPanelEnabled) {
function focusElement()
{
- WebInspector.panels.elements.switchToAndFocus(listItem.treeElement.representedObject);
+ WebInspector.panels.elements.switchToAndFocus(treeElement.representedObject);
}
contextMenu.appendItem(WebInspector.UIString("Reveal in Elements Panel"), focusElement.bind(this));
populated = true;
@@ -278,15 +408,15 @@
var textNode = event.target.enclosingNodeOrSelfWithClass("webkit-html-text-node");
if (href)
populated = WebInspector.panels.elements.populateHrefContextMenu(contextMenu, event, href);
- if (tag && listItem.treeElement._populateTagContextMenu) {
+ if (tag && treeElement._populateTagContextMenu) {
if (populated)
contextMenu.appendSeparator();
- listItem.treeElement._populateTagContextMenu(contextMenu, event);
+ treeElement._populateTagContextMenu(contextMenu, event);
populated = true;
- } else if (textNode && listItem.treeElement._populateTextContextMenu) {
+ } else if (textNode && treeElement._populateTextContextMenu) {
if (populated)
contextMenu.appendSeparator();
- listItem.treeElement._populateTextContextMenu(contextMenu, textNode);
+ treeElement._populateTextContextMenu(contextMenu, textNode);
populated = true;
}
}
@@ -508,8 +638,8 @@
}
this.updateTitle();
-
this._preventFollowingLinksOnDoubleClick();
+ this.listItemElement.draggable = true;
},
_preventFollowingLinksOnDoubleClick: function()
Modified: trunk/Source/WebCore/inspector/front-end/inspector.css (90459 => 90460)
--- trunk/Source/WebCore/inspector/front-end/inspector.css 2011-07-06 15:25:27 UTC (rev 90459)
+++ trunk/Source/WebCore/inspector/front-end/inspector.css 2011-07-06 15:25:40 UTC (rev 90460)
@@ -1221,6 +1221,12 @@
background-color: rgb(212, 212, 212);
}
+.outline-disclosure li.elements-drag-over .selection {
+ display: block;
+ margin-top: -2px;
+ border-top: 2px solid rgb(56, 121, 217);
+}
+
.outline-disclosure ol:focus li.selected .selection {
background-color: rgb(56, 121, 217);
}