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

Side by Side Diff: resources/inspector/ElementsTreeOutline.js

Issue 853002: Updating the Chromium reference build for Windows. The continuous... (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/reference_builds/chrome/
Patch Set: Added the symbol files back. Created 10 years, 9 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
« no previous file with comments | « resources/inspector/ElementsPanel.js ('k') | resources/inspector/EventListenersSidebarPane.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
4 * Copyright (C) 2009 Joseph Pecoraro
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 WebInspector.ElementsTreeOutline = function() {
32 this.element = document.createElement("ol");
33 this.element.addEventListener("mousedown", this._onmousedown.bind(this), fal se);
34 this.element.addEventListener("mousemove", this._onmousemove.bind(this), fal se);
35 this.element.addEventListener("mouseout", this._onmouseout.bind(this), false );
36
37 TreeOutline.call(this, this.element);
38
39 this.includeRootDOMNode = true;
40 this.selectEnabled = false;
41 this.showInElementsPanelEnabled = false;
42 this.rootDOMNode = null;
43 this.focusedDOMNode = null;
44 }
45
46 WebInspector.ElementsTreeOutline.prototype = {
47 get rootDOMNode()
48 {
49 return this._rootDOMNode;
50 },
51
52 set rootDOMNode(x)
53 {
54 if (this._rootDOMNode === x)
55 return;
56
57 this._rootDOMNode = x;
58
59 this.update();
60 },
61
62 get focusedDOMNode()
63 {
64 return this._focusedDOMNode;
65 },
66
67 set focusedDOMNode(x)
68 {
69 if (this._focusedDOMNode === x) {
70 this.revealAndSelectNode(x);
71 return;
72 }
73
74 this._focusedDOMNode = x;
75
76 this.revealAndSelectNode(x);
77
78 // The revealAndSelectNode() method might find a different element if th ere is inlined text,
79 // and the select() call would change the focusedDOMNode and reenter thi s setter. So to
80 // avoid calling focusedNodeChanged() twice, first check if _focusedDOMN ode is the same
81 // node as the one passed in.
82 if (this._focusedDOMNode === x) {
83 this.focusedNodeChanged();
84
85 if (x && !this.suppressSelectHighlight) {
86 InspectorController.highlightDOMNode(x.id);
87
88 if ("_restorePreviousHighlightNodeTimeout" in this)
89 clearTimeout(this._restorePreviousHighlightNodeTimeout);
90
91 function restoreHighlightToHoveredNode()
92 {
93 var hoveredNode = WebInspector.hoveredDOMNode;
94 if (hoveredNode)
95 InspectorController.highlightDOMNode(hoveredNode.id);
96 else
97 InspectorController.hideDOMNodeHighlight();
98 }
99
100 this._restorePreviousHighlightNodeTimeout = setTimeout(restoreHi ghlightToHoveredNode, 2000);
101 }
102 }
103 },
104
105 update: function()
106 {
107 this.removeChildren();
108
109 if (!this.rootDOMNode)
110 return;
111
112 var treeElement;
113 if (this.includeRootDOMNode) {
114 treeElement = new WebInspector.ElementsTreeElement(this.rootDOMNode) ;
115 treeElement.selectable = this.selectEnabled;
116 this.appendChild(treeElement);
117 } else {
118 // FIXME: this could use findTreeElement to reuse a tree element if it already exists
119 var node = this.rootDOMNode.firstChild;
120 while (node) {
121 treeElement = new WebInspector.ElementsTreeElement(node);
122 treeElement.selectable = this.selectEnabled;
123 this.appendChild(treeElement);
124 node = node.nextSibling;
125 }
126 }
127
128 this.updateSelection();
129 },
130
131 updateSelection: function()
132 {
133 if (!this.selectedTreeElement)
134 return;
135 var element = this.treeOutline.selectedTreeElement;
136 element.updateSelection();
137 },
138
139 focusedNodeChanged: function(forceUpdate) {},
140
141 findTreeElement: function(node)
142 {
143 var treeElement = TreeOutline.prototype.findTreeElement.call(this, node, isAncestorNode, parentNode);
144 if (!treeElement && node.nodeType === Node.TEXT_NODE) {
145 // The text node might have been inlined if it was short, so try to find the parent element.
146 treeElement = TreeOutline.prototype.findTreeElement.call(this, node. parentNode, isAncestorNode, parentNode);
147 }
148
149 return treeElement;
150 },
151
152 revealAndSelectNode: function(node)
153 {
154 if (!node)
155 return;
156
157 var treeElement = this.findTreeElement(node);
158 if (!treeElement)
159 return;
160
161 treeElement.reveal();
162 treeElement.select();
163 },
164
165 _treeElementFromEvent: function(event)
166 {
167 var root = this.element;
168
169 // We choose this X coordinate based on the knowledge that our list
170 // items extend nearly to the right edge of the outer <ol>.
171 var x = root.totalOffsetLeft + root.offsetWidth - 20;
172
173 var y = event.pageY;
174
175 // Our list items have 1-pixel cracks between them vertically. We avoid
176 // the cracks by checking slightly above and slightly below the mouse
177 // and seeing if we hit the same element each time.
178 var elementUnderMouse = this.treeElementFromPoint(x, y);
179 var elementAboveMouse = this.treeElementFromPoint(x, y - 2);
180 var element;
181 if (elementUnderMouse === elementAboveMouse)
182 element = elementUnderMouse;
183 else
184 element = this.treeElementFromPoint(x, y + 2);
185
186 return element;
187 },
188
189 handleKeyEvent: function(event)
190 {
191 var selectedElement = this.selectedTreeElement;
192 if (!selectedElement)
193 return;
194
195 // Delete or backspace pressed, delete the node.
196 if (event.keyCode === 8 || event.keyCode === 46) {
197 selectedElement.remove();
198 return;
199 }
200
201 // On Enter or Return start editing the first attribute
202 // or create a new attribute on the selected element.
203 if (event.keyIdentifier === "Enter") {
204 if (this._editing)
205 return;
206
207 selectedElement._startEditing();
208
209 // prevent a newline from being immediately inserted
210 event.preventDefault();
211 return;
212 }
213
214 TreeOutline.prototype.handleKeyEvent.call(this, event);
215 },
216
217 _onmousedown: function(event)
218 {
219 var element = this._treeElementFromEvent(event);
220
221 if (!element || element.isEventWithinDisclosureTriangle(event))
222 return;
223
224 element.select();
225 },
226
227 _onmousemove: function(event)
228 {
229 var element = this._treeElementFromEvent(event);
230 if (element && this._previousHoveredElement === element)
231 return;
232
233 if (this._previousHoveredElement) {
234 this._previousHoveredElement.hovered = false;
235 delete this._previousHoveredElement;
236 }
237
238 if (element && !element.elementCloseTag) {
239 element.hovered = true;
240 this._previousHoveredElement = element;
241 }
242
243 WebInspector.hoveredDOMNode = (element && !element.elementCloseTag ? ele ment.representedObject : null);
244 },
245
246 _onmouseout: function(event)
247 {
248 var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY) ;
249 if (nodeUnderMouse && nodeUnderMouse.isDescendant(this.element))
250 return;
251
252 if (this._previousHoveredElement) {
253 this._previousHoveredElement.hovered = false;
254 delete this._previousHoveredElement;
255 }
256
257 WebInspector.hoveredDOMNode = null;
258 }
259 }
260
261 WebInspector.ElementsTreeOutline.prototype.__proto__ = TreeOutline.prototype;
262
263 WebInspector.ElementsTreeElement = function(node)
264 {
265 var hasChildrenOverride = node.hasChildNodes() && !this._showInlineText(node );
266
267 // The title will be updated in onattach.
268 TreeElement.call(this, "", node, hasChildrenOverride);
269
270 if (this.representedObject.nodeType == Node.ELEMENT_NODE)
271 this._canAddAttributes = true;
272 }
273
274 WebInspector.ElementsTreeElement.prototype = {
275 get highlighted()
276 {
277 return this._highlighted;
278 },
279
280 set highlighted(x)
281 {
282 if (this._highlighted === x)
283 return;
284
285 this._highlighted = x;
286
287 if (this.listItemElement) {
288 if (x)
289 this.listItemElement.addStyleClass("highlighted");
290 else
291 this.listItemElement.removeStyleClass("highlighted");
292 }
293 },
294
295 get hovered()
296 {
297 return this._hovered;
298 },
299
300 set hovered(x)
301 {
302 if (this._hovered === x)
303 return;
304
305 this._hovered = x;
306
307 if (this.listItemElement) {
308 if (x) {
309 this.updateSelection();
310 this.listItemElement.addStyleClass("hovered");
311 if (this._canAddAttributes)
312 this._pendingToggleNewAttribute = setTimeout(this.toggleNewA ttributeButton.bind(this, true), 500);
313 } else {
314 this.listItemElement.removeStyleClass("hovered");
315 if (this._pendingToggleNewAttribute) {
316 clearTimeout(this._pendingToggleNewAttribute);
317 delete this._pendingToggleNewAttribute;
318 }
319 this.toggleNewAttributeButton(false);
320 }
321 }
322 },
323
324 toggleNewAttributeButton: function(visible)
325 {
326 function removeAddAttributeSpan()
327 {
328 if (this._addAttributeElement && this._addAttributeElement.parentNod e)
329 this._addAttributeElement.parentNode.removeChild(this._addAttrib uteElement);
330 delete this._addAttributeElement;
331 }
332
333 if (!this._addAttributeElement && visible && !this._editing) {
334 var span = document.createElement("span");
335 span.className = "add-attribute webkit-html-attribute-name";
336 span.textContent = " ?=\"\"";
337 span.addEventListener("dblclick", removeAddAttributeSpan.bind(this), false);
338 this._addAttributeElement = span;
339
340 var tag = this.listItemElement.getElementsByClassName("webkit-html-t ag")[0];
341 this._insertInLastAttributePosition(tag, span);
342 } else if (!visible && this._addAttributeElement)
343 removeAddAttributeSpan.call(this);
344 },
345
346 updateSelection: function()
347 {
348 var listItemElement = this.listItemElement;
349 if (!listItemElement)
350 return;
351
352 if (document.body.offsetWidth <= 0) {
353 // The stylesheet hasn't loaded yet or the window is closed,
354 // so we can't calculate what is need. Return early.
355 return;
356 }
357
358 if (!this.selectionElement) {
359 this.selectionElement = document.createElement("div");
360 this.selectionElement.className = "selection selected";
361 listItemElement.insertBefore(this.selectionElement, listItemElement. firstChild);
362 }
363
364 this.selectionElement.style.height = listItemElement.offsetHeight + "px" ;
365 },
366
367 onattach: function()
368 {
369 this.listItemElement.addEventListener("mousedown", this.onmousedown.bind (this), false);
370
371 if (this._highlighted)
372 this.listItemElement.addStyleClass("highlighted");
373
374 if (this._hovered) {
375 this.updateSelection();
376 this.listItemElement.addStyleClass("hovered");
377 }
378
379 this._updateTitle();
380
381 this._preventFollowingLinksOnDoubleClick();
382 },
383
384 _preventFollowingLinksOnDoubleClick: function()
385 {
386 var links = this.listItemElement.querySelectorAll("li > .webkit-html-tag > .webkit-html-attribute > .webkit-html-external-link, li > .webkit-html-tag > .webkit-html-attribute > .webkit-html-resource-link");
387 if (!links)
388 return;
389
390 for (var i = 0; i < links.length; ++i)
391 links[i].preventFollowOnDoubleClick = true;
392 },
393
394 onpopulate: function()
395 {
396 if (this.children.length || this._showInlineText(this.representedObject) )
397 return;
398
399 this.updateChildren();
400 },
401
402 updateChildren: function(fullRefresh)
403 {
404 WebInspector.domAgent.getChildNodesAsync(this.representedObject, this._u pdateChildren.bind(this, fullRefresh));
405 },
406
407 _updateChildren: function(fullRefresh)
408 {
409 if (fullRefresh) {
410 var selectedTreeElement = this.treeOutline.selectedTreeElement;
411 if (selectedTreeElement && selectedTreeElement.hasAncestor(this))
412 this.select();
413 this.removeChildren();
414 }
415
416 var treeElement = this;
417 var treeChildIndex = 0;
418
419 function updateChildrenOfNode(node)
420 {
421 var treeOutline = treeElement.treeOutline;
422 var child = node.firstChild;
423 while (child) {
424 var currentTreeElement = treeElement.children[treeChildIndex];
425 if (!currentTreeElement || currentTreeElement.representedObject !== child) {
426 // Find any existing element that is later in the children l ist.
427 var existingTreeElement = null;
428 for (var i = (treeChildIndex + 1); i < treeElement.children. length; ++i) {
429 if (treeElement.children[i].representedObject === child) {
430 existingTreeElement = treeElement.children[i];
431 break;
432 }
433 }
434
435 if (existingTreeElement && existingTreeElement.parent === tr eeElement) {
436 // If an existing element was found and it has the same parent, just move it.
437 var wasSelected = existingTreeElement.selected;
438 treeElement.removeChild(existingTreeElement);
439 treeElement.insertChild(existingTreeElement, treeChildIn dex);
440 if (wasSelected)
441 existingTreeElement.select();
442 } else {
443 // No existing element found, insert a new element.
444 var newElement = new WebInspector.ElementsTreeElement(ch ild);
445 newElement.selectable = treeOutline.selectEnabled;
446 treeElement.insertChild(newElement, treeChildIndex);
447 }
448 }
449
450 child = child.nextSibling;
451 ++treeChildIndex;
452 }
453 }
454
455 // Remove any tree elements that no longer have this node (or this node' s contentDocument) as their parent.
456 for (var i = (this.children.length - 1); i >= 0; --i) {
457 if ("elementCloseTag" in this.children[i])
458 continue;
459
460 var currentChild = this.children[i];
461 var currentNode = currentChild.representedObject;
462 var currentParentNode = currentNode.parentNode;
463
464 if (currentParentNode === this.representedObject)
465 continue;
466
467 var selectedTreeElement = this.treeOutline.selectedTreeElement;
468 if (selectedTreeElement && (selectedTreeElement === currentChild || selectedTreeElement.hasAncestor(currentChild)))
469 this.select();
470
471 this.removeChildAtIndex(i);
472 }
473
474 updateChildrenOfNode(this.representedObject);
475
476 var lastChild = this.children[this.children.length - 1];
477 if (this.representedObject.nodeType == Node.ELEMENT_NODE && (!lastChild || !lastChild.elementCloseTag)) {
478 var title = "<span class=\"webkit-html-tag close\">&lt;/" + this.rep resentedObject.nodeName.toLowerCase().escapeHTML() + "&gt;</span>";
479 var item = new TreeElement(title, null, false);
480 item.selectable = false;
481 item.elementCloseTag = true;
482 this.appendChild(item);
483 }
484 },
485
486 onexpand: function()
487 {
488 this.treeOutline.updateSelection();
489 },
490
491 oncollapse: function()
492 {
493 this.treeOutline.updateSelection();
494 },
495
496 onreveal: function()
497 {
498 if (this.listItemElement)
499 this.listItemElement.scrollIntoViewIfNeeded(false);
500 },
501
502 onselect: function()
503 {
504 this.treeOutline.focusedDOMNode = this.representedObject;
505 this.updateSelection();
506 },
507
508 onmousedown: function(event)
509 {
510 if (this._editing)
511 return;
512
513 if (this.treeOutline.showInElementsPanelEnabled) {
514 WebInspector.showElementsPanel();
515 WebInspector.panels.elements.focusedDOMNode = this.representedObject ;
516 }
517
518 // Prevent selecting the nearest word on double click.
519 if (event.detail >= 2)
520 event.preventDefault();
521 },
522
523 ondblclick: function(treeElement, event)
524 {
525 if (this._editing)
526 return;
527
528 if (this._startEditingFromEvent(event, treeElement))
529 return;
530
531 if (this.treeOutline.panel) {
532 this.treeOutline.rootDOMNode = this.representedObject.parentNode;
533 this.treeOutline.focusedDOMNode = this.representedObject;
534 }
535
536 if (this.hasChildren && !this.expanded)
537 this.expand();
538 },
539
540 _insertInLastAttributePosition: function(tag, node)
541 {
542 if (tag.getElementsByClassName("webkit-html-attribute").length > 0)
543 tag.insertBefore(node, tag.lastChild);
544 else {
545 var nodeName = tag.textContent.match(/^<(.*?)>$/)[1];
546 tag.textContent = '';
547 tag.appendChild(document.createTextNode('<'+nodeName));
548 tag.appendChild(node);
549 tag.appendChild(document.createTextNode('>'));
550 }
551 },
552
553 _startEditingFromEvent: function(event, treeElement)
554 {
555 if (this.treeOutline.focusedDOMNode != this.representedObject)
556 return;
557
558 if (this.representedObject.nodeType != Node.ELEMENT_NODE && this.represe ntedObject.nodeType != Node.TEXT_NODE)
559 return false;
560
561 var textNode = event.target.enclosingNodeOrSelfWithClass("webkit-html-te xt-node");
562 if (textNode)
563 return this._startEditingTextNode(textNode);
564
565 var attribute = event.target.enclosingNodeOrSelfWithClass("webkit-html-a ttribute");
566 if (attribute)
567 return this._startEditingAttribute(attribute, event.target);
568
569 var newAttribute = event.target.enclosingNodeOrSelfWithClass("add-attrib ute");
570 if (newAttribute)
571 return this._addNewAttribute(treeElement.listItemElement);
572
573 return false;
574 },
575
576 _startEditing: function()
577 {
578 if (this.treeOutline.focusedDOMNode !== this.representedObject)
579 return;
580
581 var listItem = this._listItemNode;
582
583 if (this._canAddAttributes) {
584 this.toggleNewAttributeButton(false);
585 var attribute = listItem.getElementsByClassName("webkit-html-attribu te")[0];
586 if (attribute)
587 return this._startEditingAttribute(attribute, attribute.getEleme ntsByClassName("webkit-html-attribute-value")[0]);
588
589 return this._addNewAttribute(listItem);
590 }
591
592 if (this.representedObject.nodeType === Node.TEXT_NODE) {
593 var textNode = listItem.getElementsByClassName("webkit-html-text-nod e")[0];
594 if (textNode)
595 return this._startEditingTextNode(textNode);
596 return;
597 }
598 },
599
600 _addNewAttribute: function(listItemElement)
601 {
602 var attr = document.createElement("span");
603 attr.className = "webkit-html-attribute";
604 attr.style.marginLeft = "2px"; // overrides the .editing margin rule
605 attr.style.marginRight = "2px"; // overrides the .editing margin rule
606 var name = document.createElement("span");
607 name.className = "webkit-html-attribute-name new-attribute";
608 name.textContent = " ";
609 var value = document.createElement("span");
610 value.className = "webkit-html-attribute-value";
611 attr.appendChild(name);
612 attr.appendChild(value);
613
614 var tag = listItemElement.getElementsByClassName("webkit-html-tag")[0];
615 this._insertInLastAttributePosition(tag, attr);
616 return this._startEditingAttribute(attr, attr);
617 },
618
619 _triggerEditAttribute: function(attributeName)
620 {
621 var attributeElements = this.listItemElement.getElementsByClassName("web kit-html-attribute-name");
622 for (var i = 0, len = attributeElements.length; i < len; ++i) {
623 if (attributeElements[i].textContent === attributeName) {
624 for (var elem = attributeElements[i].nextSibling; elem; elem = e lem.nextSibling) {
625 if (elem.nodeType !== Node.ELEMENT_NODE)
626 continue;
627
628 if (elem.hasStyleClass("webkit-html-attribute-value"))
629 return this._startEditingAttribute(attributeElements[i]. parentNode, elem);
630 }
631 }
632 }
633 },
634
635 _startEditingAttribute: function(attribute, elementForSelection)
636 {
637 if (WebInspector.isBeingEdited(attribute))
638 return true;
639
640 var attributeNameElement = attribute.getElementsByClassName("webkit-html -attribute-name")[0];
641 if (!attributeNameElement)
642 return false;
643
644 var attributeName = attributeNameElement.innerText;
645
646 function removeZeroWidthSpaceRecursive(node)
647 {
648 if (node.nodeType === Node.TEXT_NODE) {
649 node.nodeValue = node.nodeValue.replace(/\u200B/g, "");
650 return;
651 }
652
653 if (node.nodeType !== Node.ELEMENT_NODE)
654 return;
655
656 for (var child = node.firstChild; child; child = child.nextSibling)
657 removeZeroWidthSpaceRecursive(child);
658 }
659
660 // Remove zero-width spaces that were added by nodeTitleInfo.
661 removeZeroWidthSpaceRecursive(attribute);
662
663 this._editing = true;
664
665 WebInspector.startEditing(attribute, this._attributeEditingCommitted.bin d(this), this._editingCancelled.bind(this), attributeName);
666 window.getSelection().setBaseAndExtent(elementForSelection, 0, elementFo rSelection, 1);
667
668 return true;
669 },
670
671 _startEditingTextNode: function(textNode)
672 {
673 if (WebInspector.isBeingEdited(textNode))
674 return true;
675
676 this._editing = true;
677
678 WebInspector.startEditing(textNode, this._textNodeEditingCommitted.bind( this), this._editingCancelled.bind(this));
679 window.getSelection().setBaseAndExtent(textNode, 0, textNode, 1);
680
681 return true;
682 },
683
684 _attributeEditingCommitted: function(element, newText, oldText, attributeNam e, moveDirection)
685 {
686 delete this._editing;
687
688 // Before we do anything, determine where we should move
689 // next based on the current element's settings
690 var moveToAttribute;
691 var newAttribute;
692 if (moveDirection) {
693 var found = false;
694 var attributes = this.representedObject.attributes;
695 for (var i = 0, len = attributes.length; i < len; ++i) {
696 if (attributes[i].name === attributeName) {
697 found = true;
698 if (moveDirection === "backward" && i > 0)
699 moveToAttribute = attributes[i - 1].name;
700 else if (moveDirection === "forward" && i < attributes.lengt h - 1)
701 moveToAttribute = attributes[i + 1].name;
702 else if (moveDirection === "forward" && i === attributes.len gth - 1)
703 newAttribute = true;
704 }
705 }
706
707 if (!found && moveDirection === "backward" && attributes.length > 0)
708 moveToAttribute = attributes[attributes.length - 1].name;
709 else if (!found && moveDirection === "forward" && !/^\s*$/.test(newT ext))
710 newAttribute = true;
711 }
712
713 function moveToNextAttributeIfNeeded() {
714 if (moveToAttribute)
715 this._triggerEditAttribute(moveToAttribute);
716 else if (newAttribute)
717 this._addNewAttribute(this.listItemElement);
718 }
719
720 var parseContainerElement = document.createElement("span");
721 parseContainerElement.innerHTML = "<span " + newText + "></span>";
722 var parseElement = parseContainerElement.firstChild;
723
724 if (!parseElement) {
725 this._editingCancelled(element, attributeName);
726 moveToNextAttributeIfNeeded.call(this);
727 return;
728 }
729
730 if (!parseElement.hasAttributes()) {
731 this.representedObject.removeAttribute(attributeName);
732 this._updateTitle();
733 moveToNextAttributeIfNeeded.call(this);
734 return;
735 }
736
737 var foundOriginalAttribute = false;
738 for (var i = 0; i < parseElement.attributes.length; ++i) {
739 var attr = parseElement.attributes[i];
740 foundOriginalAttribute = foundOriginalAttribute || attr.name === att ributeName;
741 try {
742 this.representedObject.setAttribute(attr.name, attr.value);
743 } catch(e) {} // ignore invalid attribute (innerHTML doesn't throw e rrors, but this can)
744 }
745
746 if (!foundOriginalAttribute)
747 this.representedObject.removeAttribute(attributeName);
748
749 this._updateTitle();
750
751 this.treeOutline.focusedNodeChanged(true);
752
753 moveToNextAttributeIfNeeded.call(this);
754 },
755
756 _textNodeEditingCommitted: function(element, newText)
757 {
758 delete this._editing;
759
760 var textNode;
761 if (this.representedObject.nodeType == Node.ELEMENT_NODE) {
762 // We only show text nodes inline in elements if the element only
763 // has a single child, and that child is a text node.
764 textNode = this.representedObject.firstChild;
765 } else if (this.representedObject.nodeType == Node.TEXT_NODE)
766 textNode = this.representedObject;
767
768 textNode.nodeValue = newText;
769 this._updateTitle();
770 },
771
772 _editingCancelled: function(element, context)
773 {
774 delete this._editing;
775
776 this._updateTitle();
777 },
778
779 _updateTitle: function()
780 {
781 var title = this._nodeTitleInfo(this.representedObject, this.hasChildren , WebInspector.linkifyURL).title;
782 this.title = "<span class=\"highlight\">" + title + "</span>";
783 delete this.selectionElement;
784 this.updateSelection();
785 this._preventFollowingLinksOnDoubleClick();
786 },
787
788 _nodeTitleInfo: function(node, hasChildren, linkify)
789 {
790 var info = {title: "", hasChildren: hasChildren};
791
792 switch (node.nodeType) {
793 case Node.DOCUMENT_NODE:
794 info.title = "Document";
795 break;
796
797 case Node.ELEMENT_NODE:
798 info.title = "<span class=\"webkit-html-tag\">&lt;" + node.nodeN ame.toLowerCase().escapeHTML();
799
800 if (node.hasAttributes()) {
801 for (var i = 0; i < node.attributes.length; ++i) {
802 var attr = node.attributes[i];
803 info.title += " <span class=\"webkit-html-attribute\"><s pan class=\"webkit-html-attribute-name\">" + attr.name.escapeHTML() + "</span>=& #8203;\"";
804
805 var value = attr.value;
806 if (linkify && (attr.name === "src" || attr.name === "hr ef")) {
807 var value = value.replace(/([\/;:\)\]\}])/g, "$1\u20 0B");
808 info.title += linkify(attr.value, value, "webkit-htm l-attribute-value", node.nodeName.toLowerCase() == "a");
809 } else {
810 var value = value.escapeHTML();
811 value = value.replace(/([\/;:\)\]\}])/g, "$1&#8203;" );
812 info.title += "<span class=\"webkit-html-attribute-v alue\">" + value + "</span>";
813 }
814 info.title += "\"</span>";
815 }
816 }
817 info.title += "&gt;</span>&#8203;";
818
819 // If this element only has a single child that is a text node,
820 // just show that text and the closing tag inline rather than
821 // create a subtree for them
822
823 var textChild = onlyTextChild.call(node);
824 var showInlineText = textChild && textChild.textContent.length < Preferences.maxInlineTextChildLength;
825
826 if (showInlineText) {
827 info.title += "<span class=\"webkit-html-text-node\">" + tex tChild.nodeValue.escapeHTML() + "</span>&#8203;<span class=\"webkit-html-tag\">& lt;/" + node.nodeName.toLowerCase().escapeHTML() + "&gt;</span>";
828 info.hasChildren = false;
829 }
830 break;
831
832 case Node.TEXT_NODE:
833 if (isNodeWhitespace.call(node))
834 info.title = "(whitespace)";
835 else {
836 if (node.parentNode && node.parentNode.nodeName.toLowerCase( ) == "script") {
837 var newNode = document.createElement("span");
838 newNode.textContent = node.textContent;
839
840 var javascriptSyntaxHighlighter = new WebInspector.JavaS criptSourceSyntaxHighlighter(null, null);
841 javascriptSyntaxHighlighter.syntaxHighlightLine(newNode, null);
842
843 info.title = "<span class=\"webkit-html-text-node webkit -html-js-node\">" + newNode.innerHTML.replace(/^[\n\r]*/, "").replace(/\s*$/, "" ) + "</span>";
844 } else if (node.parentNode && node.parentNode.nodeName.toLow erCase() == "style") {
845 var newNode = document.createElement("span");
846 newNode.textContent = node.textContent;
847
848 var cssSyntaxHighlighter = new WebInspector.CSSSourceSyn taxHighligher(null, null);
849 cssSyntaxHighlighter.syntaxHighlightLine(newNode, null);
850
851 info.title = "<span class=\"webkit-html-text-node webkit -html-css-node\">" + newNode.innerHTML.replace(/^[\n\r]*/, "").replace(/\s*$/, " ") + "</span>";
852 } else {
853 info.title = "\"<span class=\"webkit-html-text-node\">" + node.nodeValue.escapeHTML() + "</span>\"";
854 }
855 }
856 break;
857
858 case Node.COMMENT_NODE:
859 info.title = "<span class=\"webkit-html-comment\">&lt;!--" + nod e.nodeValue.escapeHTML() + "--&gt;</span>";
860 break;
861
862 case Node.DOCUMENT_TYPE_NODE:
863 info.title = "<span class=\"webkit-html-doctype\">&lt;!DOCTYPE " + node.nodeName;
864 if (node.publicId) {
865 info.title += " PUBLIC \"" + node.publicId + "\"";
866 if (node.systemId)
867 info.title += " \"" + node.systemId + "\"";
868 } else if (node.systemId)
869 info.title += " SYSTEM \"" + node.systemId + "\"";
870 if (node.internalSubset)
871 info.title += " [" + node.internalSubset + "]";
872 info.title += "&gt;</span>";
873 break;
874 default:
875 info.title = node.nodeName.toLowerCase().collapseWhitespace().es capeHTML();
876 }
877
878 return info;
879 },
880
881 _showInlineText: function(node)
882 {
883 if (node.nodeType === Node.ELEMENT_NODE) {
884 var textChild = onlyTextChild.call(node);
885 if (textChild && textChild.textContent.length < Preferences.maxInlin eTextChildLength)
886 return true;
887 }
888 return false;
889 },
890
891 remove: function()
892 {
893 var parentElement = this.parent;
894 if (!parentElement)
895 return;
896
897 var self = this;
898 function removeNodeCallback(removedNodeId)
899 {
900 // -1 is an error code, which means removing the node from the DOM f ailed,
901 // so we shouldn't remove it from the tree.
902 if (removedNodeId === -1)
903 return;
904
905 parentElement.removeChild(self);
906 }
907
908 var callId = WebInspector.Callback.wrap(removeNodeCallback);
909 InspectorController.removeNode(callId, this.representedObject.id);
910 }
911 }
912
913 WebInspector.ElementsTreeElement.prototype.__proto__ = TreeElement.prototype;
914
915 WebInspector.didRemoveNode = WebInspector.Callback.processCallback;
OLDNEW
« no previous file with comments | « resources/inspector/ElementsPanel.js ('k') | resources/inspector/EventListenersSidebarPane.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698