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

Side by Side Diff: chrome/resources/inspector/ElementsPanel.js

Issue 339015: Update Windows reference build to r30072.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/reference_builds/
Patch Set: Created 11 years, 1 month 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 | « chrome/resources/inspector/Drawer.js ('k') | chrome/resources/inspector/ElementsTreeOutline.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:executable
+ *
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.ElementsPanel = function()
32 {
33 WebInspector.Panel.call(this);
34
35 this.element.addStyleClass("elements");
36
37 this.contentElement = document.createElement("div");
38 this.contentElement.id = "elements-content";
39 this.contentElement.className = "outline-disclosure";
40
41 this.treeOutline = new WebInspector.ElementsTreeOutline();
42 this.treeOutline.panel = this;
43 this.treeOutline.includeRootDOMNode = false;
44 this.treeOutline.selectEnabled = true;
45
46 this.treeOutline.focusedNodeChanged = function(forceUpdate)
47 {
48 if (this.panel.visible && WebInspector.currentFocusElement !== document. getElementById("search"))
49 WebInspector.currentFocusElement = document.getElementById("main-pan els");
50
51 this.panel.updateBreadcrumb(forceUpdate);
52
53 for (var pane in this.panel.sidebarPanes)
54 this.panel.sidebarPanes[pane].needsUpdate = true;
55
56 this.panel.updateStyles(true);
57 this.panel.updateMetrics();
58 this.panel.updateProperties();
59 this.panel.updateEventListeners();
60
61 if (InspectorController.searchingForNode()) {
62 InspectorController.toggleNodeSearch();
63 this.panel.nodeSearchButton.toggled = false;
64 }
65 if (this._focusedDOMNode)
66 InjectedScriptAccess.addInspectedNode(this._focusedDOMNode.id, funct ion() {});
67 };
68
69 this.contentElement.appendChild(this.treeOutline.element);
70
71 this.crumbsElement = document.createElement("div");
72 this.crumbsElement.className = "crumbs";
73 this.crumbsElement.addEventListener("mousemove", this._mouseMovedInCrumbs.bi nd(this), false);
74 this.crumbsElement.addEventListener("mouseout", this._mouseMovedOutOfCrumbs. bind(this), false);
75
76 this.sidebarPanes = {};
77 this.sidebarPanes.styles = new WebInspector.StylesSidebarPane();
78 this.sidebarPanes.metrics = new WebInspector.MetricsSidebarPane();
79 this.sidebarPanes.properties = new WebInspector.PropertiesSidebarPane();
80 this.sidebarPanes.eventListeners = new WebInspector.EventListenersSidebarPan e();
81
82 this.sidebarPanes.styles.onexpand = this.updateStyles.bind(this);
83 this.sidebarPanes.metrics.onexpand = this.updateMetrics.bind(this);
84 this.sidebarPanes.properties.onexpand = this.updateProperties.bind(this);
85 this.sidebarPanes.eventListeners.onexpand = this.updateEventListeners.bind(t his);
86
87 this.sidebarPanes.styles.expanded = true;
88
89 this.sidebarPanes.styles.addEventListener("style edited", this._stylesPaneEd ited, this);
90 this.sidebarPanes.styles.addEventListener("style property toggled", this._st ylesPaneEdited, this);
91 this.sidebarPanes.metrics.addEventListener("metrics edited", this._metricsPa neEdited, this);
92
93 this.sidebarElement = document.createElement("div");
94 this.sidebarElement.id = "elements-sidebar";
95
96 this.sidebarElement.appendChild(this.sidebarPanes.styles.element);
97 this.sidebarElement.appendChild(this.sidebarPanes.metrics.element);
98 this.sidebarElement.appendChild(this.sidebarPanes.properties.element);
99 this.sidebarElement.appendChild(this.sidebarPanes.eventListeners.element);
100
101 this.sidebarResizeElement = document.createElement("div");
102 this.sidebarResizeElement.className = "sidebar-resizer-vertical";
103 this.sidebarResizeElement.addEventListener("mousedown", this.rightSidebarRes izerDragStart.bind(this), false);
104
105 this.nodeSearchButton = new WebInspector.StatusBarButton(WebInspector.UIStri ng("Select an element in the page to inspect it."), "node-search-status-bar-item ");
106 this.nodeSearchButton.addEventListener("click", this._nodeSearchButtonClicke d.bind(this), false);
107
108 this.searchingForNode = false;
109
110 this.element.appendChild(this.contentElement);
111 this.element.appendChild(this.sidebarElement);
112 this.element.appendChild(this.sidebarResizeElement);
113
114 this._changedStyles = {};
115
116 this.reset();
117 }
118
119 WebInspector.ElementsPanel.prototype = {
120 toolbarItemClass: "elements",
121
122 get toolbarItemLabel()
123 {
124 return WebInspector.UIString("Elements");
125 },
126
127 get statusBarItems()
128 {
129 return [this.nodeSearchButton.element, this.crumbsElement];
130 },
131
132 updateStatusBarItems: function()
133 {
134 this.updateBreadcrumbSizes();
135 },
136
137 show: function()
138 {
139 WebInspector.Panel.prototype.show.call(this);
140 this.sidebarResizeElement.style.right = (this.sidebarElement.offsetWidth - 3) + "px";
141 this.updateBreadcrumb();
142 this.treeOutline.updateSelection();
143 if (this.recentlyModifiedNodes.length)
144 this._updateModifiedNodes();
145 },
146
147 hide: function()
148 {
149 WebInspector.Panel.prototype.hide.call(this);
150
151 WebInspector.hoveredDOMNode = null;
152
153 if (InspectorController.searchingForNode()) {
154 InspectorController.toggleNodeSearch();
155 this.nodeSearchButton.toggled = false;
156 }
157 },
158
159 resize: function()
160 {
161 this.treeOutline.updateSelection();
162 this.updateBreadcrumbSizes();
163 },
164
165 reset: function()
166 {
167 this.rootDOMNode = null;
168 this.focusedDOMNode = null;
169
170 WebInspector.hoveredDOMNode = null;
171
172 if (InspectorController.searchingForNode()) {
173 InspectorController.toggleNodeSearch();
174 this.nodeSearchButton.toggled = false;
175 }
176
177 this.recentlyModifiedNodes = [];
178
179 delete this.currentQuery;
180 this.searchCanceled();
181
182 var domWindow = WebInspector.domAgent.domWindow;
183 if (!domWindow || !domWindow.document || !domWindow.document.firstChild)
184 return;
185
186 // If the window isn't visible, return early so the DOM tree isn't built
187 // and mutation event listeners are not added.
188 if (!InspectorController.isWindowVisible())
189 return;
190
191 var inspectedRootDocument = domWindow.document;
192 inspectedRootDocument.addEventListener("DOMNodeInserted", this._nodeInse rted.bind(this));
193 inspectedRootDocument.addEventListener("DOMNodeRemoved", this._nodeRemov ed.bind(this));
194
195 this.rootDOMNode = inspectedRootDocument;
196
197 var canidateFocusNode = inspectedRootDocument.body || inspectedRootDocum ent.documentElement;
198 if (canidateFocusNode) {
199 this.treeOutline.suppressSelectHighlight = true;
200 this.focusedDOMNode = canidateFocusNode;
201 this.treeOutline.suppressSelectHighlight = false;
202
203 if (this.treeOutline.selectedTreeElement)
204 this.treeOutline.selectedTreeElement.expand();
205 }
206 },
207
208 searchCanceled: function()
209 {
210 if (this._searchResults) {
211 for (var i = 0; i < this._searchResults.length; ++i) {
212 var treeElement = this.treeOutline.findTreeElement(this._searchR esults[i]);
213 if (treeElement)
214 treeElement.highlighted = false;
215 }
216 }
217
218 WebInspector.updateSearchMatchesCount(0, this);
219
220 this._currentSearchResultIndex = 0;
221 this._searchResults = [];
222 InjectedScriptAccess.searchCanceled(function() {});
223 },
224
225 performSearch: function(query)
226 {
227 // Call searchCanceled since it will reset everything we need before doi ng a new search.
228 this.searchCanceled();
229
230 const whitespaceTrimmedQuery = query.trimWhitespace();
231 if (!whitespaceTrimmedQuery.length)
232 return;
233
234 this._updatedMatchCountOnce = false;
235 this._matchesCountUpdateTimeout = null;
236
237 InjectedScriptAccess.performSearch(whitespaceTrimmedQuery, function() {} );
238 },
239
240 _updateMatchesCount: function()
241 {
242 WebInspector.updateSearchMatchesCount(this._searchResults.length, this);
243 this._matchesCountUpdateTimeout = null;
244 this._updatedMatchCountOnce = true;
245 },
246
247 _updateMatchesCountSoon: function()
248 {
249 if (!this._updatedMatchCountOnce)
250 return this._updateMatchesCount();
251 if (this._matchesCountUpdateTimeout)
252 return;
253 // Update the matches count every half-second so it doesn't feel twitchy .
254 this._matchesCountUpdateTimeout = setTimeout(this._updateMatchesCount.bi nd(this), 500);
255 },
256
257 addNodesToSearchResult: function(nodeIds)
258 {
259 if (!nodeIds)
260 return;
261
262 var nodeIdsArray = nodeIds.split(",");
263 for (var i = 0; i < nodeIdsArray.length; ++i) {
264 var nodeId = nodeIdsArray[i];
265 var node = WebInspector.domAgent.nodeForId(nodeId);
266 if (!node)
267 continue;
268
269 if (!this._searchResults.length) {
270 this._currentSearchResultIndex = 0;
271
272 // Only change the focusedDOMNode if the search was manually per formed, because
273 // the search may have been performed programmatically and we wo uldn't want to
274 // change the current focusedDOMNode.
275 if (WebInspector.currentFocusElement === document.getElementById ("search"))
276 this.focusedDOMNode = node;
277 }
278
279 this._searchResults.push(node);
280
281 // Highlight the tree element to show it matched the search.
282 // FIXME: highlight the substrings in text nodes and attributes.
283 var treeElement = this.treeOutline.findTreeElement(node);
284 if (treeElement)
285 treeElement.highlighted = true;
286 }
287
288 this._updateMatchesCountSoon();
289 },
290
291 jumpToNextSearchResult: function()
292 {
293 if (!this._searchResults || !this._searchResults.length)
294 return;
295 if (++this._currentSearchResultIndex >= this._searchResults.length)
296 this._currentSearchResultIndex = 0;
297 this.focusedDOMNode = this._searchResults[this._currentSearchResultIndex ];
298 },
299
300 jumpToPreviousSearchResult: function()
301 {
302 if (!this._searchResults || !this._searchResults.length)
303 return;
304 if (--this._currentSearchResultIndex < 0)
305 this._currentSearchResultIndex = (this._searchResults.length - 1);
306 this.focusedDOMNode = this._searchResults[this._currentSearchResultIndex ];
307 },
308
309 renameSelector: function(oldIdentifier, newIdentifier, oldSelector, newSelec tor)
310 {
311 // TODO: Implement Shifting the oldSelector, and its contents to a newSe lector
312 },
313
314 addStyleChange: function(identifier, style, property)
315 {
316 if (!style.parentRule)
317 return;
318
319 var selector = style.parentRule.selectorText;
320 if (!this._changedStyles[identifier])
321 this._changedStyles[identifier] = {};
322
323 if (!this._changedStyles[identifier][selector])
324 this._changedStyles[identifier][selector] = {};
325
326 if (!this._changedStyles[identifier][selector][property])
327 WebInspector.styleChanges += 1;
328
329 this._changedStyles[identifier][selector][property] = style.getPropertyV alue(property);
330 },
331
332 removeStyleChange: function(identifier, style, property)
333 {
334 if (!style.parentRule)
335 return;
336
337 var selector = style.parentRule.selectorText;
338 if (!this._changedStyles[identifier] || !this._changedStyles[identifier] [selector])
339 return;
340
341 if (this._changedStyles[identifier][selector][property]) {
342 delete this._changedStyles[identifier][selector][property];
343 WebInspector.styleChanges -= 1;
344 }
345 },
346
347 generateStylesheet: function()
348 {
349 if (!WebInspector.styleChanges)
350 return;
351
352 // Merge Down to Just Selectors
353 var mergedSelectors = {};
354 for (var identifier in this._changedStyles) {
355 for (var selector in this._changedStyles[identifier]) {
356 if (!mergedSelectors[selector])
357 mergedSelectors[selector] = this._changedStyles[identifier][ selector];
358 else { // merge on selector
359 var merge = {};
360 for (var property in mergedSelectors[selector])
361 merge[property] = mergedSelectors[selector][property];
362 for (var property in this._changedStyles[identifier][selecto r]) {
363 if (!merge[property])
364 merge[property] = this._changedStyles[identifier][se lector][property];
365 else { // merge on property within a selector, include c omment to notify user
366 var value1 = merge[property];
367 var value2 = this._changedStyles[identifier][selecto r][property];
368
369 if (value1 === value2)
370 merge[property] = [value1];
371 else if (value1 instanceof Array)
372 merge[property].push(value2);
373 else
374 merge[property] = [value1, value2];
375 }
376 }
377 mergedSelectors[selector] = merge;
378 }
379 }
380 }
381
382 var builder = [];
383 builder.push("/**");
384 builder.push(" * Inspector Generated Stylesheet"); // UIString?
385 builder.push(" */\n");
386
387 var indent = " ";
388 function displayProperty(property, value, comment) {
389 if (comment)
390 return indent + "/* " + property + ": " + value + "; */";
391 else
392 return indent + property + ": " + value + ";";
393 }
394
395 for (var selector in mergedSelectors) {
396 var psuedoStyle = mergedSelectors[selector];
397 var properties = Object.properties(psuedoStyle);
398 if (properties.length) {
399 builder.push(selector + " {");
400 for (var i = 0; i < properties.length; ++i) {
401 var property = properties[i];
402 var value = psuedoStyle[property];
403 if (!(value instanceof Array))
404 builder.push(displayProperty(property, value));
405 else {
406 if (value.length === 1)
407 builder.push(displayProperty(property, value) + " /* merged from equivalent edits */"); // UIString?
408 else {
409 builder.push(indent + "/* There was a Conflict... Th ere were Multiple Edits for '" + property + "' */"); // UIString?
410 for (var j = 0; j < value.length; ++j)
411 builder.push(displayProperty(property, value, tr ue));
412 }
413 }
414 }
415 builder.push("}\n");
416 }
417 }
418
419 WebInspector.showConsole();
420 WebInspector.console.addMessage(new WebInspector.ConsoleTextMessage(buil der.join("\n")));
421 },
422
423 get rootDOMNode()
424 {
425 return this.treeOutline.rootDOMNode;
426 },
427
428 set rootDOMNode(x)
429 {
430 this.treeOutline.rootDOMNode = x;
431 },
432
433 get focusedDOMNode()
434 {
435 return this.treeOutline.focusedDOMNode;
436 },
437
438 set focusedDOMNode(x)
439 {
440 this.treeOutline.focusedDOMNode = x;
441 },
442
443 _nodeInserted: function(event)
444 {
445 this.recentlyModifiedNodes.push({node: event.target, parent: event.relat edNode, inserted: true});
446 if (this.visible)
447 this._updateModifiedNodesSoon();
448 },
449
450 _nodeRemoved: function(event)
451 {
452 this.recentlyModifiedNodes.push({node: event.target, parent: event.relat edNode, removed: true});
453 if (this.visible)
454 this._updateModifiedNodesSoon();
455 },
456
457 _updateModifiedNodesSoon: function()
458 {
459 if ("_updateModifiedNodesTimeout" in this)
460 return;
461 this._updateModifiedNodesTimeout = setTimeout(this._updateModifiedNodes. bind(this), 0);
462 },
463
464 _updateModifiedNodes: function()
465 {
466 if ("_updateModifiedNodesTimeout" in this) {
467 clearTimeout(this._updateModifiedNodesTimeout);
468 delete this._updateModifiedNodesTimeout;
469 }
470
471 var updatedParentTreeElements = [];
472 var updateBreadcrumbs = false;
473
474 for (var i = 0; i < this.recentlyModifiedNodes.length; ++i) {
475 var replaced = this.recentlyModifiedNodes[i].replaced;
476 var parent = this.recentlyModifiedNodes[i].parent;
477 if (!parent)
478 continue;
479
480 var parentNodeItem = this.treeOutline.findTreeElement(parent);
481 if (parentNodeItem && !parentNodeItem.alreadyUpdatedChildren) {
482 parentNodeItem.updateChildren(replaced);
483 parentNodeItem.alreadyUpdatedChildren = true;
484 updatedParentTreeElements.push(parentNodeItem);
485 }
486
487 if (!updateBreadcrumbs && (this.focusedDOMNode === parent || isAnces torNode(this.focusedDOMNode, parent)))
488 updateBreadcrumbs = true;
489 }
490
491 for (var i = 0; i < updatedParentTreeElements.length; ++i)
492 delete updatedParentTreeElements[i].alreadyUpdatedChildren;
493
494 this.recentlyModifiedNodes = [];
495
496 if (updateBreadcrumbs)
497 this.updateBreadcrumb(true);
498 },
499
500 _stylesPaneEdited: function()
501 {
502 this.sidebarPanes.metrics.needsUpdate = true;
503 this.updateMetrics();
504 },
505
506 _metricsPaneEdited: function()
507 {
508 this.sidebarPanes.styles.needsUpdate = true;
509 this.updateStyles(true);
510 },
511
512 _mouseMovedInCrumbs: function(event)
513 {
514 var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY) ;
515 var crumbElement = nodeUnderMouse.enclosingNodeOrSelfWithClass("crumb");
516
517 WebInspector.hoveredDOMNode = (crumbElement ? crumbElement.representedOb ject : null);
518
519 if ("_mouseOutOfCrumbsTimeout" in this) {
520 clearTimeout(this._mouseOutOfCrumbsTimeout);
521 delete this._mouseOutOfCrumbsTimeout;
522 }
523 },
524
525 _mouseMovedOutOfCrumbs: function(event)
526 {
527 var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY) ;
528 if (nodeUnderMouse.isDescendant(this.crumbsElement))
529 return;
530
531 WebInspector.hoveredDOMNode = null;
532
533 this._mouseOutOfCrumbsTimeout = setTimeout(this.updateBreadcrumbSizes.bi nd(this), 1000);
534 },
535
536 updateBreadcrumb: function(forceUpdate)
537 {
538 if (!this.visible)
539 return;
540
541 var crumbs = this.crumbsElement;
542
543 var handled = false;
544 var foundRoot = false;
545 var crumb = crumbs.firstChild;
546 while (crumb) {
547 if (crumb.representedObject === this.rootDOMNode)
548 foundRoot = true;
549
550 if (foundRoot)
551 crumb.addStyleClass("dimmed");
552 else
553 crumb.removeStyleClass("dimmed");
554
555 if (crumb.representedObject === this.focusedDOMNode) {
556 crumb.addStyleClass("selected");
557 handled = true;
558 } else {
559 crumb.removeStyleClass("selected");
560 }
561
562 crumb = crumb.nextSibling;
563 }
564
565 if (handled && !forceUpdate) {
566 // We don't need to rebuild the crumbs, but we need to adjust sizes
567 // to reflect the new focused or root node.
568 this.updateBreadcrumbSizes();
569 return;
570 }
571
572 crumbs.removeChildren();
573
574 var panel = this;
575
576 function selectCrumbFunction(event)
577 {
578 var crumb = event.currentTarget;
579 if (crumb.hasStyleClass("collapsed")) {
580 // Clicking a collapsed crumb will expose the hidden crumbs.
581 if (crumb === panel.crumbsElement.firstChild) {
582 // If the focused crumb is the first child, pick the farthes t crumb
583 // that is still hidden. This allows the user to expose ever y crumb.
584 var currentCrumb = crumb;
585 while (currentCrumb) {
586 var hidden = currentCrumb.hasStyleClass("hidden");
587 var collapsed = currentCrumb.hasStyleClass("collapsed");
588 if (!hidden && !collapsed)
589 break;
590 crumb = currentCrumb;
591 currentCrumb = currentCrumb.nextSibling;
592 }
593 }
594
595 panel.updateBreadcrumbSizes(crumb);
596 } else {
597 // Clicking a dimmed crumb or double clicking (event.detail >= 2 )
598 // will change the root node in addition to the focused node.
599 if (event.detail >= 2 || crumb.hasStyleClass("dimmed"))
600 panel.rootDOMNode = crumb.representedObject.parentNode;
601 panel.focusedDOMNode = crumb.representedObject;
602 }
603
604 event.preventDefault();
605 }
606
607 foundRoot = false;
608 for (var current = this.focusedDOMNode; current; current = current.paren tNode) {
609 if (current.nodeType === Node.DOCUMENT_NODE)
610 continue;
611
612 if (current === this.rootDOMNode)
613 foundRoot = true;
614
615 var crumb = document.createElement("span");
616 crumb.className = "crumb";
617 crumb.representedObject = current;
618 crumb.addEventListener("mousedown", selectCrumbFunction, false);
619
620 var crumbTitle;
621 switch (current.nodeType) {
622 case Node.ELEMENT_NODE:
623 crumbTitle = current.nodeName.toLowerCase();
624
625 var nameElement = document.createElement("span");
626 nameElement.textContent = crumbTitle;
627 crumb.appendChild(nameElement);
628
629 var idAttribute = current.getAttribute("id");
630 if (idAttribute) {
631 var idElement = document.createElement("span");
632 crumb.appendChild(idElement);
633
634 var part = "#" + idAttribute;
635 crumbTitle += part;
636 idElement.appendChild(document.createTextNode(part));
637
638 // Mark the name as extra, since the ID is more importan t.
639 nameElement.className = "extra";
640 }
641
642 var classAttribute = current.getAttribute("class");
643 if (classAttribute) {
644 var classes = classAttribute.split(/\s+/);
645 var foundClasses = {};
646
647 if (classes.length) {
648 var classesElement = document.createElement("span");
649 classesElement.className = "extra";
650 crumb.appendChild(classesElement);
651
652 for (var i = 0; i < classes.length; ++i) {
653 var className = classes[i];
654 if (className && !(className in foundClasses)) {
655 var part = "." + className;
656 crumbTitle += part;
657 classesElement.appendChild(document.createTe xtNode(part));
658 foundClasses[className] = true;
659 }
660 }
661 }
662 }
663
664 break;
665
666 case Node.TEXT_NODE:
667 if (isNodeWhitespace.call(current))
668 crumbTitle = WebInspector.UIString("(whitespace)");
669 else
670 crumbTitle = WebInspector.UIString("(text)");
671 break
672
673 case Node.COMMENT_NODE:
674 crumbTitle = "<!-->";
675 break;
676
677 case Node.DOCUMENT_TYPE_NODE:
678 crumbTitle = "<!DOCTYPE>";
679 break;
680
681 default:
682 crumbTitle = current.nodeName.toLowerCase();
683 }
684
685 if (!crumb.childNodes.length) {
686 var nameElement = document.createElement("span");
687 nameElement.textContent = crumbTitle;
688 crumb.appendChild(nameElement);
689 }
690
691 crumb.title = crumbTitle;
692
693 if (foundRoot)
694 crumb.addStyleClass("dimmed");
695 if (current === this.focusedDOMNode)
696 crumb.addStyleClass("selected");
697 if (!crumbs.childNodes.length)
698 crumb.addStyleClass("end");
699
700 crumbs.appendChild(crumb);
701 }
702
703 if (crumbs.hasChildNodes())
704 crumbs.lastChild.addStyleClass("start");
705
706 this.updateBreadcrumbSizes();
707 },
708
709 updateBreadcrumbSizes: function(focusedCrumb)
710 {
711 if (!this.visible)
712 return;
713
714 if (document.body.offsetWidth <= 0) {
715 // The stylesheet hasn't loaded yet or the window is closed,
716 // so we can't calculate what is need. Return early.
717 return;
718 }
719
720 var crumbs = this.crumbsElement;
721 if (!crumbs.childNodes.length || crumbs.offsetWidth <= 0)
722 return; // No crumbs, do nothing.
723
724 // A Zero index is the right most child crumb in the breadcrumb.
725 var selectedIndex = 0;
726 var focusedIndex = 0;
727 var selectedCrumb;
728
729 var i = 0;
730 var crumb = crumbs.firstChild;
731 while (crumb) {
732 // Find the selected crumb and index.
733 if (!selectedCrumb && crumb.hasStyleClass("selected")) {
734 selectedCrumb = crumb;
735 selectedIndex = i;
736 }
737
738 // Find the focused crumb index.
739 if (crumb === focusedCrumb)
740 focusedIndex = i;
741
742 // Remove any styles that affect size before
743 // deciding to shorten any crumbs.
744 if (crumb !== crumbs.lastChild)
745 crumb.removeStyleClass("start");
746 if (crumb !== crumbs.firstChild)
747 crumb.removeStyleClass("end");
748
749 crumb.removeStyleClass("compact");
750 crumb.removeStyleClass("collapsed");
751 crumb.removeStyleClass("hidden");
752
753 crumb = crumb.nextSibling;
754 ++i;
755 }
756
757 // Restore the start and end crumb classes in case they got removed in c oalesceCollapsedCrumbs().
758 // The order of the crumbs in the document is opposite of the visual ord er.
759 crumbs.firstChild.addStyleClass("end");
760 crumbs.lastChild.addStyleClass("start");
761
762 function crumbsAreSmallerThanContainer()
763 {
764 var rightPadding = 20;
765 var errorWarningElement = document.getElementById("error-warning-cou nt");
766 if (!WebInspector.drawer.visible && errorWarningElement)
767 rightPadding += errorWarningElement.offsetWidth;
768 return ((crumbs.totalOffsetLeft + crumbs.offsetWidth + rightPadding) < window.innerWidth);
769 }
770
771 if (crumbsAreSmallerThanContainer())
772 return; // No need to compact the crumbs, they all fit at full size.
773
774 var BothSides = 0;
775 var AncestorSide = -1;
776 var ChildSide = 1;
777
778 function makeCrumbsSmaller(shrinkingFunction, direction, significantCrum b)
779 {
780 if (!significantCrumb)
781 significantCrumb = (focusedCrumb || selectedCrumb);
782
783 if (significantCrumb === selectedCrumb)
784 var significantIndex = selectedIndex;
785 else if (significantCrumb === focusedCrumb)
786 var significantIndex = focusedIndex;
787 else {
788 var significantIndex = 0;
789 for (var i = 0; i < crumbs.childNodes.length; ++i) {
790 if (crumbs.childNodes[i] === significantCrumb) {
791 significantIndex = i;
792 break;
793 }
794 }
795 }
796
797 function shrinkCrumbAtIndex(index)
798 {
799 var shrinkCrumb = crumbs.childNodes[index];
800 if (shrinkCrumb && shrinkCrumb !== significantCrumb)
801 shrinkingFunction(shrinkCrumb);
802 if (crumbsAreSmallerThanContainer())
803 return true; // No need to compact the crumbs more.
804 return false;
805 }
806
807 // Shrink crumbs one at a time by applying the shrinkingFunction unt il the crumbs
808 // fit in the container or we run out of crumbs to shrink.
809 if (direction) {
810 // Crumbs are shrunk on only one side (based on direction) of th e signifcant crumb.
811 var index = (direction > 0 ? 0 : crumbs.childNodes.length - 1);
812 while (index !== significantIndex) {
813 if (shrinkCrumbAtIndex(index))
814 return true;
815 index += (direction > 0 ? 1 : -1);
816 }
817 } else {
818 // Crumbs are shrunk in order of descending distance from the si gnifcant crumb,
819 // with a tie going to child crumbs.
820 var startIndex = 0;
821 var endIndex = crumbs.childNodes.length - 1;
822 while (startIndex != significantIndex || endIndex != significant Index) {
823 var startDistance = significantIndex - startIndex;
824 var endDistance = endIndex - significantIndex;
825 if (startDistance >= endDistance)
826 var index = startIndex++;
827 else
828 var index = endIndex--;
829 if (shrinkCrumbAtIndex(index))
830 return true;
831 }
832 }
833
834 // We are not small enough yet, return false so the caller knows.
835 return false;
836 }
837
838 function coalesceCollapsedCrumbs()
839 {
840 var crumb = crumbs.firstChild;
841 var collapsedRun = false;
842 var newStartNeeded = false;
843 var newEndNeeded = false;
844 while (crumb) {
845 var hidden = crumb.hasStyleClass("hidden");
846 if (!hidden) {
847 var collapsed = crumb.hasStyleClass("collapsed");
848 if (collapsedRun && collapsed) {
849 crumb.addStyleClass("hidden");
850 crumb.removeStyleClass("compact");
851 crumb.removeStyleClass("collapsed");
852
853 if (crumb.hasStyleClass("start")) {
854 crumb.removeStyleClass("start");
855 newStartNeeded = true;
856 }
857
858 if (crumb.hasStyleClass("end")) {
859 crumb.removeStyleClass("end");
860 newEndNeeded = true;
861 }
862
863 continue;
864 }
865
866 collapsedRun = collapsed;
867
868 if (newEndNeeded) {
869 newEndNeeded = false;
870 crumb.addStyleClass("end");
871 }
872 } else
873 collapsedRun = true;
874 crumb = crumb.nextSibling;
875 }
876
877 if (newStartNeeded) {
878 crumb = crumbs.lastChild;
879 while (crumb) {
880 if (!crumb.hasStyleClass("hidden")) {
881 crumb.addStyleClass("start");
882 break;
883 }
884 crumb = crumb.previousSibling;
885 }
886 }
887 }
888
889 function compact(crumb)
890 {
891 if (crumb.hasStyleClass("hidden"))
892 return;
893 crumb.addStyleClass("compact");
894 }
895
896 function collapse(crumb, dontCoalesce)
897 {
898 if (crumb.hasStyleClass("hidden"))
899 return;
900 crumb.addStyleClass("collapsed");
901 crumb.removeStyleClass("compact");
902 if (!dontCoalesce)
903 coalesceCollapsedCrumbs();
904 }
905
906 function compactDimmed(crumb)
907 {
908 if (crumb.hasStyleClass("dimmed"))
909 compact(crumb);
910 }
911
912 function collapseDimmed(crumb)
913 {
914 if (crumb.hasStyleClass("dimmed"))
915 collapse(crumb);
916 }
917
918 if (!focusedCrumb) {
919 // When not focused on a crumb we can be biased and collapse less im portant
920 // crumbs that the user might not care much about.
921
922 // Compact child crumbs.
923 if (makeCrumbsSmaller(compact, ChildSide))
924 return;
925
926 // Collapse child crumbs.
927 if (makeCrumbsSmaller(collapse, ChildSide))
928 return;
929
930 // Compact dimmed ancestor crumbs.
931 if (makeCrumbsSmaller(compactDimmed, AncestorSide))
932 return;
933
934 // Collapse dimmed ancestor crumbs.
935 if (makeCrumbsSmaller(collapseDimmed, AncestorSide))
936 return;
937 }
938
939 // Compact ancestor crumbs, or from both sides if focused.
940 if (makeCrumbsSmaller(compact, (focusedCrumb ? BothSides : AncestorSide) ))
941 return;
942
943 // Collapse ancestor crumbs, or from both sides if focused.
944 if (makeCrumbsSmaller(collapse, (focusedCrumb ? BothSides : AncestorSide )))
945 return;
946
947 if (!selectedCrumb)
948 return;
949
950 // Compact the selected crumb.
951 compact(selectedCrumb);
952 if (crumbsAreSmallerThanContainer())
953 return;
954
955 // Collapse the selected crumb as a last resort. Pass true to prevent co alescing.
956 collapse(selectedCrumb, true);
957 },
958
959 updateStyles: function(forceUpdate)
960 {
961 var stylesSidebarPane = this.sidebarPanes.styles;
962 if (!stylesSidebarPane.expanded || !stylesSidebarPane.needsUpdate)
963 return;
964
965 stylesSidebarPane.update(this.focusedDOMNode, null, forceUpdate);
966 stylesSidebarPane.needsUpdate = false;
967 },
968
969 updateMetrics: function()
970 {
971 var metricsSidebarPane = this.sidebarPanes.metrics;
972 if (!metricsSidebarPane.expanded || !metricsSidebarPane.needsUpdate)
973 return;
974
975 metricsSidebarPane.update(this.focusedDOMNode);
976 metricsSidebarPane.needsUpdate = false;
977 },
978
979 updateProperties: function()
980 {
981 var propertiesSidebarPane = this.sidebarPanes.properties;
982 if (!propertiesSidebarPane.expanded || !propertiesSidebarPane.needsUpdat e)
983 return;
984
985 propertiesSidebarPane.update(this.focusedDOMNode);
986 propertiesSidebarPane.needsUpdate = false;
987 },
988
989 updateEventListeners: function()
990 {
991 var eventListenersSidebarPane = this.sidebarPanes.eventListeners;
992 if (!eventListenersSidebarPane.expanded || !eventListenersSidebarPane.ne edsUpdate)
993 return;
994
995 eventListenersSidebarPane.update(this.focusedDOMNode);
996 eventListenersSidebarPane.needsUpdate = false;
997 },
998
999 handleKeyEvent: function(event)
1000 {
1001 this.treeOutline.handleKeyEvent(event);
1002 },
1003
1004 handleCopyEvent: function(event)
1005 {
1006 // Don't prevent the normal copy if the user has a selection.
1007 if (!window.getSelection().isCollapsed)
1008 return;
1009 event.clipboardData.clearData();
1010 event.preventDefault();
1011 InspectorController.copyNode(this.focusedDOMNode.id);
1012 },
1013
1014 rightSidebarResizerDragStart: function(event)
1015 {
1016 WebInspector.elementDragStart(this.sidebarElement, this.rightSidebarResi zerDrag.bind(this), this.rightSidebarResizerDragEnd.bind(this), event, "col-resi ze");
1017 },
1018
1019 rightSidebarResizerDragEnd: function(event)
1020 {
1021 WebInspector.elementDragEnd(event);
1022 },
1023
1024 rightSidebarResizerDrag: function(event)
1025 {
1026 var x = event.pageX;
1027 var newWidth = Number.constrain(window.innerWidth - x, Preferences.minEl ementsSidebarWidth, window.innerWidth * 0.66);
1028
1029 this.sidebarElement.style.width = newWidth + "px";
1030 this.contentElement.style.right = newWidth + "px";
1031 this.sidebarResizeElement.style.right = (newWidth - 3) + "px";
1032
1033 this.treeOutline.updateSelection();
1034
1035 event.preventDefault();
1036 },
1037
1038 _nodeSearchButtonClicked: function(event)
1039 {
1040 InspectorController.toggleNodeSearch();
1041
1042 this.nodeSearchButton.toggled = InspectorController.searchingForNode();
1043 }
1044 }
1045
1046 WebInspector.ElementsPanel.prototype.__proto__ = WebInspector.Panel.prototype;
OLDNEW
« no previous file with comments | « chrome/resources/inspector/Drawer.js ('k') | chrome/resources/inspector/ElementsTreeOutline.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698