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

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/changes/ChangesView.js

Issue 2772643002: DevTools: Changes View (Closed)
Patch Set: Add a test Created 3 years, 9 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
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 Changes.ChangesView = class extends UI.VBox {
6 constructor() {
7 super(true);
8 this.registerRequiredCSS('changes/changesView.css');
9 var splitWidget = new UI.SplitWidget(true, false);
10 var mainWidget = new UI.Widget();
11 splitWidget.setMainWidget(mainWidget);
12 splitWidget.show(this.contentElement);
13 var diffArea = mainWidget.element.createChild('div', 'diff-area');
14
15 this._emptyWidget = new UI.EmptyWidget(Common.UIString('No changes'));
16 this._emptyWidget.show(diffArea);
17
18 this._workspaceDiff = WorkspaceDiff.workspaceDiff();
19 var fileList = new Changes.FileList(this._workspaceDiff);
20 fileList.on(Changes.FileList.SelectionChanged, this._fileListSelectionChange d, this);
21 splitWidget.setSidebarWidget(fileList);
22
23 /** @type {?Workspace.UISourceCode} */
24 this._uiSourceCode = null;
25
26 /** @type {!Array<!Changes.ChangesView.Row>} */
27 this._rows = [];
28
29 this._maxLineDigits = 1;
30
31 this._editor =
32 new TextEditor.CodeMirrorTextEditor({lineNumbers: true, lineWrapping: fa lse, maxHighlightLength: Infinity});
33 this._editor.setReadOnly(true);
34 this._editor.show(diffArea);
35 this._editor.hideWidget();
36 this._editor.setLineNumberFormatter(() => '');
37
38 this._editor.element.addEventListener('click', this._click.bind(this), false );
39
40 this._toolbar = new UI.Toolbar('changes-toolbar', mainWidget.element);
41 var revertButton = new UI.ToolbarButton(Common.UIString('Revert all changes' ), 'largeicon-undo');
42 revertButton.addEventListener(UI.ToolbarButton.Events.Click, this._revert.bi nd(this));
43 this._toolbar.appendToolbarItem(revertButton);
44 this._diffStats = new UI.ToolbarText('');
45 this._toolbar.appendToolbarItem(this._diffStats);
46 this._toolbar.setEnabled(false);
47 }
48
49 /**
50 * @param {!Changes.FileList.SelectionChanged} event
51 */
52 _fileListSelectionChanged(event) {
53 this._revealUISourceCode(event.uiSourceCode);
54 }
55
56 _revert() {
57 var uiSourceCode = this._uiSourceCode;
58 if (!uiSourceCode)
59 return;
60 uiSourceCode.requestOriginalContent().then(original => uiSourceCode.addRevis ion(original || ''));
61 }
62
63 _click(event) {
64 var selection = this._editor.selection();
65 if (!selection.isEmpty())
66 return;
67 var row = this._rows[selection.startLine];
68 if (!row)
69 return;
70 Common.Revealer.reveal(this._uiSourceCode.uiLocation(row.current - 1, select ion.startColumn), false);
71 event.consume(true);
72 }
73
74 /**
75 * @param {?Workspace.UISourceCode} uiSourceCode
76 */
77 _revealUISourceCode(uiSourceCode) {
78 if (this._uiSourceCode === uiSourceCode)
79 return;
80
81 if (this._uiSourceCode)
82 this._workspaceDiff.unsubscribeFromDiffChange(this._uiSourceCode, this._re freshDiff, this);
83 if (uiSourceCode && this.isShowing())
84 this._workspaceDiff.subscribeToDiffChange(uiSourceCode, this._refreshDiff, this);
85
86 this._uiSourceCode = uiSourceCode;
87 if (!uiSourceCode || this.isShowing())
88 this._refreshDiff();
89 }
90
91 /**
92 * @override
93 */
94 wasShown() {
95 if (!this._uiSourceCode)
96 return;
97 this._workspaceDiff.subscribeToDiffChange(this._uiSourceCode, this._refreshD iff, this);
98 this._refreshDiff();
99 }
100
101 /**
102 * @override
103 */
104 willHide() {
105 if (this._uiSourceCode)
106 this._workspaceDiff.unsubscribeFromDiffChange(this._uiSourceCode, this._re freshDiff, this);
107 }
108
109 _refreshDiff() {
110 if (!this._uiSourceCode) {
111 this._renderRows(null);
112 return;
113 }
114 var uiSourceCode = this._uiSourceCode;
115 this._workspaceDiff.requestDiff(uiSourceCode).then(diff => {
116 if (this._uiSourceCode !== uiSourceCode)
117 return;
118 this._renderRows(diff);
119 });
120 }
121
122 /**
123 * @param {?Diff.Diff.DiffArray} diff
124 */
125 _renderRows(diff) {
126 this._rows = [];
127
128 if (!diff || (diff.length === 1 && diff[0][0] === Diff.Diff.Operation.Equal) ) {
129 this._diffStats.setText('');
130 this._toolbar.setEnabled(false);
131 this._editor.hideWidget();
132 this._emptyWidget.showWidget();
133 return;
134 }
135
136 var insertions = 0;
137 var deletions = 0;
138 var currentLineNumber = 0;
139 var baselineLineNumber = 0;
140 var paddingLines = 3;
141 var originalLines = [];
142 var currentLines = [];
143
144 for (var i = 0; i < diff.length; ++i) {
145 var token = diff[i];
146 switch (token[0]) {
147 case Diff.Diff.Operation.Equal:
148 this._rows.pushAll(createEqualRows(token[1], i === 0, i === diff.lengt h - 1));
149 originalLines.pushAll(token[1]);
150 currentLines.pushAll(token[1]);
151 break;
152 case Diff.Diff.Operation.Insert:
153 for (var line of token[1])
154 this._rows.push(createRow(line, 'addition'));
155 currentLines.pushAll(token[1]);
156 break;
157 case Diff.Diff.Operation.Delete:
158 originalLines.pushAll(token[1]);
159 if (diff[i + 1] && diff[i + 1][0] === Diff.Diff.Operation.Insert) {
160 i++;
161 this._rows.pushAll(createModifyRows(token[1].join('\n'), diff[i][1]. join('\n')));
162 currentLines.pushAll(diff[i][1]);
163 } else {
164 for (var line of token[1])
165 this._rows.push(createRow(line, 'deletion'));
166 }
167 break;
168 }
169 }
170
171 this._maxLineDigits = Math.max(Math.ceil(Math.log10(Math.max(currentLineNumb er, baselineLineNumber))), 1);
172
173 this._editor.operation(() => {
174 this._editor.setHighlightMode({
175 name: 'devtools-diff',
176 rows: this._rows,
177 mimeType:
178 Bindings.NetworkProject.uiSourceCodeMimeType(/** @type {!Workspace.U ISourceCode} */ (this._uiSourceCode)),
179 baselineLines: originalLines,
180 currentLines: currentLines
181 });
182 this._editor.setText(this._rows.map(row => row.content.map(t => t.text).jo in('')).join('\n'));
183 this._editor.setLineNumberFormatter(this._lineFormatter.bind(this));
184 });
185
186 this._diffStats.setText(Common.UIString(
187 '%d insertion%s (+), %d deletion%s (-)', insertions, insertions > 1 ? 's ' : '', deletions,
188 deletions > 1 ? 's' : ''));
189 this._toolbar.setEnabled(true);
190 this._emptyWidget.hideWidget();
191 this._editor.showWidget();
192
193 /**
194 * @param {!Array<string>} lines
195 * @param {boolean} atStart
196 * @param {boolean} atEnd
197 * @return {!Array<!Changes.ChangesView.Row>}}
198 */
199 function createEqualRows(lines, atStart, atEnd) {
200 var equalRows = [];
201 if (!atStart) {
202 for (var i = 0; i < paddingLines && i < lines.length; i++)
203 equalRows.push(createRow(lines[i], 'equal'));
204 if (lines.length > paddingLines * 2 + 1 && !atEnd) {
205 equalRows.push(createRow(
206 Common.UIString('( \u2026 Skipping ') + (lines.length - paddingLin es * 2) +
207 Common.UIString(' matching lines \u2026 )'),
208 'spacer'));
209 }
210 }
211 if (!atEnd) {
212 var start = Math.max(lines.length - paddingLines - 1, atStart ? 0 : padd ingLines);
213 var skip = lines.length - paddingLines - 1;
214 if (!atStart)
215 skip -= paddingLines;
216 if (skip > 0) {
217 baselineLineNumber += skip;
218 currentLineNumber += skip;
219 }
220
221 for (var i = start; i < lines.length; i++)
222 equalRows.push(createRow(lines[i], 'equal'));
223 }
224 return equalRows;
225 }
226
227 /**
228 * @param {string} before
229 * @param {string} after
230 * @return {!Array<!Changes.ChangesView.Row>}}
231 */
232 function createModifyRows(before, after) {
233 var internalDiff = Diff.Diff.charDiff(before, after, true);
234 var deletionRows = [createRow('', 'deletion')];
235 var insertionRows = [createRow('', 'addition')];
236
237 for (var token of internalDiff) {
238 var text = token[1];
239 var type = token[0];
240 var className = type === Diff.Diff.Operation.Equal ? '' : 'double';
241 var first = true;
242 for (var line of text.split('\n')) {
243 if (first) {
244 first = false;
245 } else {
246 if (type !== Diff.Diff.Operation.Insert)
247 deletionRows.push(createRow('', 'deletion'));
248 if (type !== Diff.Diff.Operation.Delete)
249 insertionRows.push(createRow('', 'addition'));
250 }
251 if (line) {
252 if (type !== Diff.Diff.Operation.Insert)
253 deletionRows[deletionRows.length - 1].content.push({text: line, cl assName: className});
254
255 if (type !== Diff.Diff.Operation.Delete)
256 insertionRows[insertionRows.length - 1].content.push({text: line, className: className});
257 }
258 }
259 }
260 return deletionRows.concat(insertionRows);
261 }
262
263 /**
264 * @param {string} text
265 * @param {string} className
266 * @return {!Changes.ChangesView.Row}
267 */
268 function createRow(text, className) {
269 if (className === 'addition') {
270 currentLineNumber++;
271 insertions++;
272 }
273 if (className === 'deletion') {
274 baselineLineNumber++;
275 deletions++;
276 }
277 if (className === 'equal') {
278 baselineLineNumber++;
279 currentLineNumber++;
280 }
281 return {
282 base: baselineLineNumber,
283 current: currentLineNumber,
284 content: text ? [{text: text, className: 'double'}] : [],
285 className: className,
286 loc: currentLineNumber
287 };
288 }
289 }
290
291 /**
292 * @param {number} lineNumber
293 * @return {string}
294 */
295 _lineFormatter(lineNumber) {
296 var row = this._rows[lineNumber - 1];
297 if (!row)
298 return spacesPadding(this._maxLineDigits * 2 + 1);
299 var showBaseNumber = row.className === 'deletion';
300 var showCurrentNumber = row.className === 'addition';
301 if (row.className === 'equal') {
302 showBaseNumber = true;
303 showCurrentNumber = true;
304 }
305 var base = showBaseNumber ? numberToStringWithSpacesPadding(row.base, this._ maxLineDigits) :
306 spacesPadding(this._maxLineDigits);
307 var current = showCurrentNumber ? numberToStringWithSpacesPadding(row.curren t, this._maxLineDigits) :
308 spacesPadding(this._maxLineDigits);
309 return base + spacesPadding(1) + current;
310 }
311
312 /**
313 * @param {number} baselineLineNumber
314 * @param {number} currentLineNumber
315 * @param {string} text
316 * @param {string=} className
317 * @return {!Element}
318 */
319 _createRow(baselineLineNumber, currentLineNumber, text, className) {
320 var element = createElementWithClass('div', className);
321 element.createChild('span', 'number').textContent = baselineLineNumber ?
322 numberToStringWithSpacesPadding(baselineLineNumber, this._maxLineDigits) :
323 spacesPadding(this._maxLineDigits);
324 element.createChild('span', 'number').textContent = currentLineNumber ?
325 numberToStringWithSpacesPadding(currentLineNumber, this._maxLineDigits) :
326 spacesPadding(this._maxLineDigits);
327 element.createChild('span', 'double').textContent = text;
328 return element;
329 }
330 };
331
332 /** @typedef {!{base: number, current: number, content: !Array<!{text: string, c lassName: string}>, className: string, loc: number}} */
333 Changes.ChangesView.Row;
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698