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

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: Address comments Created 6 years, 5 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} node
173 */
174 _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.
175 {
176 this._performCopyOrCut(true, node);
177 },
178
179 /**
180 * @param {!WebInspector.DOMNode} node
181 */
182 _copyNode: function(node)
aandrey 2014/07/25 15:44:27 ditto
apavlov 2014/07/25 16:09:56 Done.
183 {
184 this._performCopyOrCut(false, node);
185 },
186
187 /**
188 * @param {boolean} isCut
189 * @param {!Event} event
190 */
191 handleCopyOrCutKeyboardEvent: function(isCut, event)
192 {
193 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
194
195 // Do not interfere with text editing.
196 var currentFocusElement = WebInspector.currentFocusElement();
197 if (currentFocusElement && WebInspector.isBeingEdited(currentFocusElemen t))
198 return;
199
200 var targetNode = this.selectedDOMNode();
201 if (!targetNode)
202 return;
203
204 if (isCut && (targetNode.isShadowRoot() || targetNode.ancestorUserAgentS hadowRoot()))
205 return;
206
207 event.clipboardData.clearData();
208 event.preventDefault();
209 this._performCopyOrCut(isCut, targetNode);
210 },
211
212 /**
213 * @param {boolean} isCut
214 * @param {?WebInspector.DOMNode} node
215 */
216 _performCopyOrCut: function(isCut, node)
217 {
218 node.copyNode();
219 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.
220 },
221
222 /**
223 * @param {!WebInspector.DOMNode} targetNode
224 * @return {boolean}
225 */
226 _canPaste: function(targetNode)
227 {
228 if (targetNode.isShadowRoot() || targetNode.ancestorUserAgentShadowRoot( ))
229 return false;
230
231 if (!this._clipboardNodeData)
232 return false;
233
234 var node = this._clipboardNodeData.node;
235 if (this._clipboardNodeData.isCut && (node === targetNode || node.isAnce stor(targetNode)))
236 return false;
237
238 if (targetNode.target() !== node.target())
239 return false;
240 return true;
241 },
242
243 /**
244 * @param {!WebInspector.DOMNode} targetNode
245 */
246 _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.
247 {
248 this._performPaste(targetNode);
249 },
250
251 /**
252 * @param {!Event} event
253 */
254 handlePasteKeyboardEvent: function(event)
255 {
256 // Do not interfere with text editing.
257 var currentFocusElement = WebInspector.currentFocusElement();
258 if (currentFocusElement && WebInspector.isBeingEdited(currentFocusElemen t))
259 return;
260
261 var targetNode = this.selectedDOMNode();
262 if (!targetNode || !this._canPaste(targetNode))
263 return;
264
265 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.
266 this._performPaste(targetNode);
267 },
268
269 /**
270 * @param {!WebInspector.DOMNode} targetNode
271 */
272 _performPaste: function(targetNode)
273 {
274 if (this._clipboardNodeData.isCut) {
275 this._clipboardNodeData.node.moveTo(targetNode, null, expandCallback .bind(this));
276 this._setClipboardData(null);
277 } else {
278 this._clipboardNodeData.node.copyTo(targetNode, null, expandCallback .bind(this));
279 }
280
281 /**
282 * @param {?Protocol.Error} error
283 * @param {!DOMAgent.NodeId} nodeId
284 * @this {WebInspector.ElementsTreeOutline}
285 */
286 function expandCallback(error, nodeId)
287 {
288 if (error)
289 return;
290 var pastedNode = this._domModel.nodeForId(nodeId);
291 if (!pastedNode)
292 return;
293 this.selectDOMNode(pastedNode);
294 }
295 },
296
147 /** 297 /**
148 * @param {boolean} visible 298 * @param {boolean} visible
149 */ 299 */
150 setVisible: function(visible) 300 setVisible: function(visible)
151 { 301 {
152 this._visible = visible; 302 this._visible = visible;
153 if (!this._visible) 303 if (!this._visible)
154 return; 304 return;
155 305
156 this._updateModifiedNodes(); 306 this._updateModifiedNodes();
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 493
344 /** 494 /**
345 * @param {?WebInspector.DOMNode} node 495 * @param {?WebInspector.DOMNode} node
346 * @param {boolean} omitFocus 496 * @param {boolean} omitFocus
347 */ 497 */
348 _revealAndSelectNode: function(node, omitFocus) 498 _revealAndSelectNode: function(node, omitFocus)
349 { 499 {
350 if (this._suppressRevealAndSelect) 500 if (this._suppressRevealAndSelect)
351 return; 501 return;
352 502
503 this._updateModifiedNodes();
504
353 if (!this._includeRootDOMNode && node === this.rootDOMNode && this.rootD OMNode) 505 if (!this._includeRootDOMNode && node === this.rootDOMNode && this.rootD OMNode)
354 node = this.rootDOMNode.firstChild; 506 node = this.rootDOMNode.firstChild;
355 if (!node) 507 if (!node)
356 return; 508 return;
357 var treeElement = this.createTreeElementFor(node); 509 var treeElement = this.createTreeElementFor(node);
358 if (!treeElement) 510 if (!treeElement)
359 return; 511 return;
360 512
361 treeElement.revealAndSelect(omitFocus); 513 treeElement.revealAndSelect(omitFocus);
362 }, 514 },
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 var commentNode = event.target.enclosingNodeOrSelfWithClass("webkit-html -comment"); 758 var commentNode = event.target.enclosingNodeOrSelfWithClass("webkit-html -comment");
607 contextMenu.appendApplicableItems(event.target); 759 contextMenu.appendApplicableItems(event.target);
608 if (textNode) { 760 if (textNode) {
609 contextMenu.appendSeparator(); 761 contextMenu.appendSeparator();
610 treeElement._populateTextContextMenu(contextMenu, textNode); 762 treeElement._populateTextContextMenu(contextMenu, textNode);
611 } else if (isTag) { 763 } else if (isTag) {
612 contextMenu.appendSeparator(); 764 contextMenu.appendSeparator();
613 treeElement._populateTagContextMenu(contextMenu, event); 765 treeElement._populateTagContextMenu(contextMenu, event);
614 } else if (commentNode) { 766 } else if (commentNode) {
615 contextMenu.appendSeparator(); 767 contextMenu.appendSeparator();
616 treeElement._populateNodeContextMenu(contextMenu, textNode); 768 treeElement._populateNodeContextMenu(contextMenu);
617 } else if (isPseudoElement) { 769 } else if (isPseudoElement) {
618 treeElement._populateScrollIntoView(contextMenu); 770 treeElement._populateScrollIntoView(contextMenu);
619 } else if (treeElement._node.isShadowRoot()) { 771 } else if (treeElement._node.isShadowRoot()) {
620 this.treeOutline._populateContextMenu(contextMenu, treeElement._node ); 772 this.treeOutline._populateContextMenu(contextMenu, treeElement._node );
621 } 773 }
622 }, 774 },
623 775
624 _updateModifiedNodes: function() 776 _updateModifiedNodes: function()
625 { 777 {
626 if (this._elementsTreeUpdater) 778 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. 1065 // Preserve the semantic of node by following the order of updates for h ide and show.
914 if (show) { 1066 if (show) {
915 for (var i = 0, size = this._highlightResult.length; i < size; ++i) 1067 for (var i = 0, size = this._highlightResult.length; i < size; ++i)
916 updateEntryShow(this._highlightResult[i]); 1068 updateEntryShow(this._highlightResult[i]);
917 } else { 1069 } else {
918 for (var i = (this._highlightResult.length - 1); i >= 0; --i) 1070 for (var i = (this._highlightResult.length - 1); i >= 0; --i)
919 updateEntryHide(this._highlightResult[i]); 1071 updateEntryHide(this._highlightResult[i]);
920 } 1072 }
921 }, 1073 },
922 1074
1075 /**
1076 * @param {boolean} inClipboard
1077 */
1078 setInClipboard: function(inClipboard)
1079 {
1080 if (this._inClipboard === inClipboard)
1081 return;
1082 this._inClipboard = inClipboard;
1083 this.listItemElement.classList.toggle("in-clipboard", inClipboard);
1084 },
1085
923 get hovered() 1086 get hovered()
924 { 1087 {
925 return this._hovered; 1088 return this._hovered;
926 }, 1089 },
927 1090
928 set hovered(x) 1091 set hovered(x)
929 { 1092 {
930 if (this._hovered === x) 1093 if (this._hovered === x)
931 return; 1094 return;
932 1095
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after
1446 }, 1609 },
1447 1610
1448 _populateNodeContextMenu: function(contextMenu) 1611 _populateNodeContextMenu: function(contextMenu)
1449 { 1612 {
1450 // Add free-form node-related actions. 1613 // Add free-form node-related actions.
1451 var openTagElement = this.treeOutline.getCachedTreeElement(this.represen tedObject) || this; 1614 var openTagElement = this.treeOutline.getCachedTreeElement(this.represen tedObject) || this;
1452 var isEditable = this.hasEditableNode(); 1615 var isEditable = this.hasEditableNode();
1453 if (isEditable && !this._editing) 1616 if (isEditable && !this._editing)
1454 contextMenu.appendItem(WebInspector.UIString("Edit as HTML"), openTa gElement._editAsHTML.bind(openTagElement)); 1617 contextMenu.appendItem(WebInspector.UIString("Edit as HTML"), openTa gElement._editAsHTML.bind(openTagElement));
1455 var isShadowRoot = this.representedObject.isShadowRoot(); 1618 var isShadowRoot = this.representedObject.isShadowRoot();
1456 if (!isShadowRoot)
1457 contextMenu.appendItem(WebInspector.UIString("Copy as HTML"), this._ copyHTML.bind(this));
1458 1619
1459 // Place it here so that all "Copy"-ing items stick together. 1620 // Place it here so that all "Copy"-ing items stick together.
1460 if (this.representedObject.nodeType() === Node.ELEMENT_NODE) 1621 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 )); 1622 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCa seMenuTitles() ? "Copy CSS path" : "Copy CSS Path"), this._copyCSSPath.bind(this ));
1462 if (!isShadowRoot) 1623 if (!isShadowRoot)
1463 contextMenu.appendItem(WebInspector.UIString("Copy XPath"), this._co pyXPath.bind(this)); 1624 contextMenu.appendItem(WebInspector.UIString("Copy XPath"), this._co pyXPath.bind(this));
1625 if (!isShadowRoot) {
1626 var treeOutline = this.treeOutline;
1627 contextMenu.appendItem(WebInspector.UIString("Copy"), treeOutline._c opyNode.bind(treeOutline, this.representedObject));
1628 contextMenu.appendItem(WebInspector.UIString("Cut"), treeOutline._cu tNode.bind(treeOutline, this.representedObject), !this.hasEditableNode());
1629 contextMenu.appendItem(WebInspector.UIString("Paste"), treeOutline._ pasteNode.bind(treeOutline, this.representedObject), !treeOutline._canPaste(this .representedObject));
1630 }
1631
1464 if (isEditable) 1632 if (isEditable)
1465 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCa seMenuTitles() ? "Delete node" : "Delete Node"), this.remove.bind(this)); 1633 contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCa seMenuTitles() ? "Delete node" : "Delete Node"), this.remove.bind(this));
1466 }, 1634 },
1467 1635
1468 _startEditing: function() 1636 _startEditing: function()
1469 { 1637 {
1470 if (this.treeOutline.selectedDOMNode() !== this._node) 1638 if (this.treeOutline.selectedDOMNode() !== this._node)
1471 return; 1639 return;
1472 1640
1473 var listItem = this._listItemNode; 1641 var listItem = this._listItemNode;
(...skipping 866 matching lines...) Expand 10 before | Expand all | Expand 10 after
2340 */ 2508 */
2341 function commitChange(initialValue, value) 2509 function commitChange(initialValue, value)
2342 { 2510 {
2343 if (initialValue !== value) 2511 if (initialValue !== value)
2344 node.setOuterHTML(value, selectNode); 2512 node.setOuterHTML(value, selectNode);
2345 } 2513 }
2346 2514
2347 node.getOuterHTML(this._startEditingAsHTML.bind(this, commitChange)); 2515 node.getOuterHTML(this._startEditingAsHTML.bind(this, commitChange));
2348 }, 2516 },
2349 2517
2350 _copyHTML: function()
2351 {
2352 this._node.copyNode();
2353 },
2354
2355 _copyCSSPath: function() 2518 _copyCSSPath: function()
2356 { 2519 {
2357 InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.cssPath (this._node, true)); 2520 InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.cssPath (this._node, true));
2358 }, 2521 },
2359 2522
2360 _copyXPath: function() 2523 _copyXPath: function()
2361 { 2524 {
2362 InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.xPath(t his._node, true)); 2525 InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.xPath(t his._node, true));
2363 }, 2526 },
2364 2527
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after
2628 2791
2629 this._treeOutline._fireElementsTreeUpdated(nodes); 2792 this._treeOutline._fireElementsTreeUpdated(nodes);
2630 }, 2793 },
2631 2794
2632 _reset: function() 2795 _reset: function()
2633 { 2796 {
2634 this._treeOutline.rootDOMNode = null; 2797 this._treeOutline.rootDOMNode = null;
2635 this._treeOutline.selectDOMNode(null, false); 2798 this._treeOutline.selectDOMNode(null, false);
2636 this._domModel.hideDOMNodeHighlight(); 2799 this._domModel.hideDOMNodeHighlight();
2637 this._recentlyModifiedNodes.clear(); 2800 this._recentlyModifiedNodes.clear();
2801 delete this._treeOutline._clipboardNodeData;
2638 } 2802 }
2639 } 2803 }
2640 2804
2641 /** 2805 /**
2642 * @constructor 2806 * @constructor
2643 * @param {boolean} isUpdated 2807 * @param {boolean} isUpdated
2644 * @param {!WebInspector.DOMNode=} parent 2808 * @param {!WebInspector.DOMNode=} parent
2645 */ 2809 */
2646 WebInspector.ElementsTreeUpdater.UpdateEntry = function(isUpdated, parent) 2810 WebInspector.ElementsTreeUpdater.UpdateEntry = function(isUpdated, parent)
2647 { 2811 {
(...skipping 23 matching lines...) Expand all
2671 var treeOutline = new WebInspector.ElementsTreeOutline(node.target(), fa lse, false); 2835 var treeOutline = new WebInspector.ElementsTreeOutline(node.target(), fa lse, false);
2672 treeOutline.rootDOMNode = node; 2836 treeOutline.rootDOMNode = node;
2673 treeOutline.element.classList.add("outline-disclosure"); 2837 treeOutline.element.classList.add("outline-disclosure");
2674 if (!treeOutline.children[0].hasChildren) 2838 if (!treeOutline.children[0].hasChildren)
2675 treeOutline.element.classList.add("single-node"); 2839 treeOutline.element.classList.add("single-node");
2676 treeOutline.setVisible(true); 2840 treeOutline.setVisible(true);
2677 treeOutline.element.treeElementForTest = treeOutline.children[0]; 2841 treeOutline.element.treeElementForTest = treeOutline.children[0];
2678 return treeOutline.element; 2842 return treeOutline.element;
2679 } 2843 }
2680 } 2844 }
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