Chromium Code Reviews| Index: Source/devtools/front_end/elements/ElementsTreeOutline.js |
| diff --git a/Source/devtools/front_end/elements/ElementsTreeOutline.js b/Source/devtools/front_end/elements/ElementsTreeOutline.js |
| index 9cc824b7538c809813e0b79de20e8689cc68ab22..7d1c1876f991bee0436a090ce98a0b0b0bb09839 100644 |
| --- a/Source/devtools/front_end/elements/ElementsTreeOutline.js |
| +++ b/Source/devtools/front_end/elements/ElementsTreeOutline.js |
| @@ -71,6 +71,9 @@ WebInspector.ElementsTreeOutline = function(target, omitRootDOMNode, selectEnabl |
| this._createNodeDecorators(); |
| } |
| +/** @typedef {{node: !WebInspector.DOMNode, isCut: boolean}} */ |
| +WebInspector.ElementsTreeOutline.ClipboardData; |
| + |
| /** |
| * @enum {string} |
| */ |
| @@ -144,6 +147,153 @@ WebInspector.ElementsTreeOutline.prototype = { |
| if (this._elementsTreeUpdater) |
| this._elementsTreeUpdater.dispose(); |
| }, |
| + |
| + /** |
| + * @param {?WebInspector.ElementsTreeOutline.ClipboardData} data |
| + */ |
| + _setClipboardData: function(data) |
| + { |
| + if (this._clipboardNodeData) { |
| + var treeElement = this.findTreeElement(this._clipboardNodeData.node); |
| + if (treeElement) |
| + treeElement.setInClipboard(false); |
| + delete this._clipboardNodeData; |
| + } |
| + |
| + if (data) { |
| + var treeElement = this.findTreeElement(data.node); |
| + if (treeElement) |
| + treeElement.setInClipboard(true); |
| + this._clipboardNodeData = data; |
| + } |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.DOMNode} node |
| + */ |
| + _cutNode: function(node) |
|
aandrey
2014/07/25 15:44:27
remove this in favor of .bind(..., true)?
apavlov
2014/07/25 16:09:56
Done.
|
| + { |
| + this._performCopyOrCut(true, node); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.DOMNode} node |
| + */ |
| + _copyNode: function(node) |
|
aandrey
2014/07/25 15:44:27
ditto
apavlov
2014/07/25 16:09:56
Done.
|
| + { |
| + this._performCopyOrCut(false, node); |
| + }, |
| + |
| + /** |
| + * @param {boolean} isCut |
| + * @param {!Event} event |
| + */ |
| + handleCopyOrCutKeyboardEvent: function(isCut, event) |
| + { |
| + this._setClipboardData(null); |
|
aandrey
2014/07/25 15:44:26
should it be after all the returns?
apavlov
2014/07/25 16:09:57
Nope. We don't want users to go dizzy about having
|
| + |
| + // Do not interfere with text editing. |
| + var currentFocusElement = WebInspector.currentFocusElement(); |
| + if (currentFocusElement && WebInspector.isBeingEdited(currentFocusElement)) |
| + return; |
| + |
| + var targetNode = this.selectedDOMNode(); |
| + if (!targetNode) |
| + return; |
| + |
| + if (isCut && (targetNode.isShadowRoot() || targetNode.ancestorUserAgentShadowRoot())) |
| + return; |
| + |
| + event.clipboardData.clearData(); |
| + event.preventDefault(); |
| + this._performCopyOrCut(isCut, targetNode); |
| + }, |
| + |
| + /** |
| + * @param {boolean} isCut |
| + * @param {?WebInspector.DOMNode} node |
| + */ |
| + _performCopyOrCut: function(isCut, node) |
| + { |
| + node.copyNode(); |
| + this._setClipboardData({node: node, isCut: isCut}); |
|
aandrey
2014/07/25 15:44:27
nit: spaces after { and before }
apavlov
2014/07/25 16:09:57
Done.
|
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.DOMNode} targetNode |
| + * @return {boolean} |
| + */ |
| + _canPaste: function(targetNode) |
| + { |
| + if (targetNode.isShadowRoot() || targetNode.ancestorUserAgentShadowRoot()) |
| + return false; |
| + |
| + if (!this._clipboardNodeData) |
| + return false; |
| + |
| + var node = this._clipboardNodeData.node; |
| + if (this._clipboardNodeData.isCut && (node === targetNode || node.isAncestor(targetNode))) |
| + return false; |
| + |
| + if (targetNode.target() !== node.target()) |
| + return false; |
| + return true; |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.DOMNode} targetNode |
| + */ |
| + _pasteNode: function(targetNode) |
|
aandrey
2014/07/25 15:44:26
remove this (looks like the code would be a lot si
apavlov
2014/07/25 16:09:57
Done.
|
| + { |
| + this._performPaste(targetNode); |
| + }, |
| + |
| + /** |
| + * @param {!Event} event |
| + */ |
| + handlePasteKeyboardEvent: function(event) |
| + { |
| + // Do not interfere with text editing. |
| + var currentFocusElement = WebInspector.currentFocusElement(); |
| + if (currentFocusElement && WebInspector.isBeingEdited(currentFocusElement)) |
| + return; |
| + |
| + var targetNode = this.selectedDOMNode(); |
| + if (!targetNode || !this._canPaste(targetNode)) |
| + return; |
| + |
| + event.preventDefault(); |
|
aandrey
2014/07/25 15:44:27
maybe event.consume(false); ?
apavlov
2014/07/25 16:09:57
true, since we need to preventDefault(). Done.
|
| + this._performPaste(targetNode); |
| + }, |
| + |
| + /** |
| + * @param {!WebInspector.DOMNode} targetNode |
| + */ |
| + _performPaste: function(targetNode) |
| + { |
| + if (this._clipboardNodeData.isCut) { |
| + this._clipboardNodeData.node.moveTo(targetNode, null, expandCallback.bind(this)); |
| + this._setClipboardData(null); |
| + } else { |
| + this._clipboardNodeData.node.copyTo(targetNode, null, expandCallback.bind(this)); |
| + } |
| + |
| + /** |
| + * @param {?Protocol.Error} error |
| + * @param {!DOMAgent.NodeId} nodeId |
| + * @this {WebInspector.ElementsTreeOutline} |
| + */ |
| + function expandCallback(error, nodeId) |
| + { |
| + if (error) |
| + return; |
| + var pastedNode = this._domModel.nodeForId(nodeId); |
| + if (!pastedNode) |
| + return; |
| + this.selectDOMNode(pastedNode); |
| + } |
| + }, |
| + |
| /** |
| * @param {boolean} visible |
| */ |
| @@ -350,6 +500,8 @@ WebInspector.ElementsTreeOutline.prototype = { |
| if (this._suppressRevealAndSelect) |
| return; |
| + this._updateModifiedNodes(); |
| + |
| if (!this._includeRootDOMNode && node === this.rootDOMNode && this.rootDOMNode) |
| node = this.rootDOMNode.firstChild; |
| if (!node) |
| @@ -613,7 +765,7 @@ WebInspector.ElementsTreeOutline.prototype = { |
| treeElement._populateTagContextMenu(contextMenu, event); |
| } else if (commentNode) { |
| contextMenu.appendSeparator(); |
| - treeElement._populateNodeContextMenu(contextMenu, textNode); |
| + treeElement._populateNodeContextMenu(contextMenu); |
| } else if (isPseudoElement) { |
| treeElement._populateScrollIntoView(contextMenu); |
| } else if (treeElement._node.isShadowRoot()) { |
| @@ -920,6 +1072,17 @@ WebInspector.ElementsTreeElement.prototype = { |
| } |
| }, |
| + /** |
| + * @param {boolean} inClipboard |
| + */ |
| + setInClipboard: function(inClipboard) |
| + { |
| + if (this._inClipboard === inClipboard) |
| + return; |
| + this._inClipboard = inClipboard; |
| + this.listItemElement.classList.toggle("in-clipboard", inClipboard); |
| + }, |
| + |
| get hovered() |
| { |
| return this._hovered; |
| @@ -1453,14 +1616,19 @@ WebInspector.ElementsTreeElement.prototype = { |
| if (isEditable && !this._editing) |
| contextMenu.appendItem(WebInspector.UIString("Edit as HTML"), openTagElement._editAsHTML.bind(openTagElement)); |
| var isShadowRoot = this.representedObject.isShadowRoot(); |
| - if (!isShadowRoot) |
| - contextMenu.appendItem(WebInspector.UIString("Copy as HTML"), this._copyHTML.bind(this)); |
| // Place it here so that all "Copy"-ing items stick together. |
| if (this.representedObject.nodeType() === Node.ELEMENT_NODE) |
| contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy CSS path" : "Copy CSS Path"), this._copyCSSPath.bind(this)); |
| if (!isShadowRoot) |
| contextMenu.appendItem(WebInspector.UIString("Copy XPath"), this._copyXPath.bind(this)); |
| + if (!isShadowRoot) { |
| + var treeOutline = this.treeOutline; |
| + contextMenu.appendItem(WebInspector.UIString("Copy"), treeOutline._copyNode.bind(treeOutline, this.representedObject)); |
| + contextMenu.appendItem(WebInspector.UIString("Cut"), treeOutline._cutNode.bind(treeOutline, this.representedObject), !this.hasEditableNode()); |
| + contextMenu.appendItem(WebInspector.UIString("Paste"), treeOutline._pasteNode.bind(treeOutline, this.representedObject), !treeOutline._canPaste(this.representedObject)); |
| + } |
| + |
| if (isEditable) |
| contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Delete node" : "Delete Node"), this.remove.bind(this)); |
| }, |
| @@ -2347,11 +2515,6 @@ WebInspector.ElementsTreeElement.prototype = { |
| node.getOuterHTML(this._startEditingAsHTML.bind(this, commitChange)); |
| }, |
| - _copyHTML: function() |
| - { |
| - this._node.copyNode(); |
| - }, |
| - |
| _copyCSSPath: function() |
| { |
| InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.cssPath(this._node, true)); |
| @@ -2635,6 +2798,7 @@ WebInspector.ElementsTreeUpdater.prototype = { |
| this._treeOutline.selectDOMNode(null, false); |
| this._domModel.hideDOMNodeHighlight(); |
| this._recentlyModifiedNodes.clear(); |
| + delete this._treeOutline._clipboardNodeData; |
| } |
| } |