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

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 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 * @param {!Element} crumbElement
96 * @return {?string}
97 */
98 _determineElementTitle(domNode, crumbElement) {
lushnikov 2016/12/08 21:20:43 I would expect this method to accept only a domNod
phulce 2016/12/09 00:46:30 Done.
99 switch (domNode.nodeType()) {
100 case Node.ELEMENT_NODE:
101 if (domNode.pseudoType())
102 return '::' + domNode.pseudoType();
103
104 Components.DOMPresentationUtils.decorateNodeLabel(domNode, crumbElement) ;
105 return null;
106 case Node.TEXT_NODE:
107 return Common.UIString('(text)');
108 case Node.COMMENT_NODE:
109 return '<!-->';
110 case Node.DOCUMENT_TYPE_NODE:
111 return '<!DOCTYPE>';
112 case Node.DOCUMENT_FRAGMENT_NODE:
113 return domNode.shadowRootType() ? '#shadow-root' : domNode.nodeNameInCor rectCase();
114 default:
115 return domNode.nodeNameInCorrectCase();
116 }
117 }
118
62 /** 119 /**
63 * @param {boolean=} force 120 * @param {boolean=} force
64 */ 121 */
65 update(force) { 122 update(force) {
66 if (!this.isShowing()) 123 if (!this.isShowing())
67 return; 124 return;
68 125
69 var currentDOMNode = this._currentDOMNode; 126 var currentDOMNode = this._currentDOMNode;
70 var crumbs = this.crumbsElement; 127 var crumbs = this.crumbsElement;
71 128
(...skipping 12 matching lines...) Expand all
84 141
85 if (handled && !force) { 142 if (handled && !force) {
86 // We don't need to rebuild the crumbs, but we need to adjust sizes 143 // We don't need to rebuild the crumbs, but we need to adjust sizes
87 // to reflect the new focused or root node. 144 // to reflect the new focused or root node.
88 this.updateSizes(); 145 this.updateSizes();
89 return; 146 return;
90 } 147 }
91 148
92 crumbs.removeChildren(); 149 crumbs.removeChildren();
93 150
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) { 151 for (var current = currentDOMNode; current; current = current.parentNode) {
128 if (current.nodeType() === Node.DOCUMENT_NODE) 152 if (current.nodeType() === Node.DOCUMENT_NODE)
129 continue; 153 continue;
130 154
131 crumb = createElementWithClass('span', 'crumb'); 155 crumb = createElementWithClass('span', 'crumb');
132 crumb[this._nodeSymbol] = current; 156 crumb[this._nodeSymbol] = current;
133 crumb.addEventListener('mousedown', boundSelectCrumb, false); 157 crumb.addEventListener('mousedown', this._onClickCrumb.bind(this), false);
134 158
135 var crumbTitle = ''; 159 var crumbTitle = this._determineElementTitle(current, crumb);
136 switch (current.nodeType()) { 160 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'); 161 var nameElement = createElement('span');
166 nameElement.textContent = crumbTitle; 162 nameElement.textContent = crumbTitle;
167 crumb.appendChild(nameElement); 163 crumb.appendChild(nameElement);
168 crumb.title = crumbTitle; 164 crumb.title = crumbTitle;
169 } 165 }
170 166
171 if (current === currentDOMNode) 167 if (current === currentDOMNode)
172 crumb.classList.add('selected'); 168 crumb.classList.add('selected');
173 crumbs.insertBefore(crumb, crumbs.firstChild); 169 crumbs.insertBefore(crumb, crumbs.firstChild);
174 } 170 }
175 171
176 this.updateSizes(); 172 this.updateSizes();
177 } 173 }
178 174
179 /** 175 /**
180 * @param {!Element=} focusedCrumb 176 * @param {!Element=} focusedCrumb
177 * @return {!Object}
lushnikov 2016/12/08 21:20:43 let's annotate it with details: {{selectedIndex: n
phulce 2016/12/09 00:46:30 Done.
181 */ 178 */
182 updateSizes(focusedCrumb) { 179 _resetCrumbStylesAndFindSelections(focusedCrumb) {
183 if (!this.isShowing())
184 return;
185
186 var crumbs = this.crumbsElement; 180 var crumbs = this.crumbsElement;
187 if (!crumbs.firstChild)
188 return;
189
190 var selectedIndex = 0; 181 var selectedIndex = 0;
191 var focusedIndex = 0; 182 var focusedIndex = 0;
192 var selectedCrumb; 183 var selectedCrumb;
193 184
194 // Reset crumb styles. 185 // Reset crumb styles.
195 for (var i = 0; i < crumbs.childNodes.length; ++i) { 186 for (var i = 0; i < crumbs.childNodes.length; ++i) {
196 var crumb = crumbs.children[i]; 187 var crumb = crumbs.children[i];
197 // Find the selected crumb and index. 188 // Find the selected crumb and index.
198 if (!selectedCrumb && crumb.classList.contains('selected')) { 189 if (!selectedCrumb && crumb.classList.contains('selected')) {
199 selectedCrumb = crumb; 190 selectedCrumb = crumb;
200 selectedIndex = i; 191 selectedIndex = i;
201 } 192 }
202 193
203 // Find the focused crumb index. 194 // Find the focused crumb index.
204 if (crumb === focusedCrumb) 195 if (crumb === focusedCrumb)
205 focusedIndex = i; 196 focusedIndex = i;
206 197
207 crumb.classList.remove('compact', 'collapsed', 'hidden'); 198 crumb.classList.remove('compact', 'collapsed', 'hidden');
208 } 199 }
209 200
210 // Layout 1: Measure total and normal crumb sizes 201 return {selectedIndex, focusedIndex, selectedCrumb};
lushnikov 2016/12/08 21:20:43 nit: let's avoid object shorthands here as well
phulce 2016/12/09 00:46:30 Done.
211 var contentElementWidth = this.contentElement.offsetWidth; 202 }
203
204 /**
205 * @return {!Object}
lushnikov 2016/12/08 21:20:43 let's annotate this with details
phulce 2016/12/09 00:46:30 Done.
206 */
207 _measureElementSizes() {
208 var crumbs = this.crumbsElement;
209
210 // Layout 1: Measure total and normal crumb sizes at the same time as a
211 // dummy element for the collapsed size
lushnikov 2016/12/08 21:20:43 style: "." in the end of the comment
phulce 2016/12/09 00:46:30 Done.
212 var collapsedElem = createElementWithClass('span', 'crumb collapsed');
lushnikov 2016/12/08 21:20:43 var collapsedElement = ... style: we try to avoid
phulce 2016/12/09 00:46:30 Done.
213 crumbs.insertBefore(collapsedElem, crumbs.firstChild);
214
215 var available = crumbs.offsetWidth;
216 var collapsed = crumbs.firstChild.offsetWidth;
lushnikov 2016/12/08 21:20:43 var collapsed = collapsedElem.offsetWidth;
phulce 2016/12/09 00:46:30 Done.
217
212 var normalSizes = []; 218 var normalSizes = [];
213 for (var i = 0; i < crumbs.childNodes.length; ++i) { 219 for (var i = 1; i < crumbs.childNodes.length; ++i) {
214 var crumb = crumbs.childNodes[i]; 220 var crumb = crumbs.childNodes[i];
215 normalSizes[i] = crumb.offsetWidth; 221 normalSizes[i - 1] = crumb.offsetWidth;
216 } 222 }
217 223
224 crumbs.removeChild(collapsedElem);
225
218 // Layout 2: Measure collapsed crumb sizes 226 // Layout 2: Measure collapsed crumb sizes
219 var compactSizes = []; 227 var compactSizes = [];
220 for (var i = 0; i < crumbs.childNodes.length; ++i) { 228 for (var i = 0; i < crumbs.childNodes.length; ++i) {
221 var crumb = crumbs.childNodes[i]; 229 var crumb = crumbs.childNodes[i];
222 crumb.classList.add('compact'); 230 crumb.classList.add('compact');
223 } 231 }
224 for (var i = 0; i < crumbs.childNodes.length; ++i) { 232 for (var i = 0; i < crumbs.childNodes.length; ++i) {
225 var crumb = crumbs.childNodes[i]; 233 var crumb = crumbs.childNodes[i];
226 compactSizes[i] = crumb.offsetWidth; 234 compactSizes[i] = crumb.offsetWidth;
227 } 235 }
228 236
229 // Layout 3: Measure collapsed crumb size
230 crumbs.firstChild.classList.add('collapsed');
231 var collapsedSize = crumbs.firstChild.offsetWidth;
232
233 // Clean up. 237 // Clean up.
234 for (var i = 0; i < crumbs.childNodes.length; ++i) { 238 for (var i = 0; i < crumbs.childNodes.length; ++i) {
235 var crumb = crumbs.childNodes[i]; 239 var crumb = crumbs.childNodes[i];
236 crumb.classList.remove('compact', 'collapsed'); 240 crumb.classList.remove('compact', 'collapsed');
237 } 241 }
238 242
243 return {normal: normalSizes, compact: compactSizes, collapsed: collapsed, av ailable: available};
244 }
245
246 /**
247 * @param {!Element=} focusedCrumb
248 */
249 updateSizes(focusedCrumb) {
250 if (!this.isShowing())
251 return;
252
253 var crumbs = this.crumbsElement;
254 if (!crumbs.firstChild)
255 return;
256
257 var selections = this._resetCrumbStylesAndFindSelections(focusedCrumb);
258 var sizes = this._measureElementSizes();
259 var selectedIndex = selections.selectedIndex;
260 var focusedIndex = selections.focusedIndex;
261 var selectedCrumb = selections.selectedCrumb;
262
239 function crumbsAreSmallerThanContainer() { 263 function crumbsAreSmallerThanContainer() {
240 var totalSize = 0; 264 var totalSize = 0;
241 for (var i = 0; i < crumbs.childNodes.length; ++i) { 265 for (var i = 0; i < crumbs.childNodes.length; ++i) {
242 var crumb = crumbs.childNodes[i]; 266 var crumb = crumbs.childNodes[i];
243 if (crumb.classList.contains('hidden')) 267 if (crumb.classList.contains('hidden'))
244 continue; 268 continue;
245 if (crumb.classList.contains('collapsed')) { 269 if (crumb.classList.contains('collapsed')) {
246 totalSize += collapsedSize; 270 totalSize += sizes.collapsed;
247 continue; 271 continue;
248 } 272 }
249 totalSize += crumb.classList.contains('compact') ? compactSizes[i] : nor malSizes[i]; 273 totalSize += crumb.classList.contains('compact') ? sizes.compact[i] : si zes.normal[i];
250 } 274 }
251 const rightPadding = 10; 275 const rightPadding = 10;
252 return totalSize + rightPadding < contentElementWidth; 276 return totalSize + rightPadding < sizes.available;
253 } 277 }
254 278
255 if (crumbsAreSmallerThanContainer()) 279 if (crumbsAreSmallerThanContainer())
256 return; // No need to compact the crumbs, they all fit at full size. 280 return; // No need to compact the crumbs, they all fit at full size.
257 281
258 var BothSides = 0; 282 var BothSides = 0;
259 var AncestorSide = -1; 283 var AncestorSide = -1;
260 var ChildSide = 1; 284 var ChildSide = 1;
261 285
262 /** 286 /**
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 435
412 // Collapse the selected crumb as a last resort. Pass true to prevent coales cing. 436 // Collapse the selected crumb as a last resort. Pass true to prevent coales cing.
413 collapse(selectedCrumb, true); 437 collapse(selectedCrumb, true);
414 } 438 }
415 }; 439 };
416 440
417 /** @enum {symbol} */ 441 /** @enum {symbol} */
418 Elements.ElementsBreadcrumbs.Events = { 442 Elements.ElementsBreadcrumbs.Events = {
419 NodeSelected: Symbol('NodeSelected') 443 NodeSelected: Symbol('NodeSelected')
420 }; 444 };
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