Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(190)

Side by Side Diff: Source/devtools/front_end/elements/ElementsTreeOutline.js

Issue 397303002: DevTools: [Elements] Implement shortcut-based node cut-copy-pasting (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Reset clipboard if node on it is removed Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. 2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com> 3 * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
4 * Copyright (C) 2009 Joseph Pecoraro 4 * Copyright (C) 2009 Joseph Pecoraro
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 9 *
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 this._eventSupport = new WebInspector.Object(); 64 this._eventSupport = new WebInspector.Object();
65 65
66 this._visible = false; 66 this._visible = false;
67 67
68 this.element.addEventListener("contextmenu", this._contextMenuEventFired.bin d(this), true); 68 this.element.addEventListener("contextmenu", this._contextMenuEventFired.bin d(this), true);
69 this._contextMenuCallback = contextMenuCallback; 69 this._contextMenuCallback = contextMenuCallback;
70 this._setPseudoClassCallback = setPseudoClassCallback; 70 this._setPseudoClassCallback = setPseudoClassCallback;
71 this._createNodeDecorators(); 71 this._createNodeDecorators();
72 } 72 }
73 73
74 /** @typedef {{node: !WebInspector.DOMNode, isCut: boolean}} */
75 WebInspector.ElementsTreeOutline.ClipboardData;
76
74 /** 77 /**
75 * @enum {string} 78 * @enum {string}
76 */ 79 */
77 WebInspector.ElementsTreeOutline.Events = { 80 WebInspector.ElementsTreeOutline.Events = {
78 SelectedNodeChanged: "SelectedNodeChanged", 81 SelectedNodeChanged: "SelectedNodeChanged",
79 ElementsTreeUpdated: "ElementsTreeUpdated" 82 ElementsTreeUpdated: "ElementsTreeUpdated"
80 } 83 }
81 84
82 /** 85 /**
83 * @const 86 * @const
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 wireToDOMModel: function() 140 wireToDOMModel: function()
138 { 141 {
139 this._elementsTreeUpdater = new WebInspector.ElementsTreeUpdater(this._t arget.domModel, this); 142 this._elementsTreeUpdater = new WebInspector.ElementsTreeUpdater(this._t arget.domModel, this);
140 }, 143 },
141 144
142 unwireFromDOMModel: function() 145 unwireFromDOMModel: function()
143 { 146 {
144 if (this._elementsTreeUpdater) 147 if (this._elementsTreeUpdater)
145 this._elementsTreeUpdater.dispose(); 148 this._elementsTreeUpdater.dispose();
146 }, 149 },
150
151 /**
152 * @param {?WebInspector.ElementsTreeOutline.ClipboardData} data
153 */
154 _setClipboardData: function(data)
155 {
156 if (this._clipboardNodeData) {
157 var treeElement = this.findTreeElement(this._clipboardNodeData.node) ;
158 if (treeElement)
159 treeElement.setInClipboard(false);
160 delete this._clipboardNodeData;
161 }
162
163 if (data) {
164 var treeElement = this.findTreeElement(data.node);
165 if (treeElement)
166 treeElement.setInClipboard(true);
167 this._clipboardNodeData = data;
168 }
169 },
170
171 /**
172 * @param {!WebInspector.DOMNode} removedNode
173 */
174 _resetClipboardIfNeeded: function(removedNode)
175 {
176 if (this._clipboardNodeData && this._clipboardNodeData.node === removedN ode)
177 this._setClipboardData(null);
178 },
179
180 /**
181 * @param {boolean} isCut
182 * @param {!Event} event
183 */
184 handleCopyOrCutKeyboardEvent: function(isCut, event)
185 {
186 this._setClipboardData(null);
187
188 // Do not interfere with text editing.
189 var currentFocusElement = WebInspector.currentFocusElement();
190 if (currentFocusElement && WebInspector.isBeingEdited(currentFocusElemen t))
191 return;
192
193 var targetNode = this.selectedDOMNode();
194 if (!targetNode)
195 return;
196
197 event.clipboardData.clearData();
198 event.preventDefault();
199
200 this._performCopyOrCut(isCut, targetNode);
201 },
202
203 /**
204 * @param {boolean} isCut
205 * @param {?WebInspector.DOMNode} node
206 */
207 _performCopyOrCut: function(isCut, node)
208 {
209 if (isCut && (node.isShadowRoot() || node.ancestorUserAgentShadowRoot()) )
210 return;
211
212 node.copyNode();
213 this._setClipboardData({ node: node, isCut: isCut });
214 },
215
216 /**
217 * @param {!WebInspector.DOMNode} targetNode
218 * @return {boolean}
219 */
220 _canPaste: function(targetNode)
221 {
222 if (targetNode.isShadowRoot() || targetNode.ancestorUserAgentShadowRoot( ))
223 return false;
224
225 if (!this._clipboardNodeData)
226 return false;
227
228 var node = this._clipboardNodeData.node;
229 if (this._clipboardNodeData.isCut && (node === targetNode || node.isAnce stor(targetNode)))
230 return false;
231
232 if (targetNode.target() !== node.target())
233 return false;
234 return true;
235 },
236
237 /**
238 * @param {!WebInspector.DOMNode} targetNode
239 */
240 _pasteNode: function(targetNode)
241 {
242 if (this._canPaste(targetNode))
243 this._performPaste(targetNode);
244 },
245
246 /**
247 * @param {!Event} event
248 */
249 handlePasteKeyboardEvent: function(event)
250 {
251 // Do not interfere with text editing.
252 var currentFocusElement = WebInspector.currentFocusElement();
253 if (currentFocusElement && WebInspector.isBeingEdited(currentFocusElemen t))
254 return;
255
256 var targetNode = this.selectedDOMNode();
257 if (!targetNode || !this._canPaste(targetNode))
258 return;
259
260 event.preventDefault();
261 this._performPaste(targetNode);
262 },
263
264 /**
265 * @param {!WebInspector.DOMNode} targetNode
266 */
267 _performPaste: function(targetNode)
268 {
269 if (this._clipboardNodeData.isCut) {
270 this._clipboardNodeData.node.moveTo(targetNode, null, expandCallback .bind(this));
271 this._setClipboardData(null);
272 } else {
273 this._clipboardNodeData.node.copyTo(targetNode, null, expandCallback .bind(this));
274 }
275
276 /**
277 * @param {?Protocol.Error} error
278 * @param {!DOMAgent.NodeId} nodeId
279 * @this {WebInspector.ElementsTreeOutline}
280 */
281 function expandCallback(error, nodeId)
282 {
283 if (error)
284 return;
285 var pastedNode = this._domModel.nodeForId(nodeId);
286 if (!pastedNode)
287 return;
288 this.selectDOMNode(pastedNode);
289 }
290 },
291
147 /** 292 /**
148 * @param {boolean} visible 293 * @param {boolean} visible
149 */ 294 */
150 setVisible: function(visible) 295 setVisible: function(visible)
151 { 296 {
152 this._visible = visible; 297 this._visible = visible;
153 if (!this._visible) 298 if (!this._visible)
154 return; 299 return;
155 300
156 this._updateModifiedNodes(); 301 this._updateModifiedNodes();
(...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 var commentNode = event.target.enclosingNodeOrSelfWithClass("webkit-html -comment"); 751 var commentNode = event.target.enclosingNodeOrSelfWithClass("webkit-html -comment");
607 contextMenu.appendApplicableItems(event.target); 752 contextMenu.appendApplicableItems(event.target);
608 if (textNode) { 753 if (textNode) {
609 contextMenu.appendSeparator(); 754 contextMenu.appendSeparator();
610 treeElement._populateTextContextMenu(contextMenu, textNode); 755 treeElement._populateTextContextMenu(contextMenu, textNode);
611 } else if (isTag) { 756 } else if (isTag) {
612 contextMenu.appendSeparator(); 757 contextMenu.appendSeparator();
613 treeElement._populateTagContextMenu(contextMenu, event); 758 treeElement._populateTagContextMenu(contextMenu, event);
614 } else if (commentNode) { 759 } else if (commentNode) {
615 contextMenu.appendSeparator(); 760 contextMenu.appendSeparator();
616 treeElement._populateNodeContextMenu(contextMenu, textNode); 761 treeElement._populateNodeContextMenu(contextMenu);
617 } else if (isPseudoElement) { 762 } else if (isPseudoElement) {
618 treeElement._populateScrollIntoView(contextMenu); 763 treeElement._populateScrollIntoView(contextMenu);
619 } else if (treeElement._node.isShadowRoot()) { 764 } else if (treeElement._node.isShadowRoot()) {
620 this.treeOutline._populateContextMenu(contextMenu, treeElement._node ); 765 this.treeOutline._populateContextMenu(contextMenu, treeElement._node );
621 } 766 }
622 }, 767 },
623 768
624 _updateModifiedNodes: function() 769 _updateModifiedNodes: function()
625 { 770 {
626 if (this._elementsTreeUpdater) 771 if (this._elementsTreeUpdater)
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after
913 // Preserve the semantic of node by following the order of updates for h ide and show. 1058 // Preserve the semantic of node by following the order of updates for h ide and show.
914 if (show) { 1059 if (show) {
915 for (var i = 0, size = this._highlightResult.length; i < size; ++i) 1060 for (var i = 0, size = this._highlightResult.length; i < size; ++i)
916 updateEntryShow(this._highlightResult[i]); 1061 updateEntryShow(this._highlightResult[i]);
917 } else { 1062 } else {
918 for (var i = (this._highlightResult.length - 1); i >= 0; --i) 1063 for (var i = (this._highlightResult.length - 1); i >= 0; --i)
919 updateEntryHide(this._highlightResult[i]); 1064 updateEntryHide(this._highlightResult[i]);
920 } 1065 }
921 }, 1066 },
922 1067
1068 /**
1069 * @param {boolean} inClipboard
1070 */
1071 setInClipboard: function(inClipboard)
1072 {
1073 if (this._inClipboard === inClipboard)
1074 return;
1075 this._inClipboard = inClipboard;
1076 this.listItemElement.classList.toggle("in-clipboard", inClipboard);
1077 },
1078
923 get hovered() 1079 get hovered()
924 { 1080 {
925 return this._hovered; 1081 return this._hovered;
926 }, 1082 },
927 1083
928 set hovered(x) 1084 set hovered(x)
929 { 1085 {
930 if (this._hovered === x) 1086 if (this._hovered === x)
931 return; 1087 return;
932 1088
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after
1446 }, 1602 },
1447 1603
1448 _populateNodeContextMenu: function(contextMenu) 1604 _populateNodeContextMenu: function(contextMenu)
1449 { 1605 {
1450 // Add free-form node-related actions. 1606 // Add free-form node-related actions.
1451 var openTagElement = this.treeOutline.getCachedTreeElement(this.represen tedObject) || this; 1607 var openTagElement = this.treeOutline.getCachedTreeElement(this.represen tedObject) || this;
1452 var isEditable = this.hasEditableNode(); 1608 var isEditable = this.hasEditableNode();
1453 if (isEditable && !this._editing) 1609 if (isEditable && !this._editing)
1454 contextMenu.appendItem(WebInspector.UIString("Edit as HTML"), openTa gElement._editAsHTML.bind(openTagElement)); 1610 contextMenu.appendItem(WebInspector.UIString("Edit as HTML"), openTa gElement._editAsHTML.bind(openTagElement));
1455 var isShadowRoot = this.representedObject.isShadowRoot(); 1611 var isShadowRoot = this.representedObject.isShadowRoot();
1456 if (!isShadowRoot)
1457 contextMenu.appendItem(WebInspector.UIString("Copy as HTML"), this._ copyHTML.bind(this));
1458 1612
1459 // Place it here so that all "Copy"-ing items stick together. 1613 // Place it here so that all "Copy"-ing items stick together.
1460 if (this.representedObject.nodeType() === Node.ELEMENT_NODE) 1614 if (this.representedObject.nodeType() === Node.ELEMENT_NODE)
1461 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCa seMenuTitles() ? "Copy CSS path" : "Copy CSS Path"), this._copyCSSPath.bind(this )); 1615 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCa seMenuTitles() ? "Copy CSS path" : "Copy CSS Path"), this._copyCSSPath.bind(this ));
1462 if (!isShadowRoot) 1616 if (!isShadowRoot)
1463 contextMenu.appendItem(WebInspector.UIString("Copy XPath"), this._co pyXPath.bind(this)); 1617 contextMenu.appendItem(WebInspector.UIString("Copy XPath"), this._co pyXPath.bind(this));
1618 if (!isShadowRoot) {
1619 var treeOutline = this.treeOutline;
1620 contextMenu.appendItem(WebInspector.UIString("Copy"), treeOutline._p erformCopyOrCut.bind(treeOutline, false, this.representedObject));
1621 contextMenu.appendItem(WebInspector.UIString("Cut"), treeOutline._pe rformCopyOrCut.bind(treeOutline, true, this.representedObject), !this.hasEditabl eNode());
1622 contextMenu.appendItem(WebInspector.UIString("Paste"), treeOutline._ pasteNode.bind(treeOutline, this.representedObject), !treeOutline._canPaste(this .representedObject));
1623 }
1624
1464 if (isEditable) 1625 if (isEditable)
1465 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCa seMenuTitles() ? "Delete node" : "Delete Node"), this.remove.bind(this)); 1626 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCa seMenuTitles() ? "Delete node" : "Delete Node"), this.remove.bind(this));
1466 }, 1627 },
1467 1628
1468 _startEditing: function() 1629 _startEditing: function()
1469 { 1630 {
1470 if (this.treeOutline.selectedDOMNode() !== this._node) 1631 if (this.treeOutline.selectedDOMNode() !== this._node)
1471 return; 1632 return;
1472 1633
1473 var listItem = this._listItemNode; 1634 var listItem = this._listItemNode;
(...skipping 866 matching lines...) Expand 10 before | Expand all | Expand 10 after
2340 */ 2501 */
2341 function commitChange(initialValue, value) 2502 function commitChange(initialValue, value)
2342 { 2503 {
2343 if (initialValue !== value) 2504 if (initialValue !== value)
2344 node.setOuterHTML(value, selectNode); 2505 node.setOuterHTML(value, selectNode);
2345 } 2506 }
2346 2507
2347 node.getOuterHTML(this._startEditingAsHTML.bind(this, commitChange)); 2508 node.getOuterHTML(this._startEditingAsHTML.bind(this, commitChange));
2348 }, 2509 },
2349 2510
2350 _copyHTML: function()
2351 {
2352 this._node.copyNode();
2353 },
2354
2355 _copyCSSPath: function() 2511 _copyCSSPath: function()
2356 { 2512 {
2357 InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.cssPath (this._node, true)); 2513 InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.cssPath (this._node, true));
2358 }, 2514 },
2359 2515
2360 _copyXPath: function() 2516 _copyXPath: function()
2361 { 2517 {
2362 InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.xPath(t his._node, true)); 2518 InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.xPath(t his._node, true));
2363 }, 2519 },
2364 2520
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
2544 this._nodeModified(event.data, true); 2700 this._nodeModified(event.data, true);
2545 }, 2701 },
2546 2702
2547 _nodeInserted: function(event) 2703 _nodeInserted: function(event)
2548 { 2704 {
2549 this._nodeModified(event.data, false, event.data.parentNode); 2705 this._nodeModified(event.data, false, event.data.parentNode);
2550 }, 2706 },
2551 2707
2552 _nodeRemoved: function(event) 2708 _nodeRemoved: function(event)
2553 { 2709 {
2710 this._treeOutline._resetClipboardIfNeeded(event.data.node);
2554 this._nodeModified(event.data.node, false, event.data.parent); 2711 this._nodeModified(event.data.node, false, event.data.parent);
2555 }, 2712 },
2556 2713
2557 _childNodeCountUpdated: function(event) 2714 _childNodeCountUpdated: function(event)
2558 { 2715 {
2559 var treeElement = this._treeOutline.findTreeElement(event.data); 2716 var treeElement = this._treeOutline.findTreeElement(event.data);
2560 if (treeElement) { 2717 if (treeElement) {
2561 var oldHasChildren = treeElement.hasChildren; 2718 var oldHasChildren = treeElement.hasChildren;
2562 treeElement._updateHasChildren(); 2719 treeElement._updateHasChildren();
2563 if (treeElement.hasChildren !== oldHasChildren) 2720 if (treeElement.hasChildren !== oldHasChildren)
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
2628 2785
2629 this._treeOutline._fireElementsTreeUpdated(nodes); 2786 this._treeOutline._fireElementsTreeUpdated(nodes);
2630 }, 2787 },
2631 2788
2632 _reset: function() 2789 _reset: function()
2633 { 2790 {
2634 this._treeOutline.rootDOMNode = null; 2791 this._treeOutline.rootDOMNode = null;
2635 this._treeOutline.selectDOMNode(null, false); 2792 this._treeOutline.selectDOMNode(null, false);
2636 this._domModel.hideDOMNodeHighlight(); 2793 this._domModel.hideDOMNodeHighlight();
2637 this._recentlyModifiedNodes.clear(); 2794 this._recentlyModifiedNodes.clear();
2795 delete this._treeOutline._clipboardNodeData;
2638 } 2796 }
2639 } 2797 }
2640 2798
2641 /** 2799 /**
2642 * @constructor 2800 * @constructor
2643 * @param {boolean} isUpdated 2801 * @param {boolean} isUpdated
2644 * @param {!WebInspector.DOMNode=} parent 2802 * @param {!WebInspector.DOMNode=} parent
2645 */ 2803 */
2646 WebInspector.ElementsTreeUpdater.UpdateEntry = function(isUpdated, parent) 2804 WebInspector.ElementsTreeUpdater.UpdateEntry = function(isUpdated, parent)
2647 { 2805 {
(...skipping 23 matching lines...) Expand all
2671 var treeOutline = new WebInspector.ElementsTreeOutline(node.target(), fa lse, false); 2829 var treeOutline = new WebInspector.ElementsTreeOutline(node.target(), fa lse, false);
2672 treeOutline.rootDOMNode = node; 2830 treeOutline.rootDOMNode = node;
2673 treeOutline.element.classList.add("outline-disclosure"); 2831 treeOutline.element.classList.add("outline-disclosure");
2674 if (!treeOutline.children[0].hasChildren) 2832 if (!treeOutline.children[0].hasChildren)
2675 treeOutline.element.classList.add("single-node"); 2833 treeOutline.element.classList.add("single-node");
2676 treeOutline.setVisible(true); 2834 treeOutline.setVisible(true);
2677 treeOutline.element.treeElementForTest = treeOutline.children[0]; 2835 treeOutline.element.treeElementForTest = treeOutline.children[0];
2678 return treeOutline.element; 2836 return treeOutline.element;
2679 } 2837 }
2680 } 2838 }
OLDNEW
« no previous file with comments | « Source/devtools/front_end/elements/ElementsPanel.js ('k') | Source/devtools/front_end/inspectorStyle.css » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698