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

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/css_tracker/CSSTrackerView.js

Issue 2698623008: DevTools: extract a list view out of CSSTrackerView (Closed)
Patch Set: review comments + rebase Created 3 years, 10 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
OLDNEW
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2016 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 CSSTracker.CSSTrackerView = class extends UI.VBox { 5 CSSTracker.CSSTrackerView = class extends UI.VBox {
6 constructor() { 6 constructor() {
7 super(true); 7 super(true);
8 8
9 this.registerRequiredCSS('css_tracker/cssTrackerView.css'); 9 this.registerRequiredCSS('css_tracker/cssTrackerView.css');
10 10
11 var toolbarContainer = this.contentElement.createChild('div', 'css-tracker-t oolbar-container'); 11 var toolbarContainer = this.contentElement.createChild('div', 'css-tracker-t oolbar-container');
12 var topToolbar = new UI.Toolbar('css-tracker-toolbar', toolbarContainer); 12 var topToolbar = new UI.Toolbar('css-tracker-toolbar', toolbarContainer);
13 13
14 this._recordButton = 14 this._recordButton =
15 new UI.ToolbarToggle(Common.UIString('Start recording'), 'largeicon-resu me', 'largeicon-pause'); 15 new UI.ToolbarToggle(Common.UIString('Start recording'), 'largeicon-resu me', 'largeicon-pause');
16 this._recordButton.addEventListener(UI.ToolbarButton.Events.Click, () => thi s._toggleRecording(!this._isRecording)); 16 this._recordButton.addEventListener(UI.ToolbarButton.Events.Click, () => thi s._toggleRecording(!this._isRecording));
17 topToolbar.appendToolbarItem(this._recordButton); 17 topToolbar.appendToolbarItem(this._recordButton);
18 18
19 var clearButton = new UI.ToolbarButton(Common.UIString('Clear all'), 'largei con-clear'); 19 var clearButton = new UI.ToolbarButton(Common.UIString('Clear all'), 'largei con-clear');
20 clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._reset.bind (this)); 20 clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._reset.bind (this));
21 topToolbar.appendToolbarItem(clearButton); 21 topToolbar.appendToolbarItem(clearButton);
22 22
23 this._cssResultsElement = this.contentElement.createChild('div', 'css-result s'); 23 this._cssResultsElement = this.contentElement.createChild('div', 'css-result s');
24 this._progressElement = this._cssResultsElement.createChild('div', 'progress -view'); 24 this._progressElement = this._cssResultsElement.createChild('div', 'progress -view');
25 this._treeOutline = new UI.TreeOutlineInShadow(); 25 this._listView = new CSSTracker.CSSTrackerListView();
26 this._treeOutline.registerRequiredCSS('css_tracker/unusedRulesTree.css');
27 26
28 this._statusToolbarElement = this.contentElement.createChild('div', 'css-too lbar-summary'); 27 this._statusToolbarElement = this.contentElement.createChild('div', 'css-too lbar-summary');
29 this._statusMessageElement = this._statusToolbarElement.createChild('div', ' css-message'); 28 this._statusMessageElement = this._statusToolbarElement.createChild('div', ' css-message');
30 29
31 this._isRecording = false; 30 this._isRecording = false;
32 } 31 }
33 32
34 _reset() { 33 _reset() {
35 Workspace.workspace.uiSourceCodes().forEach( 34 Workspace.workspace.uiSourceCodes().forEach(
36 uiSourceCode => uiSourceCode.removeDecorationsForType(CSSTracker.CSSTrac kerView.LineDecorator.type)); 35 uiSourceCode => uiSourceCode.removeDecorationsForType(CSSTracker.CSSTrac kerView.LineDecorator.type));
37 36
37 this._listView.detach();
38 this._cssResultsElement.removeChildren(); 38 this._cssResultsElement.removeChildren();
39 this._progressElement.textContent = ''; 39 this._progressElement.textContent = '';
40 this._cssResultsElement.appendChild(this._progressElement); 40 this._cssResultsElement.appendChild(this._progressElement);
41 41
42 this._treeOutline.removeChildren();
43 this._statusMessageElement.textContent = ''; 42 this._statusMessageElement.textContent = '';
44 } 43 }
45 44
46 /** 45 /**
47 * @param {boolean} enable 46 * @param {boolean} enable
48 */ 47 */
49 _toggleRecording(enable) { 48 _toggleRecording(enable) {
50 if (enable === this._isRecording) 49 if (enable === this._isRecording)
51 return; 50 return;
52 51
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 entry => this._populateSourceInfo(/** @type {!CSSTracker.StyleSheetUsa ge} */ (entry)))); 108 entry => this._populateSourceInfo(/** @type {!CSSTracker.StyleSheetUsa ge} */ (entry))));
110 } 109 }
111 110
112 /** 111 /**
113 * @param {!Array<!CSSTracker.StyleSheetUsage>} styleSheetUsages 112 * @param {!Array<!CSSTracker.StyleSheetUsage>} styleSheetUsages
114 * @this {!CSSTracker.CSSTrackerView} 113 * @this {!CSSTracker.CSSTrackerView}
115 */ 114 */
116 function updateViews(styleSheetUsages) { 115 function updateViews(styleSheetUsages) {
117 this._updateStats(styleSheetUsages); 116 this._updateStats(styleSheetUsages);
118 this._updateGutter(styleSheetUsages); 117 this._updateGutter(styleSheetUsages);
119 this._updateTree(styleSheetUsages); 118 this._cssResultsElement.removeChildren();
119 this._listView.update(styleSheetUsages);
120 this._listView.show(this._cssResultsElement);
120 } 121 }
121 } 122 }
122 123
123 /** 124 /**
124 * @param {!CSSTracker.StyleSheetUsage} styleSheetUsage 125 * @param {!CSSTracker.StyleSheetUsage} styleSheetUsage
125 * @return {!Promise<!CSSTracker.StyleSheetUsage>} 126 * @return {!Promise<!CSSTracker.StyleSheetUsage>}
126 */ 127 */
127 _populateSourceInfo(styleSheetUsage) { 128 _populateSourceInfo(styleSheetUsage) {
128 if (!styleSheetUsage.styleSheetHeader) 129 if (!styleSheetUsage.styleSheetHeader)
129 return Promise.resolve(styleSheetUsage); 130 return Promise.resolve(styleSheetUsage);
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 if (!uiSourceCode) 185 if (!uiSourceCode)
185 continue; 186 continue;
186 for (var rule of styleSheet.rules) { 187 for (var rule of styleSheet.rules) {
187 var gutterRange = Common.TextRange.fromObject(rule.range); 188 var gutterRange = Common.TextRange.fromObject(rule.range);
188 if (gutterRange.startColumn) 189 if (gutterRange.startColumn)
189 gutterRange.startColumn--; 190 gutterRange.startColumn--;
190 uiSourceCode.addDecoration(gutterRange, CSSTracker.CSSTrackerView.LineDe corator.type, rule.wasUsed); 191 uiSourceCode.addDecoration(gutterRange, CSSTracker.CSSTrackerView.LineDe corator.type, rule.wasUsed);
191 } 192 }
192 } 193 }
193 } 194 }
194
195 /**
196 * @param {!Array<!CSSTracker.StyleSheetUsage>} styleSheetUsages
197 */
198 _updateTree(styleSheetUsages) {
199 this._cssResultsElement.removeChildren();
200 this._cssResultsElement.appendChild(this._treeOutline.element);
201
202 for (var sheet of styleSheetUsages) {
203 var unusedRuleCount = sheet.rules.reduce((count, rule) => rule.wasUsed ? c ount : count + 1, 0);
204 if (sheet.styleSheetHeader) {
205 var url = sheet.styleSheetHeader.sourceURL;
206 if (!url)
207 continue;
208
209 var styleSheetTreeElement = new CSSTracker.CSSTrackerView.StyleSheetTree Element(url, sheet.rules);
210 this._treeOutline.appendChild(styleSheetTreeElement);
211 continue;
212 }
213 if (!unusedRuleCount)
214 continue;
215 var removedStyleSheetStats = unusedRuleCount === 1 ?
216 Common.UIString('1 unused rule in a removed style sheet.') :
217 Common.UIString('%d unused rules in removed style sheets.', unusedRule Count);
218
219 var treeElement = new UI.TreeElement(Common.UIString('Unknown style sheets '), true);
220 treeElement.toggleOnClick = true;
221 treeElement.selectable = false;
222
223 var stats = new UI.TreeElement(removedStyleSheetStats, false);
224 stats.selectable = false;
225 treeElement.appendChild(stats);
226 this._treeOutline.appendChild(treeElement);
227 }
228 }
229 }; 195 };
230 196
231 /** @typedef {{range: !Protocol.CSS.SourceRange, 197 /** @typedef {{range: !Protocol.CSS.SourceRange,
232 * selector: (string|undefined), 198 * selector: (string|undefined),
233 * wasUsed: boolean}} 199 * wasUsed: boolean}}
234 */ 200 */
235 CSSTracker.RuleUsage; 201 CSSTracker.RuleUsage;
236 202
237 /** @typedef {{styleSheetHeader: ?SDK.CSSStyleSheetHeader, rules: !Array<!CSSTra cker.RuleUsage>}} */ 203 /** @typedef {{styleSheetHeader: ?SDK.CSSStyleSheetHeader, rules: !Array<!CSSTra cker.RuleUsage>}} */
238 CSSTracker.StyleSheetUsage; 204 CSSTracker.StyleSheetUsage;
239 205
240 CSSTracker.CSSTrackerView._rulesShownAtOnce = 20;
241
242 CSSTracker.CSSTrackerView.StyleSheetTreeElement = class extends UI.TreeElement {
243 /**
244 * @param {string} url
245 * @param {!Array<!CSSTracker.RuleUsage>} ruleList
246 */
247 constructor(url, ruleList) {
248 super('', true);
249
250 this._uiSourceCode = Workspace.workspace.uiSourceCodeForURL(url);
251
252 /** @type {!Array<!CSSTracker.RuleUsage>} */
253 this._unusedRules = ruleList.filter(rule => !rule.wasUsed);
254
255 var lastLineNumber = 0;
256 for (var i = this._unusedRules.length - 1; i >= 0; --i) {
257 if (this._unusedRules[i].range) {
258 lastLineNumber = this._unusedRules[i].range.startLine;
259 break;
260 }
261 }
262 this._numberOfSpaces = lastLineNumber.toString().length + 1;
263
264 this._percentUnused = Math.round(100 * this._unusedRules.length / ruleList.l ength);
265
266 this.toggleOnClick = true;
267 this.selectable = false;
268
269 /** @type {?UI.TreeElement} */
270 this._showAllRulesTreeElement = null;
271
272 var title = createElementWithClass('div', 'rule-result');
273 var titleText;
274 if (this._uiSourceCode)
275 titleText = this._uiSourceCode.fullDisplayName();
276 else
277 titleText = Common.UIString('Style Sheet was removed');
278 title.createChild('span', 'rule-result-file-name').textContent = titleText;
279
280 var rulesCountSpan = title.createChild('span', 'rule-result-matches-count');
281
282 if (this._unusedRules.length === 1) {
283 rulesCountSpan.textContent =
284 Common.UIString('(%d unused rule : %d%%)', this._unusedRules.length, t his._percentUnused);
285 } else {
286 rulesCountSpan.textContent =
287 Common.UIString('(%d unused rules : %d%%)', this._unusedRules.length, this._percentUnused);
288 }
289 this.title = title;
290 }
291
292 /**
293 * @override
294 */
295 onpopulate() {
296 var toIndex = Math.min(this._unusedRules.length, CSSTracker.CSSTrackerView._ rulesShownAtOnce);
297 this._appendRules(0, toIndex);
298 if (toIndex < this._unusedRules.length)
299 this._appendShowAllRulesButton(toIndex);
300 }
301
302 /**
303 * @param {number} fromIndex
304 * @param {number} toIndex
305 */
306 _appendRules(fromIndex, toIndex) {
307 for (var i = fromIndex; i < toIndex; ++i) {
308 if (!this._uiSourceCode) {
309 var rule = this._unusedRules[i];
310 var contentSpan = createElementWithClass('span', 'rule-match-content');
311 contentSpan.textContent = rule.selector;
312 ruleElement.listItemElement.appendChild(contentSpan);
313 continue;
314 }
315
316 var rule = this._unusedRules[i];
317 var lineNumber = rule.range.startLine;
318 var columnNumber = rule.range.startColumn;
319
320 var anchor = Components.Linkifier.linkifyRevealable(this._uiSourceCode.uiL ocation(lineNumber, columnNumber), '');
321
322 var lineNumberSpan = createElement('span');
323 lineNumberSpan.classList.add('rule-match-line-number');
324 lineNumberSpan.textContent = numberToStringWithSpacesPadding(lineNumber + 1, this._numberOfSpaces);
325 anchor.appendChild(lineNumberSpan);
326
327 var contentSpan = anchor.createChild('span', 'rule-match-content');
328 contentSpan.textContent = rule.selector;
329
330 var ruleElement = new UI.TreeElement();
331 ruleElement.selectable = true;
332 this.appendChild(ruleElement);
333 ruleElement.listItemElement.className = 'rule-match source-code';
334 ruleElement.listItemElement.appendChild(anchor);
335 }
336 }
337
338 /**
339 * @param {number} startMatchIndex
340 */
341 _appendShowAllRulesButton(startMatchIndex) {
342 var rulesLeftCount = this._unusedRules.length - startMatchIndex;
343 var button = UI.createTextButton('', this._showMoreRulesElementSelected.bind (this, startMatchIndex));
344 button.textContent = Common.UIString('Show all rules (%d more).', rulesLeftC ount);
345 this._showAllRulesTreeElement = new UI.TreeElement(button);
346 this._showAllRulesTreeElement.selectable = false;
347 this.appendChild(this._showAllRulesTreeElement);
348 }
349
350 /**
351 * @param {number} startMatchIndex
352 */
353 _showMoreRulesElementSelected(startMatchIndex) {
354 if (!this._showAllRulesTreeElement)
355 return;
356 this.removeChild(this._showAllRulesTreeElement);
357 this._appendRules(startMatchIndex, this._unusedRules.length);
358 }
359 };
360
361 /** 206 /**
362 * @implements {SourceFrame.UISourceCodeFrame.LineDecorator} 207 * @implements {SourceFrame.UISourceCodeFrame.LineDecorator}
363 */ 208 */
364 CSSTracker.CSSTrackerView.LineDecorator = class { 209 CSSTracker.CSSTrackerView.LineDecorator = class {
365 /** 210 /**
366 * @override 211 * @override
367 * @param {!Workspace.UISourceCode} uiSourceCode 212 * @param {!Workspace.UISourceCode} uiSourceCode
368 * @param {!TextEditor.CodeMirrorTextEditor} textEditor 213 * @param {!TextEditor.CodeMirrorTextEditor} textEditor
369 */ 214 */
370 decorate(uiSourceCode, textEditor) { 215 decorate(uiSourceCode, textEditor) {
(...skipping 14 matching lines...) Expand all
385 else 230 else
386 element.className = 'text-editor-css-rule-unused-marker'; 231 element.className = 'text-editor-css-rule-unused-marker';
387 232
388 textEditor.setGutterDecoration(line, gutterType, element); 233 textEditor.setGutterDecoration(line, gutterType, element);
389 } 234 }
390 } 235 }
391 } 236 }
392 }; 237 };
393 238
394 CSSTracker.CSSTrackerView.LineDecorator.type = 'coverage'; 239 CSSTracker.CSSTrackerView.LineDecorator.type = 'coverage';
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698