| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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'; |
| OLD | NEW |