Changeset 35317 in webkit
- Timestamp:
- Jul 23, 2008 7:48:36 PM (16 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 3 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r35316 r35317 1 2008-07-23 Timothy Hatcher <timothy@apple.com> 2 3 Updates the elements DOM tree when nodes are added or removed from 4 the inspected document. 5 6 https://bugs.webkit.org/show_bug.cgi?id=6590 7 <rdar://problem/5712921> 8 9 Reviewed by Adam Roben. 10 11 * loader/FrameLoader.cpp: 12 (WebCore::FrameLoader::dispatchWindowObjectAvailable): Added a call to 13 InspectorController::inspectedWindowScriptObjectCleared. 14 * page/InspectorController.cpp: 15 (WebCore::InspectorController::inspectedWindowScriptObjectCleared): 16 Calls the WebInspector.inspectedWindowCleared script function. 17 * page/InspectorController.h: 18 * page/inspector/ElementsPanel.js: 19 (WebInspector.ElementsPanel): Create the event listener callback wrappers. 20 (WebInspector.ElementsPanel.prototype.show): Call _updateModifiedNodes if 21 there are any recently modified nodes. 22 (WebInspector.ElementsPanel.prototype.reset): Remove previous mutation event listeners. 23 Adds a check for InspectorController.isWindowVisible to prevent adding 24 event listeners when the window isn't visible. 25 (WebInspector.ElementsPanel.prototype.inspectedWindowCleared): 26 (WebInspector.ElementsPanel.prototype._addMutationEventListeners): Add DOMNodeInserted, 27 DOMNodeRemoved and DOMContentLoaded event listeners to the passed in window or window's document. 28 (WebInspector.ElementsPanel.prototype._removeMutationEventListeners): Removes the event listeners 29 added in _addMutationEventListeners. 30 (WebInspector.ElementsPanel.prototype.updateMutationEventListeners): Call _addMutationEventListeners 31 again to reinstate the listners if the document changed or window cleared them. 32 (WebInspector.ElementsPanel.prototype.registerMutationEventListeners): Append the window to 33 _mutationMonitoredWindows and call _addMutationEventListeners. 34 (WebInspector.ElementsPanel.prototype.unregisterMutationEventListeners): Remove the window from 35 _mutationMonitoredWindows and call _removeMutationEventListeners. 36 (WebInspector.ElementsPanel.prototype.unregisterAllMutationEventListeners): Call 37 _removeMutationEventListeners for all windows in _mutationMonitoredWindows and 38 clear _mutationMonitoredWindows. 39 (WebInspector.ElementsPanel.prototype._contentLoaded): Append the node and parent 40 to the recentlyModifiedNodes array. Call _updateModifiedNodesSoon if visible. 41 (WebInspector.ElementsPanel.prototype._nodeInserted): Ditto. 42 (WebInspector.ElementsPanel.prototype._nodeRemoved): Ditto. 43 (WebInspector.ElementsPanel.prototype._updateModifiedNodesSoon): Call 44 _updateModifiedNodes on a zero timeout. 45 (WebInspector.ElementsPanel.prototype._updateModifiedNodes): Iterate over 46 the recentlyModifiedNodes array and call updateChildren on all the parent 47 elements that had changes. Only calls updateChildren once per parent element. 48 (WebInspector.ElementsPanel.prototype._isAncestorIncludingParentFrames): Return 49 false if the nodes are the same. Return true if the nodes are the same while 50 looking at ancestor frame elements. THis use to return false, which was incorrect. 51 (WebInspector.DOMNodeTreeElement.prototype.onpopulate): Call updateChildren. 52 (WebInspector.DOMNodeTreeElement.prototype.updateChildren): Copied from 53 onpopulate and changed to rebuild the children elements by adding new children, 54 moving existing children and removed old children. 55 (WebInspector.DOMNodeTreeElement.prototype.onexpand): If the node has a contentDocument 56 call registerMutationEventListeners to track any mutations. 57 * page/inspector/inspector.js: 58 (WebInspector.inspectedWindowCleared): Call ElementsPanel.inspectedWindowCleared. 59 * page/inspector/treeoutline.js: 60 (TreeElement.prototype.get hasChildren): Return _hasChildren. 61 (TreeElement.prototype.set hasChildren): Set _hasChildren and update the className. 62 (TreeElement.prototype.hasAncestor): Return true if the element has the passed in ancestor. 63 (TreeElement.prototype.expand): Fix an exception that can happen if expand is 64 called before _attach. 65 * WebCore/manual-tests/inspector/dom-mutation.html: Added. 66 * WebCore/manual-tests/inspector/resources/mutate-frame-2.html: Added. 67 * WebCore/manual-tests/inspector/resources/mutate-frame.html: Added. 68 1 69 2008-07-22 Timothy Hatcher <timothy@apple.com> 2 70 -
trunk/WebCore/loader/FrameLoader.cpp
r35298 r35317 4785 4785 4786 4786 m_client->windowObjectCleared(); 4787 if (Page* page = m_frame->page()) 4787 4788 if (Page* page = m_frame->page()) { 4789 if (InspectorController* inspector = page->inspectorController()) 4790 inspector->inspectedWindowScriptObjectCleared(m_frame); 4788 4791 if (InspectorController* inspector = page->parentInspectorController()) 4789 4792 inspector->windowScriptObjectAvailable(); 4793 } 4790 4794 } 4791 4795 -
trunk/WebCore/page/InspectorController.cpp
r35314 r35317 1244 1244 } 1245 1245 1246 void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame) 1247 { 1248 if (!enabled() || !m_scriptContext || !m_scriptObject) 1249 return; 1250 1251 JSDOMWindow* win = toJSDOMWindow(frame); 1252 ExecState* exec = win->globalExec(); 1253 1254 JSValueRef arg0; 1255 1256 { 1257 KJS::JSLock lock(false); 1258 arg0 = toRef(JSInspectedObjectWrapper::wrap(exec, win)); 1259 } 1260 1261 JSValueRef exception = 0; 1262 callFunction(m_scriptContext, m_scriptObject, "inspectedWindowCleared", 1, &arg0, exception); 1263 } 1264 1246 1265 void InspectorController::windowScriptObjectAvailable() 1247 1266 { -
trunk/WebCore/page/InspectorController.h
r34696 r35317 121 121 void setScriptContext(JSContextRef context) { m_scriptContext = context; }; 122 122 123 void inspectedWindowScriptObjectCleared(Frame*); 123 124 void windowScriptObjectAvailable(); 124 125 -
trunk/WebCore/page/inspector/ElementsPanel.js
r35316 r35317 77 77 this.element.appendChild(this.sidebarResizeElement); 78 78 79 this._mutationMonitoredWindows = []; 80 this._nodeInsertedEventListener = InspectorController.wrapCallback(this._nodeInserted.bind(this)); 81 this._nodeRemovedEventListener = InspectorController.wrapCallback(this._nodeRemoved.bind(this)); 82 this._contentLoadedEventListener = InspectorController.wrapCallback(this._contentLoaded.bind(this)); 83 79 84 this.reset(); 80 85 } … … 104 109 this.updateBreadcrumb(); 105 110 this.updateTreeSelection(); 111 if (this.recentlyModifiedNodes.length) 112 this._updateModifiedNodes(); 106 113 }, 107 114 … … 129 136 this.forceHoverHighlight = false; 130 137 138 this.recentlyModifiedNodes = []; 139 this.unregisterAllMutationEventListeners(); 140 131 141 var inspectedWindow = InspectorController.inspectedWindow(); 132 142 if (!inspectedWindow || !inspectedWindow.document) … … 142 152 143 153 var contentLoadedCallback = InspectorController.wrapCallback(contentLoaded.bind(this)); 144 145 154 inspectedWindow.document.addEventListener("DOMContentLoaded", contentLoadedCallback, false); 146 155 return; 147 156 } 157 158 // If the window isn't visible, return early so the DOM tree isn't built 159 // and mutation event listeners are not added. 160 if (!InspectorController.isWindowVisible()) 161 return; 162 163 this.registerMutationEventListeners(inspectedWindow); 148 164 149 165 var inspectedRootDocument = inspectedWindow.document; … … 158 174 }, 159 175 176 inspectedWindowCleared: function(window) 177 { 178 if (InspectorController.isWindowVisible()) 179 this.updateMutationEventListeners(window); 180 }, 181 182 _addMutationEventListeners: function(monitoredWindow) 183 { 184 monitoredWindow.document.addEventListener("DOMNodeInserted", this._nodeInsertedEventListener, true); 185 monitoredWindow.document.addEventListener("DOMNodeRemoved", this._nodeRemovedEventListener, true); 186 if (monitoredWindow.frameElement) 187 monitoredWindow.addEventListener("DOMContentLoaded", this._contentLoadedEventListener, true); 188 }, 189 190 _removeMutationEventListeners: function(monitoredWindow) 191 { 192 if (monitoredWindow.frameElement) 193 monitoredWindow.removeEventListener("DOMContentLoaded", this._contentLoadedEventListener, true); 194 if (!monitoredWindow.document) 195 return; 196 monitoredWindow.document.removeEventListener("DOMNodeInserted", this._nodeInsertedEventListener, true); 197 monitoredWindow.document.removeEventListener("DOMNodeRemoved", this._nodeRemovedEventListener, true); 198 }, 199 200 updateMutationEventListeners: function(monitoredWindow) 201 { 202 this._addMutationEventListeners(monitoredWindow); 203 }, 204 205 registerMutationEventListeners: function(monitoredWindow) 206 { 207 if (!monitoredWindow || this._mutationMonitoredWindows.indexOf(monitoredWindow) !== -1) 208 return; 209 this._mutationMonitoredWindows.push(monitoredWindow); 210 if (InspectorController.isWindowVisible()) 211 this._addMutationEventListeners(monitoredWindow); 212 }, 213 214 unregisterMutationEventListeners: function(monitoredWindow) 215 { 216 if (!monitoredWindow || this._mutationMonitoredWindows.indexOf(monitoredWindow) === -1) 217 return; 218 this._mutationMonitoredWindows.remove(monitoredWindow); 219 this._removeMutationEventListeners(monitoredWindow); 220 }, 221 222 unregisterAllMutationEventListeners: function() 223 { 224 for (var i = 0; i < this._mutationMonitoredWindows.length; ++i) 225 this._removeMutationEventListeners(this._mutationMonitoredWindows[i]); 226 this._mutationMonitoredWindows = []; 227 }, 228 160 229 updateTreeSelection: function() 161 230 { … … 257 326 else 258 327 this._updateHoverHighlight(); 328 }, 329 330 _contentLoaded: function(event) 331 { 332 this.recentlyModifiedNodes.push({node: event.target, parent: event.target.defaultView.frameElement, replaced: true}); 333 if (this.visible) 334 this._updateModifiedNodesSoon(); 335 }, 336 337 _nodeInserted: function(event) 338 { 339 this.recentlyModifiedNodes.push({node: event.target, parent: event.relatedNode, inserted: true}); 340 if (this.visible) 341 this._updateModifiedNodesSoon(); 342 }, 343 344 _nodeRemoved: function(event) 345 { 346 this.recentlyModifiedNodes.push({node: event.target, parent: event.relatedNode, removed: true}); 347 if (this.visible) 348 this._updateModifiedNodesSoon(); 349 }, 350 351 _updateModifiedNodesSoon: function() 352 { 353 if ("_updateModifiedNodesTimeout" in this) 354 return; 355 this._updateModifiedNodesTimeout = setTimeout(this._updateModifiedNodes.bind(this), 0); 356 }, 357 358 _updateModifiedNodes: function() 359 { 360 if ("_updateModifiedNodesTimeout" in this) { 361 clearTimeout(this._updateModifiedNodesTimeout); 362 delete this._updateModifiedNodesTimeout; 363 } 364 365 var updatedParentTreeElements = []; 366 var updateBreadcrumbs = false; 367 368 for (var i = 0; i < this.recentlyModifiedNodes.length; ++i) { 369 var replaced = this.recentlyModifiedNodes[i].replaced; 370 var parent = this.recentlyModifiedNodes[i].parent; 371 if (!parent) 372 continue; 373 374 var parentNodeItem = this.treeOutline.findTreeElement(parent, null, null, objectsAreSame); 375 if (parentNodeItem && !parentNodeItem.alreadyUpdatedChildren) { 376 parentNodeItem.updateChildren(replaced); 377 parentNodeItem.alreadyUpdatedChildren = true; 378 updatedParentTreeElements.push(parentNodeItem); 379 } 380 381 if (!updateBreadcrumbs && (objectsAreSame(this.focusedDOMNode, parent) || this._isAncestorIncludingParentFrames(this.focusedDOMNode, parent))) 382 updateBreadcrumbs = true; 383 } 384 385 for (var i = 0; i < updatedParentTreeElements.length; ++i) 386 delete updatedParentTreeElements[i].alreadyUpdatedChildren; 387 388 this.recentlyModifiedNodes = []; 389 390 if (updateBreadcrumbs) 391 this.updateBreadcrumb(true); 259 392 }, 260 393 … … 889 1022 _isAncestorIncludingParentFrames: function(a, b) 890 1023 { 1024 if (objectsAreSame(a, b)) 1025 return false; 891 1026 for (var node = b; node; node = this._getDocumentForNode(node).defaultView.frameElement) 892 if ( isAncestorNode.call(a, node))1027 if (objectsAreSame(a, node) || isAncestorNode.call(a, node)) 893 1028 return true; 894 1029 return false; … … 1038 1173 return; 1039 1174 1040 this.removeChildren();1041 1175 this.whitespaceIgnored = Preferences.ignoreWhitespace; 1042 1176 1177 this.updateChildren(); 1178 }, 1179 1180 updateChildren: function(fullRefresh) 1181 { 1182 if (fullRefresh) { 1183 var selectedTreeElement = this.treeOutline.selectedTreeElement; 1184 if (selectedTreeElement && selectedTreeElement.hasAncestor(this)) 1185 this.select(); 1186 this.removeChildren(); 1187 } 1188 1043 1189 var treeElement = this; 1044 function appendChildrenOfNode(node) 1190 var treeChildIndex = 0; 1191 1192 function updateChildrenOfNode(node) 1045 1193 { 1194 var treeOutline = treeElement.treeOutline; 1046 1195 var child = (Preferences.ignoreWhitespace ? firstChildSkippingWhitespace.call(node) : node.firstChild); 1047 1196 while (child) { 1048 treeElement.appendChild(new WebInspector.DOMNodeTreeElement(child)); 1197 var currentTreeElement = treeElement.children[treeChildIndex]; 1198 if (!currentTreeElement || !objectsAreSame(currentTreeElement.representedObject, child)) { 1199 // Find any existing element that is later in the children list. 1200 var existingTreeElement = null; 1201 for (var i = (treeChildIndex + 1); i < treeElement.children.length; ++i) { 1202 if (objectsAreSame(treeElement.children[i].representedObject, child)) { 1203 existingTreeElement = treeElement.children[i]; 1204 break; 1205 } 1206 } 1207 1208 if (existingTreeElement && existingTreeElement.parent === treeElement) { 1209 // If an existing element was found and it has the same parent, just move it. 1210 var wasSelected = existingTreeElement.selected; 1211 treeElement.removeChild(existingTreeElement); 1212 treeElement.insertChild(existingTreeElement, treeChildIndex); 1213 if (wasSelected) 1214 existingTreeElement.select(); 1215 } else { 1216 // No existing element found, insert a new element. 1217 treeElement.insertChild(new WebInspector.DOMNodeTreeElement(child), treeChildIndex); 1218 } 1219 } 1220 1049 1221 child = Preferences.ignoreWhitespace ? nextSiblingSkippingWhitespace.call(child) : child.nextSibling; 1050 } 1222 ++treeChildIndex; 1223 } 1224 } 1225 1226 // Remove any tree elements that no longer have this node (or this node's contentDocument) as their parent. 1227 for (var i = (this.children.length - 1); i >= 0; --i) { 1228 if ("elementCloseTag" in this.children[i]) 1229 continue; 1230 1231 var currentChild = this.children[i]; 1232 var currentNode = currentChild.representedObject; 1233 var currentParentNode = currentNode.parentNode; 1234 1235 if (objectsAreSame(currentParentNode, this.representedObject)) 1236 continue; 1237 if (this.representedObject.contentDocument && objectsAreSame(currentParentNode, this.representedObject.contentDocument)) 1238 continue; 1239 1240 var selectedTreeElement = this.treeOutline.selectedTreeElement; 1241 if (selectedTreeElement && (selectedTreeElement === currentChild || selectedTreeElement.hasAncestor(currentChild))) 1242 this.select(); 1243 1244 this.removeChildAtIndex(i); 1245 1246 if (currentNode.contentDocument) 1247 this.treeOutline.panel.unregisterMutationEventListeners(currentNode.contentDocument.defaultView); 1051 1248 } 1052 1249 1053 1250 if (this.representedObject.contentDocument) 1054 appendChildrenOfNode(this.representedObject.contentDocument);1055 1056 appendChildrenOfNode(this.representedObject); 1057 1058 if (this.representedObject.nodeType == Node.ELEMENT_NODE ) {1251 updateChildrenOfNode(this.representedObject.contentDocument); 1252 updateChildrenOfNode(this.representedObject); 1253 1254 var lastChild = this.children[this.children.length - 1]; 1255 if (this.representedObject.nodeType == Node.ELEMENT_NODE && (!lastChild || !lastChild.elementCloseTag)) { 1059 1256 var title = "<span class=\"webkit-html-tag close\"></" + this.representedObject.nodeName.toLowerCase().escapeHTML() + "></span>"; 1060 var item = new TreeElement(title, this.representedObject, false);1257 var item = new TreeElement(title, null, false); 1061 1258 item.selectable = false; 1259 item.elementCloseTag = true; 1062 1260 this.appendChild(item); 1063 1261 } … … 1067 1265 { 1068 1266 this.treeOutline.panel.updateTreeSelection(); 1267 1268 if (this.representedObject.contentDocument) 1269 this.treeOutline.panel.registerMutationEventListeners(this.representedObject.contentDocument.defaultView); 1069 1270 }, 1070 1271 -
trunk/WebCore/page/inspector/inspector.js
r35113 r35317 785 785 786 786 this.console.clearMessages(); 787 } 788 789 WebInspector.inspectedWindowCleared = function(inspectedWindow) 790 { 791 this.panels.elements.inspectedWindowCleared(inspectedWindow); 787 792 } 788 793 -
trunk/WebCore/page/inspector/treeoutline.js
r35315 r35317 467 467 }, 468 468 469 get hasChildren() { 470 return this._hasChildren; 471 }, 472 473 set hasChildren(x) { 474 if (this._hasChildren === x) 475 return; 476 477 this._hasChildren = x; 478 479 if (!this._listItemNode) 480 return; 481 482 if (x) 483 this._listItemNode.addStyleClass("parent"); 484 else { 485 this._listItemNode.removeStyleClass("parent"); 486 this.collapse(); 487 } 488 }, 489 469 490 get hidden() { 470 491 return this._hidden; … … 629 650 return; 630 651 631 if ( !this._childrenListNode || this._shouldRefreshChildren) {652 if (this.treeOutline && (!this._childrenListNode || this._shouldRefreshChildren)) { 632 653 if (this._childrenListNode && this._childrenListNode.parentNode) 633 654 this._childrenListNode.parentNode.removeChild(this._childrenListNode); … … 651 672 if (this._listItemNode) { 652 673 this._listItemNode.addStyleClass("expanded"); 653 if (this._childrenListNode .parentNode != this._listItemNode.parentNode)674 if (this._childrenListNode && this._childrenListNode.parentNode != this._listItemNode.parentNode) 654 675 this.parent._childrenListNode.insertBefore(this._childrenListNode, this._listItemNode.nextSibling); 655 676 } … … 686 707 } 687 708 709 TreeElement.prototype.hasAncestor = function(ancestor) { 710 if (!ancestor) 711 return false; 712 713 var currentNode = this.parent; 714 while (currentNode) { 715 if (ancestor === currentNode) 716 return true; 717 currentNode = currentNode.parent; 718 } 719 720 return false; 721 } 722 688 723 TreeElement.prototype.reveal = function() 689 724 {
Note: See TracChangeset
for help on using the changeset viewer.