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

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/elements/ElementsBreadcrumbs.js

Issue 2551403002: [DevTools] ElementsBreadcrumbs Perf Improvements & Cleanup (Closed)
Patch Set: address more feedback Created 4 years 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
« no previous file with comments | « third_party/WebKit/LayoutTests/inspector/elements/shadow/breadcrumb-shadow-roots.html ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 /** 4 /**
5 * @unrestricted 5 * @unrestricted
6 */ 6 */
7 Elements.ElementsBreadcrumbs = class extends UI.HBox { 7 Elements.ElementsBreadcrumbs = class extends UI.HBox {
8 constructor() { 8 constructor() {
9 super(true); 9 super(true);
10 this.registerRequiredCSS('elements/breadcrumbs.css'); 10 this.registerRequiredCSS('elements/breadcrumbs.css');
(...skipping 25 matching lines...) Expand all
36 return; 36 return;
37 } 37 }
38 } 38 }
39 } 39 }
40 40
41 /** 41 /**
42 * @param {?SDK.DOMNode} node 42 * @param {?SDK.DOMNode} node
43 */ 43 */
44 setSelectedNode(node) { 44 setSelectedNode(node) {
45 this._currentDOMNode = node; 45 this._currentDOMNode = node;
46 this.update(); 46 this.crumbsElement.window().requestAnimationFrame(() => this.update());
47 } 47 }
48 48
49 _mouseMovedInCrumbs(event) { 49 _mouseMovedInCrumbs(event) {
50 var nodeUnderMouse = event.target; 50 var nodeUnderMouse = event.target;
51 var crumbElement = nodeUnderMouse.enclosingNodeOrSelfWithClass('crumb'); 51 var crumbElement = nodeUnderMouse.enclosingNodeOrSelfWithClass('crumb');
52 var node = /** @type {?SDK.DOMNode} */ (crumbElement ? crumbElement[this._no deSymbol] : null); 52 var node = /** @type {?SDK.DOMNode} */ (crumbElement ? crumbElement[this._no deSymbol] : null);
53 if (node) 53 if (node)
54 node.highlight(); 54 node.highlight();
55 } 55 }
56 56
57 _mouseMovedOutOfCrumbs(event) { 57 _mouseMovedOutOfCrumbs(event) {
58 if (this._currentDOMNode) 58 if (this._currentDOMNode)
59 SDK.DOMModel.hideDOMNodeHighlight(); 59 SDK.DOMModel.hideDOMNodeHighlight();
60 } 60 }
61 61
62
63 /**
64 * @param {!Event} event
65 * @this {Elements.ElementsBreadcrumbs}
66 */
67 _onClickCrumb(event) {
68 event.preventDefault();
69 var crumb = /** @type {!Element} */ (event.currentTarget);
70 if (!crumb.classList.contains('collapsed')) {
71 this.dispatchEventToListeners(Elements.ElementsBreadcrumbs.Events.NodeSele cted, crumb[this._nodeSymbol]);
72 return;
73 }
74
75 // Clicking a collapsed crumb will expose the hidden crumbs.
76 if (crumb === this.crumbsElement.firstChild) {
77 // If the clicked crumb is the first child, pick the farthest crumb
78 // that is still hidden. This allows the user to expose every crumb.
79 var currentCrumb = crumb;
80 while (currentCrumb) {
81 var hidden = currentCrumb.classList.contains('hidden');
82 var collapsed = currentCrumb.classList.contains('collapsed');
83 if (!hidden && !collapsed)
84 break;
85 crumb = currentCrumb;
86 currentCrumb = currentCrumb.nextSiblingElement;
87 }
88 }
89
90 this.updateSizes(crumb);
91 }
92
93 /**
94 * @param {!SDK.DOMNode} domNode
95 * @return {?string}
96 */
97 _determineElementTitle(domNode) {
98 switch (domNode.nodeType()) {
99 case Node.ELEMENT_NODE:
100 if (domNode.pseudoType())
101 return '::' + domNode.pseudoType();
102 return null;
103 case Node.TEXT_NODE:
104 return Common.UIString('(text)');
105 case Node.COMMENT_NODE:
106 return '<!-->';
107 case Node.DOCUMENT_TYPE_NODE:
108 return '<!DOCTYPE>';
109 case Node.DOCUMENT_FRAGMENT_NODE:
110 return domNode.shadowRootType() ? '#shadow-root' : domNode.nodeNameInCor rectCase();
111 default:
112 return domNode.nodeNameInCorrectCase();
113 }
114 }
115
62 /** 116 /**
63 * @param {boolean=} force 117 * @param {boolean=} force
64 */ 118 */
65 update(force) { 119 update(force) {
66 if (!this.isShowing()) 120 if (!this.isShowing())
67 return; 121 return;
68 122
69 var currentDOMNode = this._currentDOMNode; 123 var currentDOMNode = this._currentDOMNode;
70 var crumbs = this.crumbsElement; 124 var crumbs = this.crumbsElement;
71 125
(...skipping 12 matching lines...) Expand all
84 138
85 if (handled && !force) { 139 if (handled && !force) {
86 // We don't need to rebuild the crumbs, but we need to adjust sizes 140 // We don't need to rebuild the crumbs, but we need to adjust sizes
87 // to reflect the new focused or root node. 141 // to reflect the new focused or root node.
88 this.updateSizes(); 142 this.updateSizes();
89 return; 143 return;
90 } 144 }
91 145
92 crumbs.removeChildren(); 146 crumbs.removeChildren();
93 147
94 var panel = this;
95
96 /**
97 * @param {!Event} event
98 * @this {Elements.ElementsBreadcrumbs}
99 */
100 function selectCrumb(event) {
101 event.preventDefault();
102 var crumb = /** @type {!Element} */ (event.currentTarget);
103 if (!crumb.classList.contains('collapsed')) {
104 this.dispatchEventToListeners(Elements.ElementsBreadcrumbs.Events.NodeSe lected, crumb[this._nodeSymbol]);
105 return;
106 }
107
108 // Clicking a collapsed crumb will expose the hidden crumbs.
109 if (crumb === panel.crumbsElement.firstChild) {
110 // If the focused crumb is the first child, pick the farthest crumb
111 // that is still hidden. This allows the user to expose every crumb.
112 var currentCrumb = crumb;
113 while (currentCrumb) {
114 var hidden = currentCrumb.classList.contains('hidden');
115 var collapsed = currentCrumb.classList.contains('collapsed');
116 if (!hidden && !collapsed)
117 break;
118 crumb = currentCrumb;
119 currentCrumb = currentCrumb.nextSiblingElement;
120 }
121 }
122
123 this.updateSizes(crumb);
124 }
125
126 var boundSelectCrumb = selectCrumb.bind(this);
127 for (var current = currentDOMNode; current; current = current.parentNode) { 148 for (var current = currentDOMNode; current; current = current.parentNode) {
128 if (current.nodeType() === Node.DOCUMENT_NODE) 149 if (current.nodeType() === Node.DOCUMENT_NODE)
129 continue; 150 continue;
130 151
131 crumb = createElementWithClass('span', 'crumb'); 152 crumb = createElementWithClass('span', 'crumb');
132 crumb[this._nodeSymbol] = current; 153 crumb[this._nodeSymbol] = current;
133 crumb.addEventListener('mousedown', boundSelectCrumb, false); 154 crumb.addEventListener('mousedown', this._onClickCrumb.bind(this), false);
134 155
135 var crumbTitle = ''; 156 var crumbTitle = this._determineElementTitle(current);
136 switch (current.nodeType()) { 157 if (crumbTitle) {
137 case Node.ELEMENT_NODE:
138 if (current.pseudoType())
139 crumbTitle = '::' + current.pseudoType();
140 else
141 Components.DOMPresentationUtils.decorateNodeLabel(current, crumb);
142 break;
143
144 case Node.TEXT_NODE:
145 crumbTitle = Common.UIString('(text)');
146 break;
147
148 case Node.COMMENT_NODE:
149 crumbTitle = '<!-->';
150 break;
151
152 case Node.DOCUMENT_TYPE_NODE:
153 crumbTitle = '<!DOCTYPE>';
154 break;
155
156 case Node.DOCUMENT_FRAGMENT_NODE:
157 crumbTitle = current.shadowRootType() ? '#shadow-root' : current.nodeN ameInCorrectCase();
158 break;
159
160 default:
161 crumbTitle = current.nodeNameInCorrectCase();
162 }
163
164 if (!crumb.childNodes.length) {
165 var nameElement = createElement('span'); 158 var nameElement = createElement('span');
166 nameElement.textContent = crumbTitle; 159 nameElement.textContent = crumbTitle;
167 crumb.appendChild(nameElement); 160 crumb.appendChild(nameElement);
168 crumb.title = crumbTitle; 161 crumb.title = crumbTitle;
162 } else {
163 Components.DOMPresentationUtils.decorateNodeLabel(current, crumb);
169 } 164 }
170 165
171 if (current === currentDOMNode) 166 if (current === currentDOMNode)
172 crumb.classList.add('selected'); 167 crumb.classList.add('selected');
173 crumbs.insertBefore(crumb, crumbs.firstChild); 168 crumbs.insertBefore(crumb, crumbs.firstChild);
174 } 169 }
175 170
176 this.updateSizes(); 171 this.updateSizes();
177 } 172 }
178 173
179 /** 174 /**
180 * @param {!Element=} focusedCrumb 175 * @param {!Element=} focusedCrumb
176 * @return {{selectedIndex: number, focusedIndex: number, selectedCrumb: ?Elem ent}}
181 */ 177 */
182 updateSizes(focusedCrumb) { 178 _resetCrumbStylesAndFindSelections(focusedCrumb) {
183 if (!this.isShowing())
184 return;
185
186 var crumbs = this.crumbsElement; 179 var crumbs = this.crumbsElement;
187 if (!crumbs.firstChild)
188 return;
189
190 var selectedIndex = 0; 180 var selectedIndex = 0;
191 var focusedIndex = 0; 181 var focusedIndex = 0;
192 var selectedCrumb; 182 var selectedCrumb = null;
193 183
194 // Reset crumb styles. 184 // Reset crumb styles.
195 for (var i = 0; i < crumbs.childNodes.length; ++i) { 185 for (var i = 0; i < crumbs.childNodes.length; ++i) {
196 var crumb = crumbs.children[i]; 186 var crumb = crumbs.children[i];
197 // Find the selected crumb and index. 187 // Find the selected crumb and index.
198 if (!selectedCrumb && crumb.classList.contains('selected')) { 188 if (!selectedCrumb && crumb.classList.contains('selected')) {
199 selectedCrumb = crumb; 189 selectedCrumb = crumb;
200 selectedIndex = i; 190 selectedIndex = i;
201 } 191 }
202 192
203 // Find the focused crumb index. 193 // Find the focused crumb index.
204 if (crumb === focusedCrumb) 194 if (crumb === focusedCrumb)
205 focusedIndex = i; 195 focusedIndex = i;
206 196
207 crumb.classList.remove('compact', 'collapsed', 'hidden'); 197 crumb.classList.remove('compact', 'collapsed', 'hidden');
208 } 198 }
209 199
210 // Layout 1: Measure total and normal crumb sizes 200 return {selectedIndex: selectedIndex, focusedIndex: focusedIndex, selectedCr umb: selectedCrumb};
211 var contentElementWidth = this.contentElement.offsetWidth; 201 }
202
203 /**
204 * @return {{normal: !Array.<number>, compact: !Array.<number>, collapsed: num ber, available: number}}
205 */
206 _measureElementSizes() {
207 var crumbs = this.crumbsElement;
208
209 // Layout 1: Measure total and normal crumb sizes at the same time as a
210 // dummy element for the collapsed size.
211 var collapsedElement = createElementWithClass('span', 'crumb collapsed');
212 crumbs.insertBefore(collapsedElement, crumbs.firstChild);
213
214 var available = crumbs.offsetWidth;
215 var collapsed = collapsedElement.offsetWidth;
216
212 var normalSizes = []; 217 var normalSizes = [];
213 for (var i = 0; i < crumbs.childNodes.length; ++i) { 218 for (var i = 1; i < crumbs.childNodes.length; ++i) {
214 var crumb = crumbs.childNodes[i]; 219 var crumb = crumbs.childNodes[i];
215 normalSizes[i] = crumb.offsetWidth; 220 normalSizes[i - 1] = crumb.offsetWidth;
216 } 221 }
217 222
223 crumbs.removeChild(collapsedElement);
224
218 // Layout 2: Measure collapsed crumb sizes 225 // Layout 2: Measure collapsed crumb sizes
219 var compactSizes = []; 226 var compactSizes = [];
220 for (var i = 0; i < crumbs.childNodes.length; ++i) { 227 for (var i = 0; i < crumbs.childNodes.length; ++i) {
221 var crumb = crumbs.childNodes[i]; 228 var crumb = crumbs.childNodes[i];
222 crumb.classList.add('compact'); 229 crumb.classList.add('compact');
223 } 230 }
224 for (var i = 0; i < crumbs.childNodes.length; ++i) { 231 for (var i = 0; i < crumbs.childNodes.length; ++i) {
225 var crumb = crumbs.childNodes[i]; 232 var crumb = crumbs.childNodes[i];
226 compactSizes[i] = crumb.offsetWidth; 233 compactSizes[i] = crumb.offsetWidth;
227 } 234 }
228 235
229 // Layout 3: Measure collapsed crumb size
230 crumbs.firstChild.classList.add('collapsed');
231 var collapsedSize = crumbs.firstChild.offsetWidth;
232
233 // Clean up. 236 // Clean up.
234 for (var i = 0; i < crumbs.childNodes.length; ++i) { 237 for (var i = 0; i < crumbs.childNodes.length; ++i) {
235 var crumb = crumbs.childNodes[i]; 238 var crumb = crumbs.childNodes[i];
236 crumb.classList.remove('compact', 'collapsed'); 239 crumb.classList.remove('compact', 'collapsed');
237 } 240 }
238 241
242 return {normal: normalSizes, compact: compactSizes, collapsed: collapsed, av ailable: available};
243 }
244
245 /**
246 * @param {!Element=} focusedCrumb
247 */
248 updateSizes(focusedCrumb) {
249 if (!this.isShowing())
250 return;
251
252 var crumbs = this.crumbsElement;
253 if (!crumbs.firstChild)
254 return;
255
256 var selections = this._resetCrumbStylesAndFindSelections(focusedCrumb);
257 var sizes = this._measureElementSizes();
258 var selectedIndex = selections.selectedIndex;
259 var focusedIndex = selections.focusedIndex;
260 var selectedCrumb = selections.selectedCrumb;
261
239 function crumbsAreSmallerThanContainer() { 262 function crumbsAreSmallerThanContainer() {
240 var totalSize = 0; 263 var totalSize = 0;
241 for (var i = 0; i < crumbs.childNodes.length; ++i) { 264 for (var i = 0; i < crumbs.childNodes.length; ++i) {
242 var crumb = crumbs.childNodes[i]; 265 var crumb = crumbs.childNodes[i];
243 if (crumb.classList.contains('hidden')) 266 if (crumb.classList.contains('hidden'))
244 continue; 267 continue;
245 if (crumb.classList.contains('collapsed')) { 268 if (crumb.classList.contains('collapsed')) {
246 totalSize += collapsedSize; 269 totalSize += sizes.collapsed;
247 continue; 270 continue;
248 } 271 }
249 totalSize += crumb.classList.contains('compact') ? compactSizes[i] : nor malSizes[i]; 272 totalSize += crumb.classList.contains('compact') ? sizes.compact[i] : si zes.normal[i];
250 } 273 }
251 const rightPadding = 10; 274 const rightPadding = 10;
252 return totalSize + rightPadding < contentElementWidth; 275 return totalSize + rightPadding < sizes.available;
253 } 276 }
254 277
255 if (crumbsAreSmallerThanContainer()) 278 if (crumbsAreSmallerThanContainer())
256 return; // No need to compact the crumbs, they all fit at full size. 279 return; // No need to compact the crumbs, they all fit at full size.
257 280
258 var BothSides = 0; 281 var BothSides = 0;
259 var AncestorSide = -1; 282 var AncestorSide = -1;
260 var ChildSide = 1; 283 var ChildSide = 1;
261 284
262 /** 285 /**
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 434
412 // Collapse the selected crumb as a last resort. Pass true to prevent coales cing. 435 // Collapse the selected crumb as a last resort. Pass true to prevent coales cing.
413 collapse(selectedCrumb, true); 436 collapse(selectedCrumb, true);
414 } 437 }
415 }; 438 };
416 439
417 /** @enum {symbol} */ 440 /** @enum {symbol} */
418 Elements.ElementsBreadcrumbs.Events = { 441 Elements.ElementsBreadcrumbs.Events = {
419 NodeSelected: Symbol('NodeSelected') 442 NodeSelected: Symbol('NodeSelected')
420 }; 443 };
OLDNEW
« no previous file with comments | « third_party/WebKit/LayoutTests/inspector/elements/shadow/breadcrumb-shadow-roots.html ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698