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

Side by Side Diff: chrome_frame/tools/test/reference_build/chrome/resources/inspector/ElementsPanel.js

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

Powered by Google App Engine
This is Rietveld 408576698