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

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/coverage/CoverageView.js

Issue 2865573003: DevTools: support live coverage (Closed)
Patch Set: minor polish on corner cases Created 3 years, 7 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 Coverage.CoverageView = class extends UI.VBox { 5 Coverage.CoverageView = class extends UI.VBox {
6 constructor() { 6 constructor() {
7 super(true); 7 super(true);
8 8
9 /** @type {?Coverage.CoverageModel} */ 9 /** @type {?Coverage.CoverageModel} */
10 this._model = null; 10 this._model = null;
11 /** @type {number|undefined} */
12 this._pollTimer;
13 /** @type {?Coverage.CoverageDecorationManager} */
14 this._decorationManager = null;
15
11 this.registerRequiredCSS('coverage/coverageView.css'); 16 this.registerRequiredCSS('coverage/coverageView.css');
12 17
13 var toolbarContainer = this.contentElement.createChild('div', 'coverage-tool bar-container'); 18 var toolbarContainer = this.contentElement.createChild('div', 'coverage-tool bar-container');
14 var topToolbar = new UI.Toolbar('coverage-toolbar', toolbarContainer); 19 var topToolbar = new UI.Toolbar('coverage-toolbar', toolbarContainer);
15 20
16 this._toggleRecordAction = 21 this._toggleRecordAction =
17 /** @type {!UI.Action }*/ (UI.actionRegistry.action('coverage.toggle-rec ording')); 22 /** @type {!UI.Action }*/ (UI.actionRegistry.action('coverage.toggle-rec ording'));
18 this._toggleRecordButton = UI.Toolbar.createActionButton(this._toggleRecordA ction); 23 this._toggleRecordButton = UI.Toolbar.createActionButton(this._toggleRecordA ction);
19 topToolbar.appendToolbarItem(this._toggleRecordButton); 24 topToolbar.appendToolbarItem(this._toggleRecordButton);
20 25
21 var startWithReloadAction = 26 var startWithReloadAction =
22 /** @type {!UI.Action }*/ (UI.actionRegistry.action('coverage.start-with -reload')); 27 /** @type {!UI.Action }*/ (UI.actionRegistry.action('coverage.start-with -reload'));
23 this._startWithReloadButton = UI.Toolbar.createActionButton(startWithReloadA ction); 28 this._startWithReloadButton = UI.Toolbar.createActionButton(startWithReloadA ction);
24 topToolbar.appendToolbarItem(this._startWithReloadButton); 29 topToolbar.appendToolbarItem(this._startWithReloadButton);
25 30
26 this._clearButton = new UI.ToolbarButton(Common.UIString('Clear all'), 'larg eicon-clear'); 31 this._clearButton = new UI.ToolbarButton(Common.UIString('Clear all'), 'larg eicon-clear');
27 this._clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._rese t.bind(this)); 32 this._clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._rese t.bind(this));
28 topToolbar.appendToolbarItem(this._clearButton); 33 topToolbar.appendToolbarItem(this._clearButton);
29 34
30 this._coverageResultsElement = this.contentElement.createChild('div', 'cover age-results'); 35 this._coverageResultsElement = this.contentElement.createChild('div', 'cover age-results');
31 this._progressElement = this._coverageResultsElement.createChild('div', 'pro gress-view'); 36 this._progressElement = this._coverageResultsElement.createChild('div', 'pro gress-view');
32 this._listView = new Coverage.CoverageListView(); 37 this._listView = new Coverage.CoverageListView();
33 38
34 this._statusToolbarElement = this.contentElement.createChild('div', 'coverag e-toolbar-summary'); 39 this._statusToolbarElement = this.contentElement.createChild('div', 'coverag e-toolbar-summary');
35 this._statusMessageElement = this._statusToolbarElement.createChild('div', ' coverage-message'); 40 this._statusMessageElement = this._statusToolbarElement.createChild('div', ' coverage-message');
36 this._showHelpScreen(); 41 this._showHelpScreen();
37 } 42 }
38 43
39 _reset() { 44 _reset() {
40 Workspace.workspace.uiSourceCodes().forEach( 45 if (this._decorationManager) {
41 uiSourceCode => uiSourceCode.removeDecorationsForType(Coverage.CoverageV iew.LineDecorator.type)); 46 this._decorationManager.dispose();
42 47 this._decorationManager = null;
48 }
49 this._listView.reset();
43 this._listView.detach(); 50 this._listView.detach();
44 this._coverageResultsElement.removeChildren(); 51 this._coverageResultsElement.removeChildren();
45 this._showHelpScreen(); 52 this._showHelpScreen();
46 53
47 this._statusMessageElement.textContent = ''; 54 this._statusMessageElement.textContent = '';
48 } 55 }
49 56
50 _showHelpScreen() { 57 _showHelpScreen() {
51 this._coverageResultsElement.appendChild(this._progressElement); 58 this._coverageResultsElement.appendChild(this._progressElement);
52 this._progressElement.removeChildren(); 59 this._progressElement.removeChildren();
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 _startRecording() { 91 _startRecording() {
85 this._reset(); 92 this._reset();
86 var mainTarget = SDK.targetManager.mainTarget(); 93 var mainTarget = SDK.targetManager.mainTarget();
87 if (!mainTarget) 94 if (!mainTarget)
88 return; 95 return;
89 console.assert(!this._model, 'Attempting to start coverage twice'); 96 console.assert(!this._model, 'Attempting to start coverage twice');
90 var model = new Coverage.CoverageModel(mainTarget); 97 var model = new Coverage.CoverageModel(mainTarget);
91 if (!model.start()) 98 if (!model.start())
92 return; 99 return;
93 this._model = model; 100 this._model = model;
101 this._decorationManager = new Coverage.CoverageDecorationManager(model);
94 this._toggleRecordAction.setToggled(true); 102 this._toggleRecordAction.setToggled(true);
95 this._clearButton.setEnabled(false); 103 this._clearButton.setEnabled(false);
96 this._startWithReloadButton.setEnabled(false); 104 this._startWithReloadButton.setEnabled(false);
97 this._progressElement.textContent = Common.UIString('Recording...'); 105 this._coverageResultsElement.removeChildren();
106 this._listView.show(this._coverageResultsElement);
107 this._poll();
108 }
109
110 async _poll() {
111 delete this._pollTimer;
112 var updates = await this._model.poll();
113 this._updateViews(updates);
114 this._pollTimer = setTimeout(() => this._poll(), 700);
98 } 115 }
99 116
100 async _stopRecording() { 117 async _stopRecording() {
118 if (this._pollTimer) {
119 clearTimeout(this._pollTimer);
120 delete this._pollTimer;
121 }
122 var updatedEntries = await this._model.stop();
123 this._updateViews(updatedEntries);
124 this._model = null;
101 this._toggleRecordAction.setToggled(false); 125 this._toggleRecordAction.setToggled(false);
102 this._progressElement.textContent = Common.UIString('Fetching results...');
103
104 var coverageInfo = await this._model.stop();
105 this._model = null;
106 await this._updateViews(coverageInfo);
107 this._startWithReloadButton.setEnabled(true); 126 this._startWithReloadButton.setEnabled(true);
108 this._clearButton.setEnabled(true); 127 this._clearButton.setEnabled(true);
109 } 128 }
110 129
111 /** 130 /**
112 * @param {!Array<!Coverage.URLCoverageInfo>} coverageInfo 131 * @param {!Array<!Coverage.CoverageInfo>} updatedEntries
113 */ 132 */
114 async _updateViews(coverageInfo) { 133 async _updateViews(updatedEntries) {
115 this._updateStats(coverageInfo); 134 var urlEntries = this._model.entries();
116 this._coverageResultsElement.removeChildren(); 135 this._updateStats(urlEntries);
117 this._listView.update(coverageInfo); 136 this._listView.update(urlEntries);
118 this._listView.show(this._coverageResultsElement); 137 this._decorationManager.update(updatedEntries);
119 await Promise.all(coverageInfo.map(entry => Coverage.CoverageView._updateGut ter(entry)));
120 } 138 }
121 139
122 /** 140 /**
123 * @param {!Array<!Coverage.URLCoverageInfo>} coverageInfo 141 * @param {!Array<!Coverage.URLCoverageInfo>} coverageInfo
124 */ 142 */
125 _updateStats(coverageInfo) { 143 _updateStats(coverageInfo) {
126 var total = 0; 144 var total = 0;
127 var unused = 0; 145 var unused = 0;
128 for (var info of coverageInfo) { 146 for (var info of coverageInfo) {
129 total += info.size(); 147 total += info.size();
130 unused += info.unusedSize(); 148 unused += info.unusedSize();
131 } 149 }
132 150
133 var percentUnused = total ? Math.round(100 * unused / total) : 0; 151 var percentUnused = total ? Math.round(100 * unused / total) : 0;
134 this._statusMessageElement.textContent = Common.UIString( 152 this._statusMessageElement.textContent = Common.UIString(
135 '%s of %s bytes are not used. (%d%%)', Number.bytesToString(unused), Num ber.bytesToString(total), 153 '%s of %s bytes are not used. (%d%%)', Number.bytesToString(unused), Num ber.bytesToString(total),
136 percentUnused); 154 percentUnused);
137 } 155 }
138
139 /**
140 * @param {!Coverage.URLCoverageInfo} coverageInfo
141 */
142 static async _updateGutter(coverageInfo) {
143 var uiSourceCode = Workspace.workspace.uiSourceCodeForURL(coverageInfo.url() );
144 if (!uiSourceCode)
145 return;
146 // FIXME: gutter should be set in terms of offsets and therefore should not require contents.
147 var ranges = await coverageInfo.buildTextRanges();
148 for (var r of ranges)
149 uiSourceCode.addDecoration(r.range, Coverage.CoverageView.LineDecorator.ty pe, r.count);
150 }
151 }; 156 };
152 157
153 /** 158 /**
154 * @implements {SourceFrame.UISourceCodeFrame.LineDecorator}
155 */
156 Coverage.CoverageView.LineDecorator = class {
157 /**
158 * @override
159 * @param {!Workspace.UISourceCode} uiSourceCode
160 * @param {!TextEditor.CodeMirrorTextEditor} textEditor
161 */
162 decorate(uiSourceCode, textEditor) {
163 var gutterType = 'CodeMirror-gutter-coverage';
164
165 var decorations = uiSourceCode.decorationsForType(Coverage.CoverageView.Line Decorator.type);
166 textEditor.uninstallGutter(gutterType);
167 if (!decorations || !decorations.size)
168 return;
169
170 textEditor.installGutter(gutterType, false);
171 var lastLine = 0;
172 var lastData = undefined;
173 for (var decoration of decorations) {
174 var range = decoration.range();
175 var startLine = range.startLine;
176 if (lastLine && lastLine === startLine && lastData !== !!decoration.data() ) {
177 var element = createElementWithClass('div', 'text-editor-coverage-mixed- marker');
178 textEditor.setGutterDecoration(startLine, gutterType, element);
179 startLine++;
180 } else {
181 startLine = Math.max(startLine, lastLine);
182 }
183 lastLine = range.endLine;
184 lastData = !!decoration.data();
185 var className = lastData ? 'text-editor-coverage-used-marker' : 'text-edit or-coverage-unused-marker';
186 for (var line = startLine; line <= lastLine; ++line) {
187 var element = createElementWithClass('div', className);
188 textEditor.setGutterDecoration(line, gutterType, element);
189 }
190 }
191 }
192 };
193
194 Coverage.CoverageView.LineDecorator.type = 'coverage';
195
196 /**
197 * @implements {UI.ActionDelegate} 159 * @implements {UI.ActionDelegate}
198 */ 160 */
199 Coverage.CoverageView.ActionDelegate = class { 161 Coverage.CoverageView.ActionDelegate = class {
200 /** 162 /**
201 * @override 163 * @override
202 * @param {!UI.Context} context 164 * @param {!UI.Context} context
203 * @param {string} actionId 165 * @param {string} actionId
204 * @return {boolean} 166 * @return {boolean}
205 */ 167 */
206 handleAction(context, actionId) { 168 handleAction(context, actionId) {
(...skipping 15 matching lines...) Expand all
222 coverageView._toggleRecording(); 184 coverageView._toggleRecording();
223 break; 185 break;
224 case 'coverage.start-with-reload': 186 case 'coverage.start-with-reload':
225 coverageView._startWithReload(); 187 coverageView._startWithReload();
226 break; 188 break;
227 default: 189 default:
228 console.assert(false, `Unknown action: ${actionId}`); 190 console.assert(false, `Unknown action: ${actionId}`);
229 } 191 }
230 } 192 }
231 }; 193 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698