diff --git a/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-builder-side-by-side.js b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-builder-side-by-side.js new file mode 100644 index 0000000000..537adc9b5e --- /dev/null +++ b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-builder-side-by-side.js @@ -0,0 +1,53 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the 'License'); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an 'AS IS' BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +(function(window, GrDiffBuilder) { + 'use strict'; + + function GrDiffBuilderSideBySide(diff, outputEl) { + GrDiffBuilder.call(this, diff, outputEl); + } + GrDiffBuilderSideBySide.prototype = Object.create(GrDiffBuilder.prototype); + GrDiffBuilderSideBySide.prototype.constructor = GrDiffBuilderSideBySide; + + GrDiffBuilderSideBySide.prototype._emitGroup = function(group, + opt_beforeSection) { + var sectionEl = this._createElement('tbody', 'section'); + var pairs = group.getSideBySidePairs(); + for (var i = 0; i < pairs.length; ++i) { + sectionEl.appendChild(this._createRow(pairs[i].left, pairs[i].right)); + } + this._outputEl.insertBefore(sectionEl, opt_beforeSection); + }, + + GrDiffBuilderSideBySide.prototype._createRow = function(leftLine, rightLine) { + var row = this._createElement('tr'); + this._createPair(row, leftLine, leftLine.beforeNumber); + this._createPair(row, rightLine, rightLine.afterNumber); + return row; + }; + + GrDiffBuilderSideBySide.prototype._createPair = function(row, line, + lineNumber) { + if (line.type === GrDiffLine.Type.BLANK) { + row.appendChild(this._createBlankSideEl()); + return row; + } + + row.appendChild(this._createLineEl(line, lineNumber, line.type)); + row.appendChild(this._createTextEl(line)); + return row; + }; + + window.GrDiffBuilderSideBySide = GrDiffBuilderSideBySide; +})(window, GrDiffBuilder); diff --git a/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-builder-unified.js b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-builder-unified.js new file mode 100644 index 0000000000..4f57d848db --- /dev/null +++ b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-builder-unified.js @@ -0,0 +1,44 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the 'License'); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an 'AS IS' BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +(function(window, GrDiffBuilder) { + 'use strict'; + + function GrDiffBuilderUnified(diff, outputEl) { + GrDiffBuilder.call(this, diff, outputEl); + } + GrDiffBuilderUnified.prototype = Object.create(GrDiffBuilder.prototype); + GrDiffBuilderUnified.prototype.constructor = GrDiffBuilderUnified; + + GrDiffBuilderUnified.prototype._emitGroup = function(group, + opt_beforeSection) { + var sectionEl = this._createElement('tbody', 'section'); + + for (var i = 0; i < group.lines.length; ++i) { + sectionEl.appendChild(this._createRow(group.lines[i])); + } + this._outputEl.insertBefore(sectionEl, opt_beforeSection); + }; + + GrDiffBuilderUnified.prototype._createRow = function(line) { + var row = this._createElement('tr', line.type); + row.appendChild(this._createLineEl(line, line.beforeNumber, + GrDiffLine.Type.REMOVE)); + row.appendChild(this._createLineEl(line, line.afterNumber, + GrDiffLine.Type.ADD)); + row.appendChild(this._createTextEl(line)); + return row; + }; + + window.GrDiffBuilderUnified = GrDiffBuilderUnified; +})(window, GrDiffBuilder); diff --git a/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-builder.js b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-builder.js new file mode 100644 index 0000000000..abd323e8b3 --- /dev/null +++ b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-builder.js @@ -0,0 +1,128 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the 'License'); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an 'AS IS' BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +(function(window, GrDiffGroup, GrDiffLine) { + 'use strict'; + + function GrDiffBuilder(diff, outputEl) { + this._outputEl = outputEl; + this._groups = []; + + this._processContent(diff.content, this._groups); + } + + GrDiffBuilder.GroupType = { + ADDED: 'b', + BOTH: 'ab', + REMOVED: 'a', + }; + + GrDiffBuilder.prototype.emitDiff = function() { + for (var i = 0; i < this._groups.length; i++) { + this._emitGroup(this._groups[i]); + } + }; + + GrDiffBuilder.prototype._emitGroup = function(group, opt_beforeSection) { + throw Error('Subclasses must implement emitGroup'); + }, + + GrDiffBuilder.prototype._processContent = function(content, groups) { + var leftLineNum = 0; + var rightLineNum = 0; + for (var i = 0; i < content.length; i++) { + var group = content[i]; + var lines = []; + + if (group[GrDiffBuilder.GroupType.BOTH] !== undefined) { + var rows = group[GrDiffBuilder.GroupType.BOTH]; + for (var j = 0; j < rows.length; j++) { + var line = new GrDiffLine(GrDiffLine.Type.BOTH); + line.text = rows[j]; + line.beforeNumber = ++leftLineNum; + line.afterNumber = ++rightLineNum; + lines.push(line); + } + groups.push(new GrDiffGroup(GrDiffGroup.Type.BOTH, lines)); + continue; + } + + if (group[GrDiffBuilder.GroupType.REMOVED] !== undefined) { + var rows = group[GrDiffBuilder.GroupType.REMOVED]; + for (var j = 0; j < rows.length; j++) { + var line = new GrDiffLine(GrDiffLine.Type.REMOVE); + line.text = rows[j]; + line.beforeNumber = ++leftLineNum; + lines.push(line); + } + } + if (group[GrDiffBuilder.GroupType.ADDED] !== undefined) { + var rows = group[GrDiffBuilder.GroupType.ADDED]; + for (var j = 0; j < rows.length; j++) { + var line = new GrDiffLine(GrDiffLine.Type.ADD); + line.text = rows[j]; + line.afterNumber = ++rightLineNum; + lines.push(line); + } + } + groups.push(new GrDiffGroup(GrDiffGroup.Type.DELTA, lines)); + } + }; + + GrDiffBuilder.prototype._createBlankSideEl = function() { + var td = this._createElement('td'); + td.setAttribute('colspan', '2'); + return td; + }; + + GrDiffBuilder.prototype._createLineEl = function(line, number, type) { + var td = this._createElement('td', 'lineNum'); + if (line.type === GrDiffLine.Type.BOTH || line.type == type) { + td.setAttribute('data-line-num', number); + } + return td; + }; + + GrDiffBuilder.prototype._createTextEl = function(line) { + var td = this._createElement('td', 'content'); + td.classList.add(line.type); + var text = line.text || '\n'; + var html = util.escapeHTML(text); + + // If the html is equivalent to the text then it didn't get highlighted + // or escaped. Use textContent which is faster than innerHTML. + if (html == text) { + td.textContent = text; + } else { + td.innerHTML = html; + } + return td; + }; + + GrDiffBuilder.prototype._createElement = function(tagName, className) { + var el = document.createElement(tagName); + // When Shady DOM is being used, these classes are added to account for + // Polymer's polyfill behavior. In order to guarantee sufficient + // specificity within the CSS rules, these are added to every element. + // Since the Polymer DOM utility functions (which would do this + // automatically) are not being used for performance reasons, this is + // done manually. + el.classList.add('style-scope', 'gr-new-diff'); + if (!!className) { + el.classList.add(className); + } + return el; + }; + + window.GrDiffBuilder = GrDiffBuilder; +})(window, GrDiffGroup, GrDiffLine); diff --git a/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-builder_test.html b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-builder_test.html new file mode 100644 index 0000000000..c795a02a9a --- /dev/null +++ b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-builder_test.html @@ -0,0 +1,103 @@ + + + + +gr-diff-builder + + + + + + + diff --git a/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-group.js b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-group.js new file mode 100644 index 0000000000..5fd02ddb79 --- /dev/null +++ b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-group.js @@ -0,0 +1,77 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the 'License'); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an 'AS IS' BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +(function(window, GrDiffLine) { + 'use strict'; + + function GrDiffGroup(type, opt_lines) { + this.type = type; + this.lines = []; + this.adds = []; + this.removes = []; + + if (opt_lines) { + opt_lines.forEach(this.addLine, this); + } + } + + GrDiffGroup.Type = { + BOTH: 'both', + DELTA: 'delta', + HEADER: 'header', + }; + + GrDiffGroup.prototype.addLine = function(line) { + this.lines.push(line); + + var notDelta = (this.type === GrDiffGroup.Type.BOTH || + this.type === GrDiffGroup.Type.HEADER); + if (notDelta && (line.type === GrDiffLine.Type.ADD || + line.type === GrDiffLine.Type.REMOVE)) { + throw Error('Cannot add delta line to a non-delta group.'); + } + + if (line.type === GrDiffLine.Type.ADD) { + this.adds.push(line); + } else if (line.type === GrDiffLine.Type.REMOVE) { + this.removes.push(line); + } + }; + + GrDiffGroup.prototype.getSideBySidePairs = function() { + if (this.type === GrDiffGroup.Type.BOTH || + this.type === GrDiffGroup.Type.HEADER) { + return this.lines.map(function(line) { + return { + left: line, + right: line, + }; + }); + } + + var pairs = []; + var i = 0; + var j = 0; + while (i < this.removes.length || j < this.adds.length) { + pairs.push({ + left: this.removes[i] || GrDiffLine.BLANK_LINE, + right: this.adds[j] || GrDiffLine.BLANK_LINE, + }); + i++; + j++; + } + return pairs; + }; + + window.GrDiffGroup = GrDiffGroup; +})(window, GrDiffLine); diff --git a/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-group_test.html b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-group_test.html new file mode 100644 index 0000000000..f09b587f6f --- /dev/null +++ b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-group_test.html @@ -0,0 +1,105 @@ + + + + +gr-diff-group + + + + + + diff --git a/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-line.js b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-line.js new file mode 100644 index 0000000000..4113d6c238 --- /dev/null +++ b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-diff-line.js @@ -0,0 +1,38 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +(function(window) { + 'use strict'; + + function GrDiffLine(type) { + this.type = type; + } + + GrDiffLine.prototype.beforeNumber = 0; + + GrDiffLine.prototype.afterNumber = 0; + + GrDiffLine.prototype.text = ''; + + GrDiffLine.Type = { + ADD: 'add', + BOTH: 'both', + BLANK: 'blank', + REMOVE: 'remove', + }; + + GrDiffLine.BLANK_LINE = new GrDiffLine(GrDiffLine.Type.BLANK); + + window.GrDiffLine = GrDiffLine; + +})(window); diff --git a/polygerrit-ui/app/elements/diff/gr-new-diff/gr-new-diff.html b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-new-diff.html new file mode 100644 index 0000000000..37a0a1e905 --- /dev/null +++ b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-new-diff.html @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/polygerrit-ui/app/elements/diff/gr-new-diff/gr-new-diff.js b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-new-diff.js new file mode 100644 index 0000000000..7edbe73dd8 --- /dev/null +++ b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-new-diff.js @@ -0,0 +1,86 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +(function() { + 'use strict'; + + var DiffViewMode = { + SIDE_BY_SIDE: 'SIDE_BY_SIDE', + UNIFIED: 'UNIFIED_DIFF', + }; + + Polymer({ + is: 'gr-new-diff', + + properties: { + availablePatches: Array, + changeNum: String, + patchRange: Object, + path: String, + prefs: { + type: Object, + notify: true, + }, + projectConfig: Object, + + _loading: { + type: Boolean, + value: true, + }, + _viewMode: { + type: String, + value: DiffViewMode.SIDE_BY_SIDE, + }, + }, + + observers: [ + '_prefsChanged(prefs.*)', + ], + + reload: function() { + this.$.diffTable.innerHTML = null; + this._loading = true; + + return this._getDiff().then(function(diff) { + var builder = this._getDiffBuilder(diff); + builder.emitDiff(diff.content); + + this._loading = false; + }.bind(this)); + }, + + _prefsChanged: function(changeRecord) { + var prefs = changeRecord.base; + this.customStyle['--content-width'] = prefs.line_length + 'ch'; + this.updateStyles(); + }, + + _getDiff: function() { + return this.$.restAPI.getDiff( + this.changeNum, + this.patchRange.basePatchNum, + this.patchRange.patchNum, + this.path); + }, + + _getDiffBuilder: function(diff) { + if (this._viewMode === DiffViewMode.SIDE_BY_SIDE) { + return new GrDiffBuilderSideBySide(diff, this.$.diffTable); + } else if (this._viewMode === DiffViewMode.UNIFIED) { + return new GrDiffBuilderUnified(diff, this.$.diffTable); + } + throw Error('Unsupported diff view mode: ' + this._viewMode); + }, + + }); +})(); diff --git a/polygerrit-ui/app/elements/diff/gr-new-diff/gr-new-diff_test.html b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-new-diff_test.html new file mode 100644 index 0000000000..a899d6b574 --- /dev/null +++ b/polygerrit-ui/app/elements/diff/gr-new-diff/gr-new-diff_test.html @@ -0,0 +1,48 @@ + + + + +gr-new-diff + + + + + + + + + + + + diff --git a/polygerrit-ui/app/test/index.html b/polygerrit-ui/app/test/index.html index 31d93b78ea..5da0ace5a8 100644 --- a/polygerrit-ui/app/test/index.html +++ b/polygerrit-ui/app/test/index.html @@ -45,6 +45,9 @@ limitations under the License. '../elements/diff/gr-diff-preferences/gr-diff-preferences_test.html', '../elements/diff/gr-diff-side/gr-diff-side_test.html', '../elements/diff/gr-diff-view/gr-diff-view_test.html', + '../elements/diff/gr-new-diff/gr-diff-builder_test.html', + '../elements/diff/gr-new-diff/gr-diff-group_test.html', + '../elements/diff/gr-new-diff/gr-new-diff_test.html', '../elements/diff/gr-patch-range-select/gr-patch-range-select_test.html', '../elements/shared/gr-account-label/gr-account-label_test.html', '../elements/shared/gr-account-link/gr-account-link_test.html',