OLD | NEW |
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 * | 5 * |
5 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
7 * are met: | 8 * are met: |
8 * | 9 * |
9 * 1. Redistributions of source code must retain the above copyright | 10 * 1. Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 11 * notice, this list of conditions and the following disclaimer. |
11 * 2. Redistributions in binary form must reproduce the above copyright | 12 * 2. Redistributions in binary form must reproduce the above copyright |
12 * notice, this list of conditions and the following disclaimer in the | 13 * notice, this list of conditions and the following disclaimer in the |
13 * documentation and/or other materials provided with the distribution. | 14 * documentation and/or other materials provided with the distribution. |
(...skipping 29 matching lines...) Expand all Loading... |
43 } | 44 } |
44 | 45 |
45 WebInspector.ElementsTreeOutline.prototype = { | 46 WebInspector.ElementsTreeOutline.prototype = { |
46 get rootDOMNode() | 47 get rootDOMNode() |
47 { | 48 { |
48 return this._rootDOMNode; | 49 return this._rootDOMNode; |
49 }, | 50 }, |
50 | 51 |
51 set rootDOMNode(x) | 52 set rootDOMNode(x) |
52 { | 53 { |
53 if (objectsAreSame(this._rootDOMNode, x)) | 54 if (this._rootDOMNode === x) |
54 return; | 55 return; |
55 | 56 |
56 this._rootDOMNode = x; | 57 this._rootDOMNode = x; |
57 | 58 |
58 this.update(); | 59 this.update(); |
59 }, | 60 }, |
60 | 61 |
61 get focusedDOMNode() | 62 get focusedDOMNode() |
62 { | 63 { |
63 return this._focusedDOMNode; | 64 return this._focusedDOMNode; |
64 }, | 65 }, |
65 | 66 |
66 set focusedDOMNode(x) | 67 set focusedDOMNode(x) |
67 { | 68 { |
68 if (objectsAreSame(this._focusedDOMNode, x)) { | 69 if (this._focusedDOMNode === x) { |
69 this.revealAndSelectNode(x); | 70 this.revealAndSelectNode(x); |
70 return; | 71 return; |
71 } | 72 } |
72 | 73 |
73 this._focusedDOMNode = x; | 74 this._focusedDOMNode = x; |
74 | 75 |
75 this.revealAndSelectNode(x); | 76 this.revealAndSelectNode(x); |
76 | 77 |
77 // The revealAndSelectNode() method might find a different element if th
ere is inlined text, | 78 // The revealAndSelectNode() method might find a different element if th
ere is inlined text, |
78 // and the select() call would change the focusedDOMNode and reenter thi
s setter. So to | 79 // and the select() call would change the focusedDOMNode and reenter thi
s setter. So to |
79 // avoid calling focusedNodeChanged() twice, first check if _focusedDOMN
ode is the same | 80 // avoid calling focusedNodeChanged() twice, first check if _focusedDOMN
ode is the same |
80 // node as the one passed in. | 81 // node as the one passed in. |
81 if (objectsAreSame(this._focusedDOMNode, x)) { | 82 if (this._focusedDOMNode === x) { |
82 this.focusedNodeChanged(); | 83 this.focusedNodeChanged(); |
83 | 84 |
84 if (x && !this.suppressSelectHighlight) { | 85 if (x && !this.suppressSelectHighlight) { |
85 InspectorController.highlightDOMNode(x); | 86 InspectorController.highlightDOMNode(x.id); |
86 | 87 |
87 if ("_restorePreviousHighlightNodeTimeout" in this) | 88 if ("_restorePreviousHighlightNodeTimeout" in this) |
88 clearTimeout(this._restorePreviousHighlightNodeTimeout); | 89 clearTimeout(this._restorePreviousHighlightNodeTimeout); |
89 | 90 |
90 function restoreHighlightToHoveredNode() | 91 function restoreHighlightToHoveredNode() |
91 { | 92 { |
92 var hoveredNode = WebInspector.hoveredDOMNode; | 93 var hoveredNode = WebInspector.hoveredDOMNode; |
93 if (hoveredNode) | 94 if (hoveredNode) |
94 InspectorController.highlightDOMNode(hoveredNode); | 95 InspectorController.highlightDOMNode(hoveredNode.id); |
95 else | 96 else |
96 InspectorController.hideDOMNodeHighlight(); | 97 InspectorController.hideDOMNodeHighlight(); |
97 } | 98 } |
98 | 99 |
99 this._restorePreviousHighlightNodeTimeout = setTimeout(restoreHi
ghlightToHoveredNode, 2000); | 100 this._restorePreviousHighlightNodeTimeout = setTimeout(restoreHi
ghlightToHoveredNode, 2000); |
100 } | 101 } |
101 } | 102 } |
102 }, | 103 }, |
103 | 104 |
104 update: function() | 105 update: function() |
(...skipping 25 matching lines...) Expand all Loading... |
130 updateSelection: function() | 131 updateSelection: function() |
131 { | 132 { |
132 if (!this.selectedTreeElement) | 133 if (!this.selectedTreeElement) |
133 return; | 134 return; |
134 var element = this.treeOutline.selectedTreeElement; | 135 var element = this.treeOutline.selectedTreeElement; |
135 element.updateSelection(); | 136 element.updateSelection(); |
136 }, | 137 }, |
137 | 138 |
138 focusedNodeChanged: function(forceUpdate) {}, | 139 focusedNodeChanged: function(forceUpdate) {}, |
139 | 140 |
140 findTreeElement: function(node, isAncestor, getParent, equal) | 141 findTreeElement: function(node) |
141 { | 142 { |
142 if (typeof isAncestor === "undefined") | 143 var treeElement = TreeOutline.prototype.findTreeElement.call(this, node,
isAncestorNode, parentNode); |
143 isAncestor = isAncestorIncludingParentFrames; | |
144 if (typeof getParent === "undefined") | |
145 getParent = parentNodeOrFrameElement; | |
146 if (typeof equal === "undefined") | |
147 equal = objectsAreSame; | |
148 | |
149 var treeElement = TreeOutline.prototype.findTreeElement.call(this, node,
isAncestor, getParent, equal); | |
150 if (!treeElement && node.nodeType === Node.TEXT_NODE) { | 144 if (!treeElement && node.nodeType === Node.TEXT_NODE) { |
151 // The text node might have been inlined if it was short, so try to
find the parent element. | 145 // The text node might have been inlined if it was short, so try to
find the parent element. |
152 treeElement = TreeOutline.prototype.findTreeElement.call(this, node.
parentNode, isAncestor, getParent, equal); | 146 treeElement = TreeOutline.prototype.findTreeElement.call(this, node.
parentNode, isAncestorNode, parentNode); |
153 } | 147 } |
154 | 148 |
155 return treeElement; | 149 return treeElement; |
156 }, | 150 }, |
157 | 151 |
158 revealAndSelectNode: function(node) | 152 revealAndSelectNode: function(node) |
159 { | 153 { |
160 if (!node) | 154 if (!node) |
161 return; | 155 return; |
162 | 156 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
240 } | 234 } |
241 | 235 |
242 WebInspector.hoveredDOMNode = null; | 236 WebInspector.hoveredDOMNode = null; |
243 } | 237 } |
244 } | 238 } |
245 | 239 |
246 WebInspector.ElementsTreeOutline.prototype.__proto__ = TreeOutline.prototype; | 240 WebInspector.ElementsTreeOutline.prototype.__proto__ = TreeOutline.prototype; |
247 | 241 |
248 WebInspector.ElementsTreeElement = function(node) | 242 WebInspector.ElementsTreeElement = function(node) |
249 { | 243 { |
250 var hasChildren = node.contentDocument || (Preferences.ignoreWhitespace ? (f
irstChildSkippingWhitespace.call(node) ? true : false) : node.hasChildNodes()); | 244 var hasChildren = Preferences.ignoreWhitespace ? (firstChildSkippingWhitespa
ce.call(node) ? true : false) : node.hasChildNodes(); |
251 var titleInfo = nodeTitleInfo.call(node, hasChildren, WebInspector.linkifyUR
L); | 245 var titleInfo = nodeTitleInfo.call(node, hasChildren, WebInspector.linkifyUR
L); |
252 | 246 |
253 if (titleInfo.hasChildren) | 247 if (titleInfo.hasChildren) |
254 this.whitespaceIgnored = Preferences.ignoreWhitespace; | 248 this.whitespaceIgnored = Preferences.ignoreWhitespace; |
255 | 249 |
256 // The title will be updated in onattach. | 250 // The title will be updated in onattach. |
257 TreeElement.call(this, "", node, titleInfo.hasChildren); | 251 TreeElement.call(this, "", node, titleInfo.hasChildren); |
| 252 |
| 253 if (this.representedObject.nodeType == Node.ELEMENT_NODE) |
| 254 this._canAddAttributes = true; |
258 } | 255 } |
259 | 256 |
260 WebInspector.ElementsTreeElement.prototype = { | 257 WebInspector.ElementsTreeElement.prototype = { |
261 get highlighted() | 258 get highlighted() |
262 { | 259 { |
263 return this._highlighted; | 260 return this._highlighted; |
264 }, | 261 }, |
265 | 262 |
266 set highlighted(x) | 263 set highlighted(x) |
267 { | 264 { |
(...skipping 21 matching lines...) Expand all Loading... |
289 return; | 286 return; |
290 | 287 |
291 this._hovered = x; | 288 this._hovered = x; |
292 | 289 |
293 if (this.listItemElement) { | 290 if (this.listItemElement) { |
294 if (x) { | 291 if (x) { |
295 this.updateSelection(); | 292 this.updateSelection(); |
296 this.listItemElement.addStyleClass("hovered"); | 293 this.listItemElement.addStyleClass("hovered"); |
297 } else | 294 } else |
298 this.listItemElement.removeStyleClass("hovered"); | 295 this.listItemElement.removeStyleClass("hovered"); |
| 296 if (this._canAddAttributes) |
| 297 this.toggleNewAttributeButton(); |
299 } | 298 } |
300 }, | 299 }, |
301 | 300 |
| 301 toggleNewAttributeButton: function() |
| 302 { |
| 303 function removeWhenEditing(event) |
| 304 { |
| 305 if (this._addAttributeElement && this._addAttributeElement.parentNod
e) |
| 306 this._addAttributeElement.parentNode.removeChild(this._addAttrib
uteElement); |
| 307 delete this._addAttributeElement; |
| 308 } |
| 309 |
| 310 if (!this._addAttributeElement && this._hovered && !this._editing) { |
| 311 var span = document.createElement("span"); |
| 312 span.className = "add-attribute"; |
| 313 span.textContent = "\u2026"; |
| 314 span.addEventListener("dblclick", removeWhenEditing.bind(this), fals
e); |
| 315 this._addAttributeElement = span; |
| 316 |
| 317 var tag = this.listItemElement.getElementsByClassName("webkit-html-t
ag")[0]; |
| 318 this._insertInLastAttributePosition(tag, span); |
| 319 } else if (!this._hovered && this._addAttributeElement) { |
| 320 if (this._addAttributeElement.parentNode) |
| 321 this._addAttributeElement.parentNode.removeChild(this._addAttrib
uteElement); |
| 322 delete this._addAttributeElement; |
| 323 } |
| 324 }, |
| 325 |
302 updateSelection: function() | 326 updateSelection: function() |
303 { | 327 { |
304 var listItemElement = this.listItemElement; | 328 var listItemElement = this.listItemElement; |
305 if (!listItemElement) | 329 if (!listItemElement) |
306 return; | 330 return; |
307 | 331 |
308 if (document.body.offsetWidth <= 0) { | 332 if (document.body.offsetWidth <= 0) { |
309 // The stylesheet hasn't loaded yet or the window is closed, | 333 // The stylesheet hasn't loaded yet or the window is closed, |
310 // so we can't calculate what is need. Return early. | 334 // so we can't calculate what is need. Return early. |
311 return; | 335 return; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 | 373 |
350 onpopulate: function() | 374 onpopulate: function() |
351 { | 375 { |
352 if (this.children.length || this.whitespaceIgnored !== Preferences.ignor
eWhitespace) | 376 if (this.children.length || this.whitespaceIgnored !== Preferences.ignor
eWhitespace) |
353 return; | 377 return; |
354 | 378 |
355 this.whitespaceIgnored = Preferences.ignoreWhitespace; | 379 this.whitespaceIgnored = Preferences.ignoreWhitespace; |
356 | 380 |
357 this.updateChildren(); | 381 this.updateChildren(); |
358 }, | 382 }, |
| 383 |
| 384 updateChildren: function(fullRefresh) |
| 385 { |
| 386 WebInspector.domAgent.getChildNodesAsync(this.representedObject, this._u
pdateChildren.bind(this, fullRefresh)); |
| 387 }, |
359 | 388 |
360 updateChildren: function(fullRefresh) | 389 _updateChildren: function(fullRefresh) |
361 { | 390 { |
362 if (fullRefresh) { | 391 if (fullRefresh) { |
363 var selectedTreeElement = this.treeOutline.selectedTreeElement; | 392 var selectedTreeElement = this.treeOutline.selectedTreeElement; |
364 if (selectedTreeElement && selectedTreeElement.hasAncestor(this)) | 393 if (selectedTreeElement && selectedTreeElement.hasAncestor(this)) |
365 this.select(); | 394 this.select(); |
366 this.removeChildren(); | 395 this.removeChildren(); |
367 } | 396 } |
368 | 397 |
369 var treeElement = this; | 398 var treeElement = this; |
370 var treeChildIndex = 0; | 399 var treeChildIndex = 0; |
371 | 400 |
372 function updateChildrenOfNode(node) | 401 function updateChildrenOfNode(node) |
373 { | 402 { |
374 var treeOutline = treeElement.treeOutline; | 403 var treeOutline = treeElement.treeOutline; |
375 var child = (Preferences.ignoreWhitespace ? firstChildSkippingWhites
pace.call(node) : node.firstChild); | 404 var child = (Preferences.ignoreWhitespace ? firstChildSkippingWhites
pace.call(node) : node.firstChild); |
376 while (child) { | 405 while (child) { |
377 var currentTreeElement = treeElement.children[treeChildIndex]; | 406 var currentTreeElement = treeElement.children[treeChildIndex]; |
378 if (!currentTreeElement || !objectsAreSame(currentTreeElement.re
presentedObject, child)) { | 407 if (!currentTreeElement || currentTreeElement.representedObject
!== child) { |
379 // Find any existing element that is later in the children l
ist. | 408 // Find any existing element that is later in the children l
ist. |
380 var existingTreeElement = null; | 409 var existingTreeElement = null; |
381 for (var i = (treeChildIndex + 1); i < treeElement.children.
length; ++i) { | 410 for (var i = (treeChildIndex + 1); i < treeElement.children.
length; ++i) { |
382 if (objectsAreSame(treeElement.children[i].representedOb
ject, child)) { | 411 if (treeElement.children[i].representedObject === child)
{ |
383 existingTreeElement = treeElement.children[i]; | 412 existingTreeElement = treeElement.children[i]; |
384 break; | 413 break; |
385 } | 414 } |
386 } | 415 } |
387 | 416 |
388 if (existingTreeElement && existingTreeElement.parent === tr
eeElement) { | 417 if (existingTreeElement && existingTreeElement.parent === tr
eeElement) { |
389 // If an existing element was found and it has the same
parent, just move it. | 418 // If an existing element was found and it has the same
parent, just move it. |
390 var wasSelected = existingTreeElement.selected; | 419 var wasSelected = existingTreeElement.selected; |
391 treeElement.removeChild(existingTreeElement); | 420 treeElement.removeChild(existingTreeElement); |
392 treeElement.insertChild(existingTreeElement, treeChildIn
dex); | 421 treeElement.insertChild(existingTreeElement, treeChildIn
dex); |
(...skipping 14 matching lines...) Expand all Loading... |
407 | 436 |
408 // Remove any tree elements that no longer have this node (or this node'
s contentDocument) as their parent. | 437 // Remove any tree elements that no longer have this node (or this node'
s contentDocument) as their parent. |
409 for (var i = (this.children.length - 1); i >= 0; --i) { | 438 for (var i = (this.children.length - 1); i >= 0; --i) { |
410 if ("elementCloseTag" in this.children[i]) | 439 if ("elementCloseTag" in this.children[i]) |
411 continue; | 440 continue; |
412 | 441 |
413 var currentChild = this.children[i]; | 442 var currentChild = this.children[i]; |
414 var currentNode = currentChild.representedObject; | 443 var currentNode = currentChild.representedObject; |
415 var currentParentNode = currentNode.parentNode; | 444 var currentParentNode = currentNode.parentNode; |
416 | 445 |
417 if (objectsAreSame(currentParentNode, this.representedObject)) | 446 if (currentParentNode === this.representedObject) |
418 continue; | |
419 if (this.representedObject.contentDocument && objectsAreSame(current
ParentNode, this.representedObject.contentDocument)) | |
420 continue; | 447 continue; |
421 | 448 |
422 var selectedTreeElement = this.treeOutline.selectedTreeElement; | 449 var selectedTreeElement = this.treeOutline.selectedTreeElement; |
423 if (selectedTreeElement && (selectedTreeElement === currentChild ||
selectedTreeElement.hasAncestor(currentChild))) | 450 if (selectedTreeElement && (selectedTreeElement === currentChild ||
selectedTreeElement.hasAncestor(currentChild))) |
424 this.select(); | 451 this.select(); |
425 | 452 |
426 this.removeChildAtIndex(i); | 453 this.removeChildAtIndex(i); |
427 | |
428 if (this.treeOutline.panel && currentNode.contentDocument) | |
429 this.treeOutline.panel.unregisterMutationEventListeners(currentN
ode.contentDocument.defaultView); | |
430 } | 454 } |
431 | 455 |
432 if (this.representedObject.contentDocument) | |
433 updateChildrenOfNode(this.representedObject.contentDocument); | |
434 updateChildrenOfNode(this.representedObject); | 456 updateChildrenOfNode(this.representedObject); |
435 | 457 |
436 var lastChild = this.children[this.children.length - 1]; | 458 var lastChild = this.children[this.children.length - 1]; |
437 if (this.representedObject.nodeType == Node.ELEMENT_NODE && (!lastChild
|| !lastChild.elementCloseTag)) { | 459 if (this.representedObject.nodeType == Node.ELEMENT_NODE && (!lastChild
|| !lastChild.elementCloseTag)) { |
438 var title = "<span class=\"webkit-html-tag close\"></" + this.rep
resentedObject.nodeName.toLowerCase().escapeHTML() + "></span>"; | 460 var title = "<span class=\"webkit-html-tag close\"></" + this.rep
resentedObject.nodeName.toLowerCase().escapeHTML() + "></span>"; |
439 var item = new TreeElement(title, null, false); | 461 var item = new TreeElement(title, null, false); |
440 item.selectable = false; | 462 item.selectable = false; |
441 item.elementCloseTag = true; | 463 item.elementCloseTag = true; |
442 this.appendChild(item); | 464 this.appendChild(item); |
443 } | 465 } |
444 }, | 466 }, |
445 | 467 |
446 onexpand: function() | 468 onexpand: function() |
447 { | 469 { |
448 this.treeOutline.updateSelection(); | 470 this.treeOutline.updateSelection(); |
449 | |
450 if (this.treeOutline.panel && this.representedObject.contentDocument) | |
451 this.treeOutline.panel.registerMutationEventListeners(this.represent
edObject.contentDocument.defaultView); | |
452 }, | 471 }, |
453 | 472 |
454 oncollapse: function() | 473 oncollapse: function() |
455 { | 474 { |
456 this.treeOutline.updateSelection(); | 475 this.treeOutline.updateSelection(); |
457 }, | 476 }, |
458 | 477 |
459 onreveal: function() | 478 onreveal: function() |
460 { | 479 { |
461 if (this.listItemElement) | 480 if (this.listItemElement) |
(...skipping 14 matching lines...) Expand all Loading... |
476 // Prevent selecting the nearest word on double click. | 495 // Prevent selecting the nearest word on double click. |
477 if (event.detail >= 2) | 496 if (event.detail >= 2) |
478 event.preventDefault(); | 497 event.preventDefault(); |
479 }, | 498 }, |
480 | 499 |
481 ondblclick: function(treeElement, event) | 500 ondblclick: function(treeElement, event) |
482 { | 501 { |
483 if (this._editing) | 502 if (this._editing) |
484 return; | 503 return; |
485 | 504 |
486 if (this._startEditing(event)) | 505 if (this._startEditing(event, treeElement)) |
487 return; | 506 return; |
488 | 507 |
489 if (this.treeOutline.panel) { | 508 if (this.treeOutline.panel) { |
490 this.treeOutline.rootDOMNode = this.parent.representedObject; | 509 this.treeOutline.rootDOMNode = this.representedObject.parentNode; |
491 this.treeOutline.focusedDOMNode = this.representedObject; | 510 this.treeOutline.focusedDOMNode = this.representedObject; |
492 } | 511 } |
493 | 512 |
494 if (this.hasChildren && !this.expanded) | 513 if (this.hasChildren && !this.expanded) |
495 this.expand(); | 514 this.expand(); |
496 }, | 515 }, |
497 | 516 |
498 _startEditing: function(event) | 517 _insertInLastAttributePosition: function(tag, node) |
| 518 { |
| 519 if (tag.getElementsByClassName("webkit-html-attribute").length > 0) |
| 520 tag.insertBefore(node, tag.lastChild); |
| 521 else { |
| 522 var nodeName = tag.textContent.match(/^<(.*?)>$/)[1]; |
| 523 tag.textContent = ''; |
| 524 tag.appendChild(document.createTextNode('<'+nodeName)); |
| 525 tag.appendChild(node); |
| 526 tag.appendChild(document.createTextNode('>')); |
| 527 } |
| 528 }, |
| 529 |
| 530 _startEditing: function(event, treeElement) |
499 { | 531 { |
500 if (this.treeOutline.focusedDOMNode != this.representedObject) | 532 if (this.treeOutline.focusedDOMNode != this.representedObject) |
501 return; | 533 return; |
502 | 534 |
503 if (this.representedObject.nodeType != Node.ELEMENT_NODE && this.represe
ntedObject.nodeType != Node.TEXT_NODE) | 535 if (this.representedObject.nodeType != Node.ELEMENT_NODE && this.represe
ntedObject.nodeType != Node.TEXT_NODE) |
504 return false; | 536 return false; |
505 | 537 |
506 var textNode = event.target.enclosingNodeOrSelfWithClass("webkit-html-te
xt-node"); | 538 var textNode = event.target.enclosingNodeOrSelfWithClass("webkit-html-te
xt-node"); |
507 if (textNode) | 539 if (textNode) |
508 return this._startEditingTextNode(textNode); | 540 return this._startEditingTextNode(textNode); |
509 | 541 |
510 var attribute = event.target.enclosingNodeOrSelfWithClass("webkit-html-a
ttribute"); | 542 var attribute = event.target.enclosingNodeOrSelfWithClass("webkit-html-a
ttribute"); |
511 if (attribute) | 543 if (attribute) |
512 return this._startEditingAttribute(attribute, event); | 544 return this._startEditingAttribute(attribute, event.target); |
| 545 |
| 546 var newAttribute = event.target.enclosingNodeOrSelfWithClass("add-attrib
ute"); |
| 547 if (newAttribute) |
| 548 return this._addNewAttribute(treeElement.listItemElement); |
513 | 549 |
514 return false; | 550 return false; |
515 }, | 551 }, |
516 | 552 |
517 _startEditingAttribute: function(attribute, event) | 553 _addNewAttribute: function(listItemElement) |
| 554 { |
| 555 var attr = document.createElement("span"); |
| 556 attr.className = "webkit-html-attribute"; |
| 557 attr.style.marginLeft = "2px"; // overrides the .editing margin rule |
| 558 attr.style.marginRight = "2px"; // overrides the .editing margin rule |
| 559 var name = document.createElement("span"); |
| 560 name.className = "webkit-html-attribute-name new-attribute"; |
| 561 name.textContent = " "; |
| 562 var value = document.createElement("span"); |
| 563 value.className = "webkit-html-attribute-value"; |
| 564 attr.appendChild(name); |
| 565 attr.appendChild(value); |
| 566 |
| 567 var tag = listItemElement.getElementsByClassName("webkit-html-tag")[0]; |
| 568 this._insertInLastAttributePosition(tag, attr); |
| 569 return this._startEditingAttribute(attr, attr); |
| 570 }, |
| 571 |
| 572 _triggerEditAttribute: function(attributeName) |
| 573 { |
| 574 var attributeElements = this.listItemElement.getElementsByClassName("web
kit-html-attribute-name"); |
| 575 for (var i = 0, len = attributeElements.length; i < len; ++i) { |
| 576 if (attributeElements[i].textContent === attributeName) { |
| 577 for (var elem = attributeElements[i].nextSibling; elem; elem = e
lem.nextSibling) { |
| 578 if (elem.nodeType !== Node.ELEMENT_NODE) |
| 579 continue; |
| 580 |
| 581 if (elem.hasStyleClass("webkit-html-attribute-value")) |
| 582 return this._startEditingAttribute(attributeElements[i].
parentNode, elem); |
| 583 } |
| 584 } |
| 585 } |
| 586 }, |
| 587 |
| 588 _startEditingAttribute: function(attribute, elementForSelection) |
518 { | 589 { |
519 if (WebInspector.isBeingEdited(attribute)) | 590 if (WebInspector.isBeingEdited(attribute)) |
520 return true; | 591 return true; |
521 | 592 |
522 var attributeNameElement = attribute.getElementsByClassName("webkit-html
-attribute-name")[0]; | 593 var attributeNameElement = attribute.getElementsByClassName("webkit-html
-attribute-name")[0]; |
523 if (!attributeNameElement) | 594 if (!attributeNameElement) |
524 return false; | 595 return false; |
525 | 596 |
526 var attributeName = attributeNameElement.innerText; | 597 var attributeName = attributeNameElement.innerText; |
527 | 598 |
(...skipping 10 matching lines...) Expand all Loading... |
538 for (var child = node.firstChild; child; child = child.nextSibling) | 609 for (var child = node.firstChild; child; child = child.nextSibling) |
539 removeZeroWidthSpaceRecursive(child); | 610 removeZeroWidthSpaceRecursive(child); |
540 } | 611 } |
541 | 612 |
542 // Remove zero-width spaces that were added by nodeTitleInfo. | 613 // Remove zero-width spaces that were added by nodeTitleInfo. |
543 removeZeroWidthSpaceRecursive(attribute); | 614 removeZeroWidthSpaceRecursive(attribute); |
544 | 615 |
545 this._editing = true; | 616 this._editing = true; |
546 | 617 |
547 WebInspector.startEditing(attribute, this._attributeEditingCommitted.bin
d(this), this._editingCancelled.bind(this), attributeName); | 618 WebInspector.startEditing(attribute, this._attributeEditingCommitted.bin
d(this), this._editingCancelled.bind(this), attributeName); |
548 window.getSelection().setBaseAndExtent(event.target, 0, event.target, 1)
; | 619 window.getSelection().setBaseAndExtent(elementForSelection, 0, elementFo
rSelection, 1); |
549 | 620 |
550 return true; | 621 return true; |
551 }, | 622 }, |
552 | 623 |
553 _startEditingTextNode: function(textNode) | 624 _startEditingTextNode: function(textNode) |
554 { | 625 { |
555 if (WebInspector.isBeingEdited(textNode)) | 626 if (WebInspector.isBeingEdited(textNode)) |
556 return true; | 627 return true; |
557 | 628 |
558 this._editing = true; | 629 this._editing = true; |
559 | 630 |
560 WebInspector.startEditing(textNode, this._textNodeEditingCommitted.bind(
this), this._editingCancelled.bind(this)); | 631 WebInspector.startEditing(textNode, this._textNodeEditingCommitted.bind(
this), this._editingCancelled.bind(this)); |
561 window.getSelection().setBaseAndExtent(textNode, 0, textNode, 1); | 632 window.getSelection().setBaseAndExtent(textNode, 0, textNode, 1); |
562 | 633 |
563 return true; | 634 return true; |
564 }, | 635 }, |
565 | 636 |
566 _attributeEditingCommitted: function(element, newText, oldText, attributeNam
e) | 637 _attributeEditingCommitted: function(element, newText, oldText, attributeNam
e, moveDirection) |
567 { | 638 { |
568 delete this._editing; | 639 delete this._editing; |
569 | 640 |
| 641 // Before we do anything, determine where we should move |
| 642 // next based on the current element's settings |
| 643 var moveToAttribute; |
| 644 var newAttribute; |
| 645 if (moveDirection) { |
| 646 var found = false; |
| 647 var attributes = this.representedObject.attributes; |
| 648 for (var i = 0, len = attributes.length; i < len; ++i) { |
| 649 if (attributes[i].name === attributeName) { |
| 650 found = true; |
| 651 if (moveDirection === "backward" && i > 0) |
| 652 moveToAttribute = attributes[i - 1].name; |
| 653 else if (moveDirection === "forward" && i < attributes.lengt
h - 1) |
| 654 moveToAttribute = attributes[i + 1].name; |
| 655 else if (moveDirection === "forward" && i === attributes.len
gth - 1) |
| 656 newAttribute = true; |
| 657 } |
| 658 } |
| 659 |
| 660 if (!found && moveDirection === "backward") |
| 661 moveToAttribute = attributes[attributes.length - 1].name; |
| 662 else if (!found && moveDirection === "forward" && !/^\s*$/.test(newT
ext)) |
| 663 newAttribute = true; |
| 664 } |
| 665 |
| 666 function moveToNextAttributeIfNeeded() { |
| 667 if (moveToAttribute) |
| 668 this._triggerEditAttribute(moveToAttribute); |
| 669 else if (newAttribute) |
| 670 this._addNewAttribute(this.listItemElement); |
| 671 } |
| 672 |
570 var parseContainerElement = document.createElement("span"); | 673 var parseContainerElement = document.createElement("span"); |
571 parseContainerElement.innerHTML = "<span " + newText + "></span>"; | 674 parseContainerElement.innerHTML = "<span " + newText + "></span>"; |
572 var parseElement = parseContainerElement.firstChild; | 675 var parseElement = parseContainerElement.firstChild; |
573 if (!parseElement || !parseElement.hasAttributes()) { | 676 |
574 this._editingCancelled(element, context); | 677 if (!parseElement) { |
| 678 this._editingCancelled(element, attributeName); |
| 679 moveToNextAttributeIfNeeded.call(this); |
575 return; | 680 return; |
576 } | 681 } |
577 | 682 |
| 683 if (!parseElement.hasAttributes()) { |
| 684 this.representedObject.removeAttribute(attributeName); |
| 685 this._updateTitle(); |
| 686 moveToNextAttributeIfNeeded.call(this); |
| 687 return; |
| 688 } |
| 689 |
578 var foundOriginalAttribute = false; | 690 var foundOriginalAttribute = false; |
579 for (var i = 0; i < parseElement.attributes.length; ++i) { | 691 for (var i = 0; i < parseElement.attributes.length; ++i) { |
580 var attr = parseElement.attributes[i]; | 692 var attr = parseElement.attributes[i]; |
581 foundOriginalAttribute = foundOriginalAttribute || attr.name === att
ributeName; | 693 foundOriginalAttribute = foundOriginalAttribute || attr.name === att
ributeName; |
582 InspectorController.inspectedWindow().Element.prototype.setAttribute
.call(this.representedObject, attr.name, attr.value); | 694 try { |
| 695 this.representedObject.setAttribute(attr.name, attr.value); |
| 696 } catch(e) {} // ignore invalid attribute (innerHTML doesn't throw e
rrors, but this can) |
583 } | 697 } |
584 | 698 |
585 if (!foundOriginalAttribute) | 699 if (!foundOriginalAttribute) |
586 InspectorController.inspectedWindow().Element.prototype.removeAttrib
ute.call(this.representedObject, attributeName); | 700 this.representedObject.removeAttribute(attributeName); |
587 | 701 |
588 this._updateTitle(); | 702 this._updateTitle(); |
589 | 703 |
590 this.treeOutline.focusedNodeChanged(true); | 704 this.treeOutline.focusedNodeChanged(true); |
| 705 |
| 706 moveToNextAttributeIfNeeded.call(this); |
591 }, | 707 }, |
592 | 708 |
593 _textNodeEditingCommitted: function(element, newText) | 709 _textNodeEditingCommitted: function(element, newText) |
594 { | 710 { |
595 delete this._editing; | 711 delete this._editing; |
596 | 712 |
597 var textNode; | 713 var textNode; |
598 if (this.representedObject.nodeType == Node.ELEMENT_NODE) { | 714 if (this.representedObject.nodeType == Node.ELEMENT_NODE) { |
599 // We only show text nodes inline in elements if the element only | 715 // We only show text nodes inline in elements if the element only |
600 // has a single child, and that child is a text node. | 716 // has a single child, and that child is a text node. |
(...skipping 16 matching lines...) Expand all Loading... |
617 { | 733 { |
618 var title = nodeTitleInfo.call(this.representedObject, this.hasChildren,
WebInspector.linkifyURL).title; | 734 var title = nodeTitleInfo.call(this.representedObject, this.hasChildren,
WebInspector.linkifyURL).title; |
619 this.title = "<span class=\"highlight\">" + title + "</span>"; | 735 this.title = "<span class=\"highlight\">" + title + "</span>"; |
620 delete this.selectionElement; | 736 delete this.selectionElement; |
621 this.updateSelection(); | 737 this.updateSelection(); |
622 this._preventFollowingLinksOnDoubleClick(); | 738 this._preventFollowingLinksOnDoubleClick(); |
623 }, | 739 }, |
624 } | 740 } |
625 | 741 |
626 WebInspector.ElementsTreeElement.prototype.__proto__ = TreeElement.prototype; | 742 WebInspector.ElementsTreeElement.prototype.__proto__ = TreeElement.prototype; |
OLD | NEW |