Changeset 56683 in webkit
- Timestamp:
- Mar 28, 2010 1:49:39 AM (14 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r56676 r56683 1 2010-03-27 Joseph Pecoraro <joepeck@webkit.org> 2 3 Reviewed by Pavel Feldman. 4 5 Web Inspector: Edit Tag Names 6 https://bugs.webkit.org/show_bug.cgi?id=36481 7 8 Allow editing an Element's Tag Name by double clicking 9 on the tag name in the Element's Tree Hierarchy. 10 11 The usual asynchronous InspectorBackend, InspectorDOMAgent, InspectorFrontend flow. 12 13 * inspector/InspectorBackend.cpp: moved DOM manipulation to InspectorDOMAgent 14 (WebCore::InspectorBackend::removeNode): 15 (WebCore::InspectorBackend::changeTagName): 16 * inspector/InspectorBackend.h: 17 * inspector/InspectorBackend.idl: 18 * inspector/InspectorDOMAgent.cpp: 19 (WebCore::InspectorDOMAgent::removeNode): 20 (WebCore::InspectorDOMAgent::changeTagName): 21 * inspector/InspectorDOMAgent.h: 22 * inspector/InspectorFrontend.cpp: 23 (WebCore::InspectorFrontend::didChangeTagName): 24 * inspector/InspectorFrontend.h: 25 26 * inspector/front-end/DOMAgent.js: 27 28 Handle the UI for editing an Element's tag name. 29 30 * inspector/front-end/ElementsTreeOutline.js: 31 (WebInspector.ElementsTreeElement.prototype._startEditingFromEvent): allow editing from double click. 32 (WebInspector.ElementsTreeElement.prototype._startEditingTagName.keyupListener): update the closing tag 33 (WebInspector.ElementsTreeElement.prototype._startEditingTagName.editingComitted): remove extra listener and commit 34 (WebInspector.ElementsTreeElement.prototype._startEditingTagName.editingCancelled): remove extra listener and cancel 35 (WebInspector.ElementsTreeElement.prototype._startEditingTagName): 36 (WebInspector.ElementsTreeElement.prototype._tagNameEditingCommitted.cancel): 37 (WebInspector.ElementsTreeElement.prototype._tagNameEditingCommitted.moveToNextAttributeIfNeeded): 38 (WebInspector.ElementsTreeElement.prototype._tagNameEditingCommitted.editTagNameCallback): 39 (WebInspector.ElementsTreeElement.prototype._tagNameEditingCommitted): 40 (WebInspector.ElementsTreeElement.prototype._distinctClosingTagElement): get the closing tag for an opening tag 41 (WebInspector.ElementsTreeElement.prototype._nodeTitleInfo): wrap the tagName in span.webkit-html-tag-name 42 43 Miscellaneous updates. 44 45 * inspector/front-end/treeoutline.js: fixed a typo. 46 1 47 2010-03-27 Dmitry Gorbik <socket.h@gmail.com> 2 48 -
trunk/WebCore/inspector/InspectorBackend.cpp
r56107 r56683 327 327 Pasteboard::generalPasteboard()->writePlainText(markup); 328 328 } 329 329 330 330 void InspectorBackend::removeNode(long callId, long nodeId) 331 331 { 332 InspectorFrontend* frontend = inspectorFrontend(); 333 if (!frontend) 334 return; 335 336 Node* node = nodeForId(nodeId); 337 if (!node) { 338 // Use -1 to denote an error condition. 339 frontend->didRemoveNode(callId, -1); 340 return; 341 } 342 343 Node* parentNode = node->parentNode(); 344 if (!parentNode) { 345 frontend->didRemoveNode(callId, -1); 346 return; 347 } 348 349 ExceptionCode code; 350 parentNode->removeChild(node, code); 351 if (code) { 352 frontend->didRemoveNode(callId, -1); 353 return; 354 } 355 356 frontend->didRemoveNode(callId, nodeId); 332 if (InspectorDOMAgent* domAgent = inspectorDOMAgent()) 333 domAgent->removeNode(callId, nodeId); 334 } 335 336 void InspectorBackend::changeTagName(long callId, long nodeId, const AtomicString& tagName, bool expanded) 337 { 338 if (InspectorDOMAgent* domAgent = inspectorDOMAgent()) 339 domAgent->changeTagName(callId, nodeId, tagName, expanded); 357 340 } 358 341 -
trunk/WebCore/inspector/InspectorBackend.h
r56107 r56683 7 7 * 8 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer. 10 10 * 2. Redistributions in binary form must reproduce the above copyright 11 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 12 * documentation and/or other materials provided with the distribution. 13 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 15 * from this software without specific prior written permission. 16 16 * 17 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY … … 113 113 void copyNode(long nodeId); 114 114 void removeNode(long callId, long nodeId); 115 void changeTagName(long callId, long nodeId, const AtomicString& tagName, bool expanded); 115 116 116 117 void getStyles(long callId, long nodeId, bool authOnly); -
trunk/WebCore/inspector/InspectorBackend.idl
r56107 r56683 88 88 void copyNode(in long nodeId); 89 89 void removeNode(in long callId, in long nodeId); 90 void changeTagName(in long callId, in long nodeId, in DOMString newTagName, in boolean expanded); 90 91 void highlightDOMNode(in long nodeId); 91 92 void hideDOMNodeHighlight(); -
trunk/WebCore/inspector/InspectorDOMAgent.cpp
r56670 r56683 353 353 } 354 354 355 void InspectorDOMAgent::removeNode(long callId, long nodeId) 356 { 357 Node* node = nodeForId(nodeId); 358 if (!node) { 359 // Use -1 to denote an error condition. 360 m_frontend->didRemoveNode(callId, -1); 361 return; 362 } 363 364 Node* parentNode = node->parentNode(); 365 if (!parentNode) { 366 m_frontend->didRemoveNode(callId, -1); 367 return; 368 } 369 370 ExceptionCode code; 371 parentNode->removeChild(node, code); 372 if (code) { 373 m_frontend->didRemoveNode(callId, -1); 374 return; 375 } 376 377 m_frontend->didRemoveNode(callId, nodeId); 378 } 379 380 void InspectorDOMAgent::changeTagName(long callId, long nodeId, const AtomicString& tagName, bool expanded) 381 { 382 Node* oldNode = nodeForId(nodeId); 383 if (!oldNode || !oldNode->isElementNode()) { 384 // Use -1 to denote an error condition. 385 m_frontend->didChangeTagName(callId, -1); 386 return; 387 } 388 389 ExceptionCode code = 0; 390 RefPtr<Element> newElem = oldNode->document()->createElement(tagName, code); 391 if (code) { 392 m_frontend->didChangeTagName(callId, -1); 393 return; 394 } 395 396 // Copy over the original node's attributes. 397 Element* oldElem = static_cast<Element*>(oldNode); 398 newElem->copyNonAttributeProperties(oldElem); 399 if (oldElem->attributes()) 400 newElem->attributes()->setAttributes(*(oldElem->attributes(true))); 401 402 // Copy over the original node's children. 403 Node* child; 404 while ((child = oldNode->firstChild())) 405 newElem->appendChild(child, code); 406 407 // Replace the old node with the new node 408 Node* parent = oldNode->parentNode(); 409 parent->insertBefore(newElem, oldNode->nextSibling(), code); 410 parent->removeChild(oldNode, code); 411 412 if (code) { 413 m_frontend->didChangeTagName(callId, -1); 414 return; 415 } 416 417 long newId = pushNodePathToFrontend(newElem.get()); 418 if (expanded) 419 pushChildNodesToFrontend(newId); 420 m_frontend->didChangeTagName(callId, newId); 421 } 422 355 423 void InspectorDOMAgent::setTextNodeValue(long callId, long nodeId, const String& value) 356 424 { -
trunk/WebCore/inspector/InspectorDOMAgent.h
r56608 r56683 97 97 void setAttribute(long callId, long elementId, const String& name, const String& value); 98 98 void removeAttribute(long callId, long elementId, const String& name); 99 void removeNode(long callId, long nodeId); 100 void changeTagName(long callId, long nodeId, const AtomicString& tagName, bool expanded); 99 101 void setTextNodeValue(long callId, long nodeId, const String& value); 100 102 void getEventListenersForNode(long callId, long nodeId); -
trunk/WebCore/inspector/InspectorFrontend.cpp
r56670 r56683 471 471 } 472 472 473 void InspectorFrontend::didChangeTagName(long callId, long nodeId) 474 { 475 ScriptFunctionCall function(m_webInspector, "dispatch"); 476 function.appendArgument("didChangeTagName"); 477 function.appendArgument(callId); 478 function.appendArgument(nodeId); 479 function.call(); 480 } 481 473 482 void InspectorFrontend::didGetChildNodes(long callId) 474 483 { -
trunk/WebCore/inspector/InspectorFrontend.h
r56670 r56683 133 133 void didGetEventListenersForNode(long callId, long nodeId, const ScriptArray& listenersArray); 134 134 void didRemoveNode(long callId, long nodeId); 135 void didChangeTagName(long callId, long nodeId); 135 136 136 137 void didGetStyles(long callId, const ScriptValue& styles); -
trunk/WebCore/inspector/front-end/DOMAgent.js
r56383 r56683 677 677 WebInspector.didSetTextNodeValue = WebInspector.Callback.processCallback; 678 678 WebInspector.didRemoveNode = WebInspector.Callback.processCallback; 679 WebInspector.didChangeTagName = WebInspector.Callback.processCallback; 679 680 WebInspector.didGetEventListenersForNode = WebInspector.Callback.processCallback; 680 681 -
trunk/WebCore/inspector/front-end/ElementsTreeOutline.js
r56446 r56683 219 219 return element; 220 220 }, 221 221 222 222 _keyDown: function(event) 223 223 { … … 478 478 this.updateChildren(); 479 479 }, 480 480 481 481 updateChildren: function(fullRefresh) 482 482 { … … 671 671 return; 672 672 673 if (this.treeOutline.showInElementsPanelEnabled) { 673 if (this.treeOutline.showInElementsPanelEnabled) { 674 674 WebInspector.showElementsPanel(); 675 675 WebInspector.panels.elements.focusedDOMNode = this.representedObject; … … 724 724 return this._startEditingAttribute(attribute, event.target); 725 725 726 if (this.treeOutline.isXMLMimeType || !WebInspector.ElementsTreeElement.EditTagBlacklist[this.representedObject.localName]) { 727 var tagName = event.target.enclosingNodeOrSelfWithClass("webkit-html-tag-name"); 728 if (tagName) 729 return this._startEditingTagName(tagName); 730 } 731 726 732 var newAttribute = event.target.enclosingNodeOrSelfWithClass("add-attribute"); 727 733 if (newAttribute) … … 742 748 contextMenu.appendSeparator(); 743 749 744 // Add node-related actions.750 // Add free-form node-related actions. 745 751 contextMenu.appendItem(WebInspector.UIString("Edit as HTML"), this._editAsHTML.bind(this)); 746 752 contextMenu.appendItem(WebInspector.UIString("Copy as HTML"), this._copyHTML.bind(this)); … … 857 863 window.getSelection().setBaseAndExtent(textNode, 0, textNode, 1); 858 864 865 return true; 866 }, 867 868 _startEditingTagName: function(tagNameElement) 869 { 870 if (WebInspector.isBeingEdited(tagNameElement)) 871 return true; 872 873 this._editing = true; 874 875 var closingTagElement = this._distinctClosingTagElement(); 876 877 function keyupListener(event) 878 { 879 if (closingTagElement) 880 closingTagElement.textContent = "</" + tagNameElement.textContent + ">"; 881 } 882 883 function editingComitted(element, newTagName) 884 { 885 tagNameElement.removeEventListener('keyup', keyupListener, false); 886 this._tagNameEditingCommitted.apply(this, arguments); 887 } 888 889 function editingCancelled() 890 { 891 tagNameElement.removeEventListener('keyup', keyupListener, false); 892 this._editingCancelled.apply(this, arguments); 893 } 894 895 tagNameElement.addEventListener('keyup', keyupListener, false); 896 897 WebInspector.startEditing(tagNameElement, editingComitted.bind(this), editingCancelled.bind(this), tagNameElement.textContent); 898 window.getSelection().setBaseAndExtent(tagNameElement, 0, tagNameElement, 1); 859 899 return true; 860 900 }, … … 947 987 this._triggerEditAttribute(moveToAttribute); 948 988 else if (newAttribute) 949 this._addNewAttribute( this.listItemElement);989 this._addNewAttribute(); 950 990 } 951 991 … … 983 1023 }, 984 1024 1025 _tagNameEditingCommitted: function(element, newText, oldText, tagName, moveDirection) 1026 { 1027 delete this._editing; 1028 var self = this; 1029 1030 function cancel() 1031 { 1032 var closingTagElement = self._distinctClosingTagElement(); 1033 if (closingTagElement) 1034 closingTagElement.textContent = "</" + tagName + ">"; 1035 1036 self._editingCancelled(element, tagName); 1037 moveToNextAttributeIfNeeded.call(self); 1038 } 1039 1040 function moveToNextAttributeIfNeeded() 1041 { 1042 if (moveDirection !== "forward") 1043 return; 1044 1045 var attributes = this.representedObject.attributes; 1046 if (attributes.length > 0) 1047 this._triggerEditAttribute(attributes[0].name); 1048 else 1049 this._addNewAttribute(); 1050 } 1051 1052 newText = newText.trim(); 1053 if (newText === oldText) { 1054 cancel(); 1055 return; 1056 } 1057 1058 var treeOutline = this.treeOutline; 1059 var wasExpanded = this.expanded; 1060 1061 function changeTagNameCallback(nodeId) 1062 { 1063 if (nodeId === -1) { 1064 cancel(); 1065 return; 1066 } 1067 1068 // Select it and expand if necessary. We force tree update so that it processes dom events and is up to date. 1069 WebInspector.panels.elements.updateModifiedNodes(); 1070 1071 WebInspector.updateFocusedNode(nodeId); 1072 var newTreeItem = treeOutline.findTreeElement(WebInspector.domAgent.nodeForId(nodeId)); 1073 if (wasExpanded) 1074 newTreeItem.expand(); 1075 1076 moveToNextAttributeIfNeeded.call(newTreeItem); 1077 } 1078 1079 var callId = WebInspector.Callback.wrap(changeTagNameCallback); 1080 InspectorBackend.changeTagName(callId, this.representedObject.id, newText, wasExpanded); 1081 }, 1082 985 1083 _textNodeEditingCommitted: function(element, newText) 986 1084 { … … 1009 1107 }, 1010 1108 1109 _distinctClosingTagElement: function() 1110 { 1111 // FIXME: Improve the Tree Element / Outline Abstraction to prevent crawling the DOM 1112 1113 // For an expanded element, it will be the last element with class "close" 1114 // in the child element list. 1115 if (this.expanded) { 1116 var closers = this._childrenListNode.querySelectorAll(".close"); 1117 return closers[closers.length-1]; 1118 } 1119 1120 // Remaining cases are single line non-expanded elements with a closing 1121 // tag, or HTML elements without a closing tag (such as <br>). Return 1122 // null in the case where there isn't a closing tag. 1123 var tags = this.listItemElement.getElementsByClassName("webkit-html-tag"); 1124 return (tags.length === 1 ? null : tags[tags.length-1]); 1125 }, 1126 1011 1127 updateTitle: function() 1012 1128 { … … 1061 1177 var node = this.representedObject; 1062 1178 var info = {title: "", hasChildren: this.hasChildren}; 1063 1179 1064 1180 switch (node.nodeType) { 1065 1181 case Node.DOCUMENT_NODE: 1066 1182 info.title = "Document"; 1067 1183 break; 1068 1184 1069 1185 case Node.DOCUMENT_FRAGMENT_NODE: 1070 1186 info.title = "Document Fragment"; … … 1073 1189 case Node.ELEMENT_NODE: 1074 1190 var tagName = this.treeOutline.nodeNameToCorrectCase(node.nodeName).escapeHTML(); 1075 info.title = "<span class=\"webkit-html-tag\"><" + tagName;1076 1191 info.title = "<span class=\"webkit-html-tag\"><"; 1192 info.title += "<span class=\"webkit-html-tag-name\">" + tagName + "</span>"; 1077 1193 if (node.hasAttributes()) { 1078 1194 for (var i = 0; i < node.attributes.length; ++i) { 1079 1195 var attr = node.attributes[i]; 1080 1196 info.title += " <span class=\"webkit-html-attribute\"><span class=\"webkit-html-attribute-name\">" + attr.name.escapeHTML() + "</span>=​\""; 1081 1197 1082 1198 var value = attr.value; 1083 1199 if (linkify && (attr.name === "src" || attr.name === "href")) { … … 1093 1209 } 1094 1210 info.title += "></span>​"; 1095 1211 1096 1212 const closingTagHTML = "<span class=\"webkit-html-tag\"></" + tagName + "></span>​"; 1097 1213 var textChild = onlyTextChild.call(node); … … 1112 1228 } 1113 1229 break; 1114 1230 1115 1231 case Node.TEXT_NODE: 1116 1232 if (isNodeWhitespace.call(node)) … … 1131 1247 var cssSyntaxHighlighter = new WebInspector.DOMSyntaxHighlighter("text/css"); 1132 1248 cssSyntaxHighlighter.syntaxHighlightNode(newNode); 1133 1249 1134 1250 info.title = "<span class=\"webkit-html-text-node webkit-html-css-node\">" + newNode.innerHTML.replace(/^[\n\r]*/, "").replace(/\s*$/, "") + "</span>"; 1135 1251 } else { 1136 info.title = "\"<span class=\"webkit-html-text-node\">" + node.nodeValue.escapeHTML() + "</span>\""; 1252 info.title = "\"<span class=\"webkit-html-text-node\">" + node.nodeValue.escapeHTML() + "</span>\""; 1137 1253 } 1138 } 1254 } 1139 1255 break; 1140 1256 … … 1248 1364 1249 1365 WebInspector.ElementsTreeElement.prototype.__proto__ = TreeElement.prototype; 1366 1367 WebInspector.ElementsTreeElement.EditTagBlacklist = ["html", "head", "body"].keySet(); -
trunk/WebCore/inspector/front-end/treeoutline.js
r53053 r56683 288 288 return cachedElement; 289 289 290 // The representedObject isn't know , so we start at the top of the tree and work down to find the first290 // The representedObject isn't known, so we start at the top of the tree and work down to find the first 291 291 // tree element that represents representedObject or one of its ancestors. 292 292 var item;
Note: See TracChangeset
for help on using the changeset viewer.