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

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

Issue 2551403002: [DevTools] ElementsBreadcrumbs Perf Improvements & Cleanup (Closed)
Patch Set: Include performance improvements 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 * @param {!Element} crumbElement
96 * @return {?string}
97 */
98 _determineElementTitle(domNode, crumbElement) {
99 switch (domNode.nodeType()) {
100 case Node.ELEMENT_NODE:
101 if (domNode.pseudoType()) {
102 return '::' + domNode.pseudoType();
103 } else {
lushnikov 2016/12/08 05:37:03 style: no "else" after the "then" branch was termi
phulce 2016/12/08 19:03:27 done, should I apply that to all the case statemen
104 Components.DOMPresentationUtils.decorateNodeLabel(domNode, crumbElemen t);
105 return null;
106 }
107 break;
108
109 case Node.TEXT_NODE:
110 return Common.UIString('(text)');
111 break;
112
113 case Node.COMMENT_NODE:
114 return '<!-->';
115 break;
116
117 case Node.DOCUMENT_TYPE_NODE:
118 return '<!DOCTYPE>';
119 break;
120
121 case Node.DOCUMENT_FRAGMENT_NODE:
122 return domNode.shadowRootType() ? '#shadow-root' : domNode.nodeNameInCor rectCase();
123 break;
124
125 default:
126 return domNode.nodeNameInCorrectCase();
127 }
128 }
129
62 /** 130 /**
63 * @param {boolean=} force 131 * @param {boolean=} force
64 */ 132 */
65 update(force) { 133 update(force) {
66 if (!this.isShowing()) 134 if (!this.isShowing())
67 return; 135 return;
68 136
69 var currentDOMNode = this._currentDOMNode; 137 var currentDOMNode = this._currentDOMNode;
70 var crumbs = this.crumbsElement; 138 var crumbs = this.crumbsElement;
71 139
(...skipping 12 matching lines...) Expand all
84 152
85 if (handled && !force) { 153 if (handled && !force) {
86 // We don't need to rebuild the crumbs, but we need to adjust sizes 154 // We don't need to rebuild the crumbs, but we need to adjust sizes
87 // to reflect the new focused or root node. 155 // to reflect the new focused or root node.
88 this.updateSizes(); 156 this.updateSizes();
89 return; 157 return;
90 } 158 }
91 159
92 crumbs.removeChildren(); 160 crumbs.removeChildren();
93 161
94 var panel = this; 162 var onClickCrumb = this._onClickCrumb.bind(this);
lushnikov 2016/12/08 05:37:03 can we inline this?
phulce 2016/12/08 19:03:27 sure, we'll bind inside a loop but I guess the bre
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) { 163 for (var current = currentDOMNode; current; current = current.parentNode) {
128 if (current.nodeType() === Node.DOCUMENT_NODE) 164 if (current.nodeType() === Node.DOCUMENT_NODE)
129 continue; 165 continue;
130 166
131 crumb = createElementWithClass('span', 'crumb'); 167 crumb = createElementWithClass('span', 'crumb');
132 crumb[this._nodeSymbol] = current; 168 crumb[this._nodeSymbol] = current;
133 crumb.addEventListener('mousedown', boundSelectCrumb, false); 169 crumb.addEventListener('mousedown', onClickCrumb, false);
134 170
135 var crumbTitle = ''; 171 var crumbTitle = this._determineElementTitle(current, crumb);
136 switch (current.nodeType()) { 172 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'); 173 var nameElement = createElement('span');
166 nameElement.textContent = crumbTitle; 174 nameElement.textContent = crumbTitle;
167 crumb.appendChild(nameElement); 175 crumb.appendChild(nameElement);
168 crumb.title = crumbTitle; 176 crumb.title = crumbTitle;
169 } 177 }
170 178
171 if (current === currentDOMNode) 179 if (current === currentDOMNode)
172 crumb.classList.add('selected'); 180 crumb.classList.add('selected');
173 crumbs.insertBefore(crumb, crumbs.firstChild); 181 crumbs.insertBefore(crumb, crumbs.firstChild);
174 } 182 }
175 183
176 this.updateSizes(); 184 this.updateSizes();
177 } 185 }
178 186
179 /** 187 /**
180 * @param {!Element=} focusedCrumb 188 * @param {!Element=} focusedCrumb
189 * @return {!Object}
181 */ 190 */
182 updateSizes(focusedCrumb) { 191 _resetCrumbStylesAndFindSelections(focusedCrumb) {
183 if (!this.isShowing())
184 return;
185
186 var crumbs = this.crumbsElement; 192 var crumbs = this.crumbsElement;
187 if (!crumbs.firstChild)
188 return;
189
190 var selectedIndex = 0; 193 var selectedIndex = 0;
191 var focusedIndex = 0; 194 var focusedIndex = 0;
192 var selectedCrumb; 195 var selectedCrumb;
193 196
194 // Reset crumb styles. 197 // Reset crumb styles.
195 for (var i = 0; i < crumbs.childNodes.length; ++i) { 198 for (var i = 0; i < crumbs.childNodes.length; ++i) {
196 var crumb = crumbs.children[i]; 199 var crumb = crumbs.children[i];
197 // Find the selected crumb and index. 200 // Find the selected crumb and index.
198 if (!selectedCrumb && crumb.classList.contains('selected')) { 201 if (!selectedCrumb && crumb.classList.contains('selected')) {
199 selectedCrumb = crumb; 202 selectedCrumb = crumb;
200 selectedIndex = i; 203 selectedIndex = i;
201 } 204 }
202 205
203 // Find the focused crumb index. 206 // Find the focused crumb index.
204 if (crumb === focusedCrumb) 207 if (crumb === focusedCrumb)
205 focusedIndex = i; 208 focusedIndex = i;
206 209
207 crumb.classList.remove('compact', 'collapsed', 'hidden'); 210 crumb.classList.remove('compact', 'collapsed', 'hidden');
208 } 211 }
209 212
210 // Layout 1: Measure total and normal crumb sizes 213 return {selectedIndex, focusedIndex, selectedCrumb};
211 var contentElementWidth = this.contentElement.offsetWidth; 214 }
212 var normalSizes = []; 215
213 for (var i = 0; i < crumbs.childNodes.length; ++i) { 216 /**
217 * @return {!Object}
218 */
219 _measureElementSizes() {
220 var crumbs = this.crumbsElement;
221
222 // Layout 1: Measure total and normal crumb sizes at the same time as a
223 // dummy element for the collapsed size
224 var collapsedElem = createElementWithClass('span', 'crumb collapsed');
225 crumbs.insertBefore(collapsedElem, crumbs.firstChild);
226
227 var available = crumbs.offsetWidth;
lushnikov 2016/12/08 05:37:03 can we use .measurePrefferedSize() method?
phulce 2016/12/08 19:03:27 oh, jw why would that be better? looks like that w
228 var collapsed = crumbs.firstChild.offsetWidth;
229
230 var normal = [];
231 for (var i = 1; i < crumbs.childNodes.length; ++i) {
214 var crumb = crumbs.childNodes[i]; 232 var crumb = crumbs.childNodes[i];
215 normalSizes[i] = crumb.offsetWidth; 233 normal[i - 1] = crumb.offsetWidth;
216 } 234 }
217 235
236 crumbs.removeChild(collapsedElem);
237
218 // Layout 2: Measure collapsed crumb sizes 238 // Layout 2: Measure collapsed crumb sizes
219 var compactSizes = []; 239 var compact = [];
220 for (var i = 0; i < crumbs.childNodes.length; ++i) { 240 for (var i = 0; i < crumbs.childNodes.length; ++i) {
221 var crumb = crumbs.childNodes[i]; 241 var crumb = crumbs.childNodes[i];
222 crumb.classList.add('compact'); 242 crumb.classList.add('compact');
223 } 243 }
224 for (var i = 0; i < crumbs.childNodes.length; ++i) { 244 for (var i = 0; i < crumbs.childNodes.length; ++i) {
225 var crumb = crumbs.childNodes[i]; 245 var crumb = crumbs.childNodes[i];
226 compactSizes[i] = crumb.offsetWidth; 246 compact[i] = crumb.offsetWidth;
227 } 247 }
228 248
229 // Layout 3: Measure collapsed crumb size
230 crumbs.firstChild.classList.add('collapsed');
231 var collapsedSize = crumbs.firstChild.offsetWidth;
232
233 // Clean up. 249 // Clean up.
234 for (var i = 0; i < crumbs.childNodes.length; ++i) { 250 for (var i = 0; i < crumbs.childNodes.length; ++i) {
235 var crumb = crumbs.childNodes[i]; 251 var crumb = crumbs.childNodes[i];
236 crumb.classList.remove('compact', 'collapsed'); 252 crumb.classList.remove('compact', 'collapsed');
237 } 253 }
238 254
255 return {normal, compact, collapsed, available};
lushnikov 2016/12/08 05:37:03 so far we don't use shorthand notation yet. No one
phulce 2016/12/08 19:03:27 apparently it does :) haha will remove for now
256 }
257
258 /**
259 * @param {!Element=} focusedCrumb
260 */
261 updateSizes(focusedCrumb) {
262 if (!this.isShowing())
263 return;
264
265 var crumbs = this.crumbsElement;
266 if (!crumbs.firstChild)
267 return;
268
269 var selections = this._resetCrumbStylesAndFindSelections(focusedCrumb);
270 var sizes = this._measureElementSizes();
271 var selectedIndex = selections.selectedIndex;
272 var focusedIndex = selections.focusedIndex;
273 var selectedCrumb = selections.selectedCrumb;
274
239 function crumbsAreSmallerThanContainer() { 275 function crumbsAreSmallerThanContainer() {
240 var totalSize = 0; 276 var totalSize = 0;
241 for (var i = 0; i < crumbs.childNodes.length; ++i) { 277 for (var i = 0; i < crumbs.childNodes.length; ++i) {
242 var crumb = crumbs.childNodes[i]; 278 var crumb = crumbs.childNodes[i];
243 if (crumb.classList.contains('hidden')) 279 if (crumb.classList.contains('hidden'))
244 continue; 280 continue;
245 if (crumb.classList.contains('collapsed')) { 281 if (crumb.classList.contains('collapsed')) {
246 totalSize += collapsedSize; 282 totalSize += sizes.collapsed;
247 continue; 283 continue;
248 } 284 }
249 totalSize += crumb.classList.contains('compact') ? compactSizes[i] : nor malSizes[i]; 285 totalSize += crumb.classList.contains('compact') ? sizes.compact[i] : si zes.normal[i];
250 } 286 }
251 const rightPadding = 10; 287 const rightPadding = 10;
252 return totalSize + rightPadding < contentElementWidth; 288 return totalSize + rightPadding < sizes.available;
253 } 289 }
254 290
255 if (crumbsAreSmallerThanContainer()) 291 if (crumbsAreSmallerThanContainer())
256 return; // No need to compact the crumbs, they all fit at full size. 292 return; // No need to compact the crumbs, they all fit at full size.
257 293
258 var BothSides = 0; 294 var BothSides = 0;
259 var AncestorSide = -1; 295 var AncestorSide = -1;
260 var ChildSide = 1; 296 var ChildSide = 1;
261 297
262 /** 298 /**
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 447
412 // Collapse the selected crumb as a last resort. Pass true to prevent coales cing. 448 // Collapse the selected crumb as a last resort. Pass true to prevent coales cing.
413 collapse(selectedCrumb, true); 449 collapse(selectedCrumb, true);
414 } 450 }
415 }; 451 };
416 452
417 /** @enum {symbol} */ 453 /** @enum {symbol} */
418 Elements.ElementsBreadcrumbs.Events = { 454 Elements.ElementsBreadcrumbs.Events = {
419 NodeSelected: Symbol('NodeSelected') 455 NodeSelected: Symbol('NodeSelected')
420 }; 456 };
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