Make gr-builder a Polymer component
Updated tests, fixed draft comments, context expanding.
Change-Id: Ic4bd9682c63edd8e80fbc2abcb4fa5e406a202ab
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder-image.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder-image.js
deleted file mode 100644
index b897708..0000000
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder-image.js
+++ /dev/null
@@ -1,100 +0,0 @@
-// 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, GrDiffBuilderSideBySide) {
- 'use strict';
-
- function GrDiffBuilderImage(diff, comments, prefs, outputEl, baseImage,
- revisionImage) {
- GrDiffBuilderSideBySide.call(this, diff, comments, prefs, outputEl);
- this._baseImage = baseImage;
- this._revisionImage = revisionImage;
- }
-
- GrDiffBuilderImage.prototype = Object.create(
- GrDiffBuilderSideBySide.prototype);
- GrDiffBuilderImage.prototype.constructor = GrDiffBuilderImage;
-
- GrDiffBuilderImage.prototype.emitDiff = function() {
- this.emitGroup(this._groups[0]);
-
- var section = this._createElement('tbody', 'image-diff');
-
- this._emitImagePair(section);
- this._emitImageLabels(section);
-
- this._outputEl.appendChild(section);
- };
-
- GrDiffBuilderImage.prototype._emitImagePair = function(section) {
- var tr = this._createElement('tr');
-
- tr.appendChild(this._createElement('td'));
- tr.appendChild(this._createImageCell(this._baseImage, 'left'));
-
- tr.appendChild(this._createElement('td'));
- tr.appendChild(this._createImageCell(this._revisionImage, 'right'));
-
- section.appendChild(tr);
- };
-
- GrDiffBuilderImage.prototype._createImageCell = function(image, className) {
- var td = this._createElement('td', className);
- if (image) {
- var imageEl = this._createElement('img');
- imageEl.src = 'data:' + image.type + ';base64, ' + image.body;
- image._height = imageEl.naturalHeight;
- image._width = imageEl.naturalWidth;
- imageEl.addEventListener('error', function(e) {
- imageEl.remove();
- td.textContent = '[Image failed to load]';
- });
- td.appendChild(imageEl);
- }
- return td;
- };
-
- GrDiffBuilderImage.prototype._emitImageLabels = function(section) {
- var tr = this._createElement('tr');
-
- tr.appendChild(this._createElement('td'));
- var td = this._createElement('td', 'left');
- var label = this._createElement('label');
- label.textContent = this._getImageLabel(this._baseImage);
- td.appendChild(label);
- tr.appendChild(td);
-
- tr.appendChild(this._createElement('td'));
- td = this._createElement('td', 'right');
- label = this._createElement('label');
- label.textContent = this._getImageLabel(this._revisionImage);
- td.appendChild(label);
- tr.appendChild(td);
-
- section.appendChild(tr);
- };
-
- GrDiffBuilderImage.prototype._getImageLabel = function(image) {
- if (image) {
- var type = image.type || image._expectedType;
- if (image._width && image._height) {
- return image._width + '⨉' + image._height + ' ' + type;
- } else {
- return type;
- }
- }
- return 'No image';
- };
-
- window.GrDiffBuilderImage = GrDiffBuilderImage;
-})(window, GrDiffBuilderSideBySide);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder-side-by-side.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder-side-by-side.js
deleted file mode 100644
index 7e8779f..0000000
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder-side-by-side.js
+++ /dev/null
@@ -1,68 +0,0 @@
-// 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, comments, prefs, outputEl) {
- GrDiffBuilder.call(this, diff, comments, prefs, outputEl);
- }
- GrDiffBuilderSideBySide.prototype = Object.create(GrDiffBuilder.prototype);
- GrDiffBuilderSideBySide.prototype.constructor = GrDiffBuilderSideBySide;
-
- GrDiffBuilderSideBySide.prototype.buildSectionElement = function(group,
- opt_beforeSection) {
- var sectionEl = this._createElement('tbody', 'section');
- sectionEl.classList.add(group.type);
- var pairs = group.getSideBySidePairs();
- for (var i = 0; i < pairs.length; i++) {
- sectionEl.appendChild(this._createRow(sectionEl, pairs[i].left,
- pairs[i].right));
- }
- return sectionEl;
- };
-
- GrDiffBuilderSideBySide.prototype._createRow = function(section, leftLine,
- rightLine) {
- var row = this._createElement('tr');
- row.classList.add('diff-row', 'side-by-side');
- row.setAttribute('left-type', leftLine.type);
- row.setAttribute('right-type', rightLine.type);
-
- this._appendPair(section, row, leftLine, leftLine.beforeNumber,
- GrDiffBuilder.Side.LEFT);
- this._appendPair(section, row, rightLine, rightLine.afterNumber,
- GrDiffBuilder.Side.RIGHT);
- return row;
- };
-
- GrDiffBuilderSideBySide.prototype._appendPair = function(section, row, line,
- lineNumber, side) {
- var lineEl = this._createLineEl(line, lineNumber, line.type, side);
- lineEl.classList.add(side);
- row.appendChild(lineEl);
- var action = this._createContextControl(section, line);
- if (action) {
- row.appendChild(action);
- } else {
- var textEl = this._createTextEl(line);
- var threadEl = this._commentThreadForLine(line, side);
- if (threadEl) {
- textEl.appendChild(threadEl);
- }
- row.appendChild(textEl);
- }
- };
-
- window.GrDiffBuilderSideBySide = GrDiffBuilderSideBySide;
-})(window, GrDiffBuilder);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder-unified.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder-unified.js
deleted file mode 100644
index 2f1aac6..0000000
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder-unified.js
+++ /dev/null
@@ -1,60 +0,0 @@
-// 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, comments, prefs, outputEl) {
- GrDiffBuilder.call(this, diff, comments, prefs, outputEl);
- }
- GrDiffBuilderUnified.prototype = Object.create(GrDiffBuilder.prototype);
- GrDiffBuilderUnified.prototype.constructor = GrDiffBuilderUnified;
-
- GrDiffBuilderUnified.prototype.buildSectionElement = function(group) {
- var sectionEl = this._createElement('tbody', 'section');
- sectionEl.classList.add(group.type);
-
- for (var i = 0; i < group.lines.length; ++i) {
- sectionEl.appendChild(this._createRow(sectionEl, group.lines[i]));
- }
- return sectionEl;
- };
-
- GrDiffBuilderUnified.prototype._createRow = function(section, line) {
- var row = this._createElement('tr', line.type);
- var lineEl = this._createLineEl(line, line.beforeNumber,
- GrDiffLine.Type.REMOVE);
- lineEl.classList.add('left');
- row.appendChild(lineEl);
- lineEl = this._createLineEl(line, line.afterNumber,
- GrDiffLine.Type.ADD);
- lineEl.classList.add('right');
- row.appendChild(lineEl);
- row.classList.add('diff-row', 'unified');
-
- var action = this._createContextControl(section, line);
- if (action) {
- row.appendChild(action);
- } else {
- var textEl = this._createTextEl(line);
- var threadEl = this._commentThreadForLine(line);
- if (threadEl) {
- textEl.appendChild(threadEl);
- }
- row.appendChild(textEl);
- }
- return row;
- };
-
- window.GrDiffBuilderUnified = GrDiffBuilderUnified;
-})(window, GrDiffBuilder);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder.js
deleted file mode 100644
index f03687c..0000000
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder.js
+++ /dev/null
@@ -1,691 +0,0 @@
-// 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, comments, prefs, outputEl) {
- this._diff = diff;
- this._comments = comments;
- this._prefs = prefs;
- this._outputEl = outputEl;
- this._groups = [];
-
- this._commentLocations = this._getCommentLocations(comments);
- this._processContent(diff.content, this._groups, prefs.context);
- }
-
- GrDiffBuilder.LESS_THAN_CODE = '<'.charCodeAt(0);
- GrDiffBuilder.GREATER_THAN_CODE = '>'.charCodeAt(0);
- GrDiffBuilder.AMPERSAND_CODE = '&'.charCodeAt(0);
- GrDiffBuilder.SEMICOLON_CODE = ';'.charCodeAt(0);
-
- GrDiffBuilder.TAB_REGEX = /\t/g;
-
- GrDiffBuilder.LINE_FEED_HTML =
- '<span class="style-scope gr-diff br"></span>';
-
- GrDiffBuilder.GroupType = {
- ADDED: 'b',
- BOTH: 'ab',
- REMOVED: 'a',
- };
-
- GrDiffBuilder.Highlights = {
- ADDED: 'edit_b',
- REMOVED: 'edit_a',
- };
-
- GrDiffBuilder.Side = {
- LEFT: 'left',
- RIGHT: 'right',
- };
-
- GrDiffBuilder.ContextButtonType = {
- ABOVE: 'above',
- BELOW: 'below',
- ALL: 'all',
- };
-
- var PARTIAL_CONTEXT_AMOUNT = 10;
-
- GrDiffBuilder.prototype.emitDiff = function() {
- for (var i = 0; i < this._groups.length; i++) {
- this.emitGroup(this._groups[i]);
- }
- };
-
- GrDiffBuilder.prototype.buildSectionElement = function(
- group, opt_beforeSection) {
- throw Error('Subclasses must implement buildGroupElement');
- };
-
- GrDiffBuilder.prototype.emitGroup = function(group, opt_beforeSection) {
- var element = this.buildSectionElement(group);
- this._outputEl.insertBefore(element, opt_beforeSection);
- group.element = element;
- };
-
- GrDiffBuilder.prototype.renderSection = function(element) {
- for (var i = 0; i < this._groups.length; i++) {
- var group = this._groups[i];
- if (group.element === element) {
- var newElement = this.buildSectionElement(group);
- group.element.parentElement.replaceChild(newElement, group.element);
- group.element = newElement;
- break;
- }
- }
- };
-
- GrDiffBuilder.prototype.getSectionsByLineRange = function(
- startLine, endLine, opt_side) {
- var sections = [];
- for (var i = 0; i < this._groups.length; i++) {
- var group = this._groups[i];
- if (group.lines.length === 0) {
- continue;
- }
- var groupStartLine;
- var groupEndLine;
- if (opt_side === GrDiffBuilder.Side.LEFT) {
- groupStartLine = group.lines[0].beforeNumber;
- groupEndLine = group.lines[group.lines.length - 1].beforeNumber;
- } else if (opt_side === GrDiffBuilder.Side.RIGHT) {
- groupStartLine = group.lines[0].afterNumber;
- groupEndLine = group.lines[group.lines.length - 1].afterNumber;
- }
- if (startLine <= groupEndLine && endLine >= groupStartLine) {
- sections.push(group.element);
- }
- }
- return sections;
- };
-
- GrDiffBuilder.prototype._processContent = function(content, groups, context) {
- this._appendFileComments(groups);
-
- var WHOLE_FILE = -1;
- context = content.length > 1 ? context : WHOLE_FILE;
-
- var lineNums = {
- left: 0,
- right: 0,
- };
- content = this._splitCommonGroupsWithComments(content, lineNums);
- 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];
- this._appendCommonLines(rows, lines, lineNums);
-
- var hiddenRange = [context, rows.length - context];
- if (i === 0) {
- hiddenRange[0] = 0;
- } else if (i === content.length - 1) {
- hiddenRange[1] = rows.length;
- }
-
- if (context !== WHOLE_FILE && hiddenRange[1] - hiddenRange[0] > 0) {
- this._insertContextGroups(groups, lines, hiddenRange);
- } else {
- groups.push(new GrDiffGroup(GrDiffGroup.Type.BOTH, lines));
- }
- continue;
- }
-
- if (group[GrDiffBuilder.GroupType.REMOVED] !== undefined) {
- var highlights = undefined;
- if (group[GrDiffBuilder.Highlights.REMOVED] !== undefined) {
- highlights = this._normalizeIntralineHighlights(
- group[GrDiffBuilder.GroupType.REMOVED],
- group[GrDiffBuilder.Highlights.REMOVED]);
- }
- this._appendRemovedLines(group[GrDiffBuilder.GroupType.REMOVED], lines,
- lineNums, highlights);
- }
-
- if (group[GrDiffBuilder.GroupType.ADDED] !== undefined) {
- var highlights = undefined;
- if (group[GrDiffBuilder.Highlights.ADDED] !== undefined) {
- highlights = this._normalizeIntralineHighlights(
- group[GrDiffBuilder.GroupType.ADDED],
- group[GrDiffBuilder.Highlights.ADDED]);
- }
- this._appendAddedLines(group[GrDiffBuilder.GroupType.ADDED], lines,
- lineNums, highlights);
- }
- groups.push(new GrDiffGroup(GrDiffGroup.Type.DELTA, lines));
- }
- };
-
- GrDiffBuilder.prototype._appendFileComments = function(groups) {
- var line = new GrDiffLine(GrDiffLine.Type.BOTH);
- line.beforeNumber = GrDiffLine.FILE;
- line.afterNumber = GrDiffLine.FILE;
- groups.push(new GrDiffGroup(GrDiffGroup.Type.BOTH, [line]));
- };
-
- GrDiffBuilder.prototype._getCommentLocations = function(comments) {
- var result = {
- left: {},
- right: {},
- };
- for (var side in comments) {
- if (side !== GrDiffBuilder.Side.LEFT &&
- side !== GrDiffBuilder.Side.RIGHT) {
- continue;
- }
- comments[side].forEach(function(c) {
- result[side][c.line || GrDiffLine.FILE] = true;
- });
- }
- return result;
- };
-
- GrDiffBuilder.prototype._commentIsAtLineNum = function(side, lineNum) {
- return this._commentLocations[side][lineNum] === true;
- };
-
- // In order to show comments out of the bounds of the selected context,
- // treat them as separate chunks within the model so that the content (and
- // context surrounding it) renders correctly.
- GrDiffBuilder.prototype._splitCommonGroupsWithComments = function(content,
- lineNums) {
- var result = [];
- var leftLineNum = lineNums.left;
- var rightLineNum = lineNums.right;
- for (var i = 0; i < content.length; i++) {
- if (!content[i].ab) {
- result.push(content[i]);
- if (content[i].a) {
- leftLineNum += content[i].a.length;
- }
- if (content[i].b) {
- rightLineNum += content[i].b.length;
- }
- continue;
- }
- var chunk = content[i].ab;
- var currentChunk = {ab: []};
- for (var j = 0; j < chunk.length; j++) {
- leftLineNum++;
- rightLineNum++;
- if (this._commentIsAtLineNum(GrDiffBuilder.Side.LEFT, leftLineNum) ||
- this._commentIsAtLineNum(GrDiffBuilder.Side.RIGHT, rightLineNum)) {
- if (currentChunk.ab && currentChunk.ab.length > 0) {
- result.push(currentChunk);
- currentChunk = {ab: []};
- }
- result.push({ab: [chunk[j]]});
- } else {
- currentChunk.ab.push(chunk[j]);
- }
- }
- // != instead of !== because we want to cover both undefined and null.
- if (currentChunk.ab != null && currentChunk.ab.length > 0) {
- result.push(currentChunk);
- }
- }
- return result;
- };
-
- // The `highlights` array consists of a list of <skip length, mark length>
- // pairs, where the skip length is the number of characters between the
- // end of the previous edit and the start of this edit, and the mark
- // length is the number of edited characters following the skip. The start
- // of the edits is from the beginning of the related diff content lines.
- //
- // Note that the implied newline character at the end of each line is
- // included in the length calculation, and thus it is possible for the
- // edits to span newlines.
- //
- // A line highlight object consists of three fields:
- // - contentIndex: The index of the diffChunk `content` field (the line
- // being referred to).
- // - startIndex: Where the highlight should begin.
- // - endIndex: (optional) Where the highlight should end. If omitted, the
- // highlight is meant to be a continuation onto the next line.
- GrDiffBuilder.prototype._normalizeIntralineHighlights = function(content,
- highlights) {
- var contentIndex = 0;
- var idx = 0;
- var normalized = [];
- for (var i = 0; i < highlights.length; i++) {
- var line = content[contentIndex] + '\n';
- var hl = highlights[i];
- var j = 0;
- while (j < hl[0]) {
- if (idx === line.length) {
- idx = 0;
- line = content[++contentIndex] + '\n';
- continue;
- }
- idx++;
- j++;
- }
- var lineHighlight = {
- contentIndex: contentIndex,
- startIndex: idx,
- };
-
- j = 0;
- while (line && j < hl[1]) {
- if (idx === line.length) {
- idx = 0;
- line = content[++contentIndex] + '\n';
- normalized.push(lineHighlight);
- lineHighlight = {
- contentIndex: contentIndex,
- startIndex: idx,
- };
- continue;
- }
- idx++;
- j++;
- }
- lineHighlight.endIndex = idx;
- normalized.push(lineHighlight);
- }
- return normalized;
- };
-
- GrDiffBuilder.prototype._insertContextGroups = function(groups, lines,
- hiddenRange) {
- var linesBeforeCtx = lines.slice(0, hiddenRange[0]);
- var hiddenLines = lines.slice(hiddenRange[0], hiddenRange[1]);
- var linesAfterCtx = lines.slice(hiddenRange[1]);
-
- if (linesBeforeCtx.length > 0) {
- groups.push(new GrDiffGroup(GrDiffGroup.Type.BOTH, linesBeforeCtx));
- }
-
- var ctxLine = new GrDiffLine(GrDiffLine.Type.CONTEXT_CONTROL);
- ctxLine.contextGroup =
- new GrDiffGroup(GrDiffGroup.Type.BOTH, hiddenLines);
- groups.push(new GrDiffGroup(GrDiffGroup.Type.CONTEXT_CONTROL,
- [ctxLine]));
-
- if (linesAfterCtx.length > 0) {
- groups.push(new GrDiffGroup(GrDiffGroup.Type.BOTH, linesAfterCtx));
- }
- };
-
- GrDiffBuilder.prototype._appendCommonLines = function(rows, lines, lineNums) {
- for (var i = 0; i < rows.length; i++) {
- var line = new GrDiffLine(GrDiffLine.Type.BOTH);
- line.text = rows[i];
- line.beforeNumber = ++lineNums.left;
- line.afterNumber = ++lineNums.right;
- lines.push(line);
- }
- };
-
- GrDiffBuilder.prototype._appendRemovedLines = function(rows, lines, lineNums,
- opt_highlights) {
- for (var i = 0; i < rows.length; i++) {
- var line = new GrDiffLine(GrDiffLine.Type.REMOVE);
- line.text = rows[i];
- line.beforeNumber = ++lineNums.left;
- if (opt_highlights) {
- line.highlights = opt_highlights.filter(function(hl) {
- return hl.contentIndex === i;
- });
- }
- lines.push(line);
- }
- };
-
- GrDiffBuilder.prototype._appendAddedLines = function(rows, lines, lineNums,
- opt_highlights) {
- for (var i = 0; i < rows.length; i++) {
- var line = new GrDiffLine(GrDiffLine.Type.ADD);
- line.text = rows[i];
- line.afterNumber = ++lineNums.right;
- if (opt_highlights) {
- line.highlights = opt_highlights.filter(function(hl) {
- return hl.contentIndex === i;
- });
- }
- lines.push(line);
- }
- };
-
- GrDiffBuilder.prototype._createContextControl = function(section, line) {
- if (!line.contextGroup || !line.contextGroup.lines.length) {
- return null;
- }
-
- var td = this._createElement('td');
- var showPartialLinks =
- line.contextGroup.lines.length > PARTIAL_CONTEXT_AMOUNT;
-
- if (showPartialLinks) {
- td.appendChild(this._createContextButton(
- GrDiffBuilder.ContextButtonType.ABOVE, section, line));
- td.appendChild(document.createTextNode(' - '));
- }
-
- td.appendChild(this._createContextButton(
- GrDiffBuilder.ContextButtonType.ALL, section, line));
-
- if (showPartialLinks) {
- td.appendChild(document.createTextNode(' - '));
- td.appendChild(this._createContextButton(
- GrDiffBuilder.ContextButtonType.BELOW, section, line));
- }
-
- return td;
- };
-
- GrDiffBuilder.prototype._createContextButton = function(type, section, line) {
- var contextLines = line.contextGroup.lines;
- var context = PARTIAL_CONTEXT_AMOUNT;
-
- var button = this._createElement('gr-button', 'showContext');
- button.setAttribute('link', true);
-
- var text;
- var groups = []; // The groups that replace this one if tapped.
-
- if (type === GrDiffBuilder.ContextButtonType.ALL) {
- text = 'Show ' + contextLines.length + ' common line';
- if (contextLines.length > 1) { text += 's'; }
- groups.push(line.contextGroup);
- } else if (type === GrDiffBuilder.ContextButtonType.ABOVE) {
- text = '+' + context + '↑';
- this._insertContextGroups(groups, contextLines,
- [context, contextLines.length]);
- } else if (type === GrDiffBuilder.ContextButtonType.BELOW) {
- text = '+' + context + '↓';
- this._insertContextGroups(groups, contextLines,
- [0, contextLines.length - context]);
- }
-
- button.textContent = text;
-
- button.addEventListener('tap', function(e) {
- e.detail = {
- groups: groups,
- section: section,
- };
- // Let it bubble up the DOM tree.
- });
-
- return button;
- };
-
- GrDiffBuilder.prototype._getCommentsForLine = function(comments, line,
- opt_side) {
- function byLineNum(lineNum) {
- return function(c) {
- return (c.line === lineNum) ||
- (c.line === undefined && lineNum === GrDiffLine.FILE);
- };
- }
- var leftComments =
- comments[GrDiffBuilder.Side.LEFT].filter(byLineNum(line.beforeNumber));
- var rightComments =
- comments[GrDiffBuilder.Side.RIGHT].filter(byLineNum(line.afterNumber));
-
- var result;
-
- switch (opt_side) {
- case GrDiffBuilder.Side.LEFT:
- result = leftComments;
- break;
- case GrDiffBuilder.Side.RIGHT:
- result = rightComments;
- break;
- default:
- result = leftComments.concat(rightComments);
- break;
- }
-
- return result;
- };
-
- GrDiffBuilder.prototype.createCommentThread = function(changeNum, patchNum,
- path, side, projectConfig) {
- var threadEl = document.createElement('gr-diff-comment-thread');
- threadEl.changeNum = changeNum;
- threadEl.patchNum = patchNum;
- threadEl.path = path;
- threadEl.side = side;
- threadEl.projectConfig = projectConfig;
- return threadEl;
- };
-
- GrDiffBuilder.prototype._commentThreadForLine = function(line, opt_side) {
- var comments = this._getCommentsForLine(this._comments, line, opt_side);
- if (!comments || comments.length === 0) {
- return null;
- }
-
- var patchNum = this._comments.meta.patchRange.patchNum;
- var side = comments[0].side || 'REVISION';
- if (line.type === GrDiffLine.Type.REMOVE ||
- opt_side === GrDiffBuilder.Side.LEFT) {
- if (this._comments.meta.patchRange.basePatchNum === 'PARENT') {
- side = 'PARENT';
- } else {
- patchNum = this._comments.meta.patchRange.basePatchNum;
- }
- }
- var threadEl = this.createCommentThread(
- this._comments.meta.changeNum,
- patchNum,
- this._comments.meta.path,
- side,
- this._comments.meta.projectConfig);
- threadEl.comments = comments;
- return threadEl;
- };
-
- GrDiffBuilder.prototype._createLineEl = function(line, number, type,
- opt_class) {
- var td = this._createElement('td');
- if (opt_class) {
- td.classList.add(opt_class);
- }
- if (line.type === GrDiffLine.Type.BLANK) {
- return td;
- } else if (line.type === GrDiffLine.Type.CONTEXT_CONTROL) {
- td.classList.add('contextLineNum');
- td.setAttribute('data-value', '@@');
- } else if (line.type === GrDiffLine.Type.BOTH || line.type === type) {
- td.classList.add('lineNum');
- td.setAttribute('data-value', number);
- }
- return td;
- };
-
- GrDiffBuilder.prototype._createTextEl = function(line) {
- var td = this._createElement('td');
- if (line.type !== GrDiffLine.Type.BLANK) {
- td.classList.add('content');
- }
- td.classList.add(line.type);
- var text = line.text;
- var html = util.escapeHTML(text);
-
- td.classList.add(line.highlights.length > 0 ?
- 'lightHighlight' : 'darkHighlight');
-
- if (line.highlights.length > 0) {
- html = this._addIntralineHighlights(text, html, line.highlights);
- }
-
- if (this._textLength(text, this._prefs.tab_size) >
- this._prefs.line_length) {
- html = this._addNewlines(text, html);
- }
- html = this._addTabWrappers(html);
-
- // 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._textLength = function(text, tabSize) {
- // TODO(andybons): Unicode support.
- var numChars = 0;
- for (var i = 0; i < text.length; i++) {
- if (text[i] === '\t') {
- numChars += tabSize;
- } else {
- numChars++;
- }
- }
- return numChars;
- };
-
- // Advance `index` by the appropriate number of characters that would
- // represent one source code character and return that index. For
- // example, for source code '<span>' the escaped html string is
- // '<span>'. Advancing from index 0 on the prior html string would
- // return 4, since < maps to one source code character ('<').
- GrDiffBuilder.prototype._advanceChar = function(html, index) {
- // TODO(andybons): Unicode is all kinds of messed up in JS. Account for it.
- // https://mathiasbynens.be/notes/javascript-unicode
-
- // Tags don't count as characters
- while (index < html.length &&
- html.charCodeAt(index) === GrDiffBuilder.LESS_THAN_CODE) {
- while (index < html.length &&
- html.charCodeAt(index) !== GrDiffBuilder.GREATER_THAN_CODE) {
- index++;
- }
- index++; // skip the ">" itself
- }
- // An HTML entity (e.g., <) counts as one character.
- if (index < html.length &&
- html.charCodeAt(index) === GrDiffBuilder.AMPERSAND_CODE) {
- while (index < html.length &&
- html.charCodeAt(index) !== GrDiffBuilder.SEMICOLON_CODE) {
- index++;
- }
- }
- return index + 1;
- };
-
- GrDiffBuilder.prototype._addNewlines = function(text, html) {
- var htmlIndex = 0;
- var indices = [];
- var numChars = 0;
- for (var i = 0; i < text.length; i++) {
- if (numChars > 0 && numChars % this._prefs.line_length === 0) {
- indices.push(htmlIndex);
- }
- htmlIndex = this._advanceChar(html, htmlIndex);
- if (text[i] === '\t') {
- numChars += this._prefs.tab_size;
- } else {
- numChars++;
- }
- }
- var result = html;
- // Since the result string is being altered in place, start from the end
- // of the string so that the insertion indices are not affected as the
- // result string changes.
- for (var i = indices.length - 1; i >= 0; i--) {
- result = result.slice(0, indices[i]) + GrDiffBuilder.LINE_FEED_HTML +
- result.slice(indices[i]);
- }
- return result;
- };
-
- GrDiffBuilder.prototype._addTabWrappers = function(html) {
- var htmlStr = this._getTabWrapper(this._prefs.tab_size,
- this._prefs.show_tabs);
- return html.replace(GrDiffBuilder.TAB_REGEX, htmlStr);
- };
-
- GrDiffBuilder.prototype._addIntralineHighlights = function(content, html,
- highlights) {
- var START_TAG = '<hl class="style-scope gr-diff">';
- var END_TAG = '</hl>';
-
- for (var i = 0; i < highlights.length; i++) {
- var hl = highlights[i];
-
- var htmlStartIndex = 0;
- // Find the index of the HTML string to insert the start tag.
- for (var j = 0; j < hl.startIndex; j++) {
- htmlStartIndex = this._advanceChar(html, htmlStartIndex);
- }
-
- var htmlEndIndex = 0;
- if (hl.endIndex !== undefined) {
- for (var j = 0; j < hl.endIndex; j++) {
- htmlEndIndex = this._advanceChar(html, htmlEndIndex);
- }
- } else {
- // If endIndex isn't present, continue to the end of the line.
- htmlEndIndex = html.length;
- }
- // The start and end indices could be the same if a highlight is meant
- // to start at the end of a line and continue onto the next one.
- // Ignore it.
- if (htmlStartIndex !== htmlEndIndex) {
- html = html.slice(0, htmlStartIndex) + START_TAG +
- html.slice(htmlStartIndex, htmlEndIndex) + END_TAG +
- html.slice(htmlEndIndex);
- }
- }
- return html;
- };
-
- GrDiffBuilder.prototype._getTabWrapper = function(tabSize, showTabs) {
- // Force this to be a number to prevent arbitrary injection.
- tabSize = +tabSize;
- if (isNaN(tabSize)) {
- throw Error('Invalid tab size from preferences.');
- }
-
- var str = '<span class="style-scope gr-diff tab ';
- if (showTabs) {
- str += 'withIndicator';
- }
- str += '" style="';
- // TODO(andybons): CSS tab-size is not supported in IE.
- str += 'tab-size:' + tabSize + ';';
- str += '-moz-tab-size:' + tabSize + ';';
- str += '">\t</span>';
- return str;
- };
-
- 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-diff');
- if (!!className) {
- el.classList.add(className);
- }
- return el;
- };
-
- window.GrDiffBuilder = GrDiffBuilder;
-})(window, GrDiffGroup, GrDiffLine);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder_test.html
deleted file mode 100644
index 5905bd9..0000000
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-builder_test.html
+++ /dev/null
@@ -1,602 +0,0 @@
-<!DOCTYPE html>
-<!--
-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.
--->
-
-<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
-<title>gr-diff-builder</title>
-
-<script src="../../../bower_components/web-component-tester/browser.js"></script>
-<script src="gr-diff-line.js"></script>
-<script src="gr-diff-group.js"></script>
-<script src="gr-diff-builder.js"></script>
-
-<script>
- suite('gr-diff-builder tests', function() {
- var builder;
-
- setup(function() {
- var prefs = {
- line_length: 10,
- show_tabs: true,
- tab_size: 4,
- };
- builder = new GrDiffBuilder({content: []}, {left: [], right: []}, prefs);
- });
-
- test('process loaded content', function() {
- var content = [
- {
- ab: [
- '<!DOCTYPE html>',
- '<meta charset="utf-8">',
- ]
- },
- {
- a: [
- ' Welcome ',
- ' to the wooorld of tomorrow!',
- ],
- b: [
- ' Hello, world!',
- ],
- },
- {
- ab: [
- 'Leela: This is the only place the ship can’t hear us, so ',
- 'everyone pretend to shower.',
- 'Fry: Same as every day. Got it.',
- ]
- },
- ];
- var groups = [];
-
- builder._processContent(content, groups, -1);
-
- assert.equal(groups.length, 4);
-
- var group = groups[0];
- assert.equal(group.type, GrDiffGroup.Type.BOTH);
- assert.equal(group.lines.length, 1);
- assert.equal(group.lines[0].text, '');
- assert.equal(group.lines[0].beforeNumber, GrDiffLine.FILE);
- assert.equal(group.lines[0].afterNumber, GrDiffLine.FILE);
-
- group = groups[1];
- assert.equal(group.type, GrDiffGroup.Type.BOTH);
- assert.equal(group.lines.length, 2);
- assert.equal(group.lines.length, 2);
-
- function beforeNumberFn(l) { return l.beforeNumber; }
- function afterNumberFn(l) { return l.afterNumber; }
- function textFn(l) { return l.text; }
-
- assert.deepEqual(group.lines.map(beforeNumberFn), [1, 2]);
- assert.deepEqual(group.lines.map(afterNumberFn), [1, 2]);
- assert.deepEqual(group.lines.map(textFn), [
- '<!DOCTYPE html>',
- '<meta charset="utf-8">',
- ]);
-
- group = groups[2];
- assert.equal(group.type, GrDiffGroup.Type.DELTA);
- assert.equal(group.lines.length, 3);
- assert.equal(group.adds.length, 1);
- assert.equal(group.removes.length, 2);
- assert.deepEqual(group.removes.map(beforeNumberFn), [3, 4]);
- assert.deepEqual(group.adds.map(afterNumberFn), [3]);
- assert.deepEqual(group.removes.map(textFn), [
- ' Welcome ',
- ' to the wooorld of tomorrow!',
- ]);
- assert.deepEqual(group.adds.map(textFn), [
- ' Hello, world!',
- ]);
-
- group = groups[3];
- assert.equal(group.type, GrDiffGroup.Type.BOTH);
- assert.equal(group.lines.length, 3);
- assert.deepEqual(group.lines.map(beforeNumberFn), [5, 6, 7]);
- assert.deepEqual(group.lines.map(afterNumberFn), [4, 5, 6]);
- assert.deepEqual(group.lines.map(textFn), [
- 'Leela: This is the only place the ship can’t hear us, so ',
- 'everyone pretend to shower.',
- 'Fry: Same as every day. Got it.',
- ]);
- });
-
- test('insert context groups', function() {
- var content = [
- {ab: []},
- {a: ['all work and no play make andybons a dull boy']},
- {ab: []},
- {b: ['elgoog elgoog elgoog']},
- {ab: []},
- ];
- for (var i = 0; i < 100; i++) {
- content[0].ab.push('all work and no play make jack a dull boy');
- content[4].ab.push('all work and no play make jill a dull girl');
- }
- for (var i = 0; i < 5; i++) {
- content[2].ab.push('no tv and no beer make homer go crazy');
- }
- var groups = [];
- var context = 10;
-
- builder._processContent(content, groups, context);
-
- assert.equal(groups[0].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[0].lines.length, 1);
- assert.equal(groups[0].lines[0].text, '');
- assert.equal(groups[0].lines[0].beforeNumber, GrDiffLine.FILE);
- assert.equal(groups[0].lines[0].afterNumber, GrDiffLine.FILE);
-
- assert.equal(groups[1].type, GrDiffGroup.Type.CONTEXT_CONTROL);
- assert.instanceOf(groups[1].lines[0].contextGroup, GrDiffGroup);
- assert.equal(groups[1].lines[0].contextGroup.lines.length, 90);
- groups[1].lines[0].contextGroup.lines.forEach(function(l) {
- assert.equal(l.text, content[0].ab[0]);
- });
-
- assert.equal(groups[2].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[2].lines.length, context);
- groups[2].lines.forEach(function(l) {
- assert.equal(l.text, content[0].ab[0]);
- });
-
- assert.equal(groups[3].type, GrDiffGroup.Type.DELTA);
- assert.equal(groups[3].lines.length, 1);
- assert.equal(groups[3].removes.length, 1);
- assert.equal(groups[3].removes[0].text,
- 'all work and no play make andybons a dull boy');
-
- assert.equal(groups[4].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[4].lines.length, 5);
- groups[4].lines.forEach(function(l) {
- assert.equal(l.text, content[2].ab[0]);
- });
-
- assert.equal(groups[5].type, GrDiffGroup.Type.DELTA);
- assert.equal(groups[5].lines.length, 1);
- assert.equal(groups[5].adds.length, 1);
- assert.equal(groups[5].adds[0].text, 'elgoog elgoog elgoog');
-
- assert.equal(groups[6].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[6].lines.length, context);
- groups[6].lines.forEach(function(l) {
- assert.equal(l.text, content[4].ab[0]);
- });
-
- assert.equal(groups[7].type, GrDiffGroup.Type.CONTEXT_CONTROL);
- assert.instanceOf(groups[7].lines[0].contextGroup, GrDiffGroup);
- assert.equal(groups[7].lines[0].contextGroup.lines.length, 90);
- groups[7].lines[0].contextGroup.lines.forEach(function(l) {
- assert.equal(l.text, content[4].ab[0]);
- });
-
- content = [
- {a: ['all work and no play make andybons a dull boy']},
- {ab: []},
- {b: ['elgoog elgoog elgoog']},
- ];
- for (var i = 0; i < 50; i++) {
- content[1].ab.push('no tv and no beer make homer go crazy');
- }
- groups = [];
-
- builder._processContent(content, groups, 10);
-
- assert.equal(groups[0].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[0].lines.length, 1);
- assert.equal(groups[0].lines[0].text, '');
- assert.equal(groups[0].lines[0].beforeNumber, GrDiffLine.FILE);
- assert.equal(groups[0].lines[0].afterNumber, GrDiffLine.FILE);
-
- assert.equal(groups[1].type, GrDiffGroup.Type.DELTA);
- assert.equal(groups[1].lines.length, 1);
- assert.equal(groups[1].removes.length, 1);
- assert.equal(groups[1].removes[0].text,
- 'all work and no play make andybons a dull boy');
-
- assert.equal(groups[2].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[2].lines.length, context);
- groups[2].lines.forEach(function(l) {
- assert.equal(l.text, content[1].ab[0]);
- });
-
- assert.equal(groups[3].type, GrDiffGroup.Type.CONTEXT_CONTROL);
- assert.instanceOf(groups[3].lines[0].contextGroup, GrDiffGroup);
- assert.equal(groups[3].lines[0].contextGroup.lines.length, 30);
- groups[3].lines[0].contextGroup.lines.forEach(function(l) {
- assert.equal(l.text, content[1].ab[0]);
- });
-
- assert.equal(groups[4].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[4].lines.length, context);
- groups[4].lines.forEach(function(l) {
- assert.equal(l.text, content[1].ab[0]);
- });
-
- assert.equal(groups[5].type, GrDiffGroup.Type.DELTA);
- assert.equal(groups[5].lines.length, 1);
- assert.equal(groups[5].adds.length, 1);
- assert.equal(groups[5].adds[0].text, 'elgoog elgoog elgoog');
- });
-
- test('context control buttons', function() {
- var section = {};
- var line = {contextGroup: {lines: []}};
-
- // Create 10 lines.
- for (var i = 0; i < 10; i++) {
- line.contextGroup.lines.push('lorem upsum');
- }
-
- // Does not include +10 buttons when there are fewer than 11 lines.
- var td = builder._createContextControl(section, line);
- var buttons = td.querySelectorAll('gr-button.showContext');
-
- assert.equal(buttons.length, 1);
- assert.equal(buttons[0].textContent, 'Show 10 common lines');
-
- // Add another line.
- line.contextGroup.lines.push('lorem upsum');
-
- // Includes +10 buttons when there are at least 11 lines.
- td = builder._createContextControl(section, line);
- buttons = td.querySelectorAll('gr-button.showContext');
-
- assert.equal(buttons.length, 3);
- assert.equal(buttons[0].textContent, '+10↑');
- assert.equal(buttons[1].textContent, 'Show 11 common lines');
- assert.equal(buttons[2].textContent, '+10↓');
- });
-
- test('newlines', function() {
- var text = 'abcdef';
- assert.equal(builder._addNewlines(text, text), text);
- text = 'a'.repeat(20);
- assert.equal(builder._addNewlines(text, text),
- 'a'.repeat(10) +
- GrDiffBuilder.LINE_FEED_HTML +
- 'a'.repeat(10));
-
- text = '<span class="thumbsup">👍</span>';
- var html = '<span class="thumbsup">👍</span>';
- assert.equal(builder._addNewlines(text, html),
- '<span clas' +
- GrDiffBuilder.LINE_FEED_HTML +
- 's="thumbsu' +
- GrDiffBuilder.LINE_FEED_HTML +
- 'p">👍</spa' +
- GrDiffBuilder.LINE_FEED_HTML +
- 'n>');
-
- text = '01234\t56789';
- assert.equal(builder._addNewlines(text, text),
- '01234\t5' +
- GrDiffBuilder.LINE_FEED_HTML +
- '6789');
- });
-
- test('text length with tabs', function() {
- assert.equal(builder._textLength('12345', 4), 5);
- assert.equal(builder._textLength('\t\t12', 4), 10);
- });
-
- test('tab wrapper insertion', function() {
- var html = 'abc\tdef';
- var wrapper = builder._getTabWrapper(
- builder._prefs.tab_size,
- builder._prefs.show_tabs);
- assert.ok(wrapper);
- assert.isAbove(wrapper.length, 0);
- assert.equal(builder._addTabWrappers(html), 'abc' + wrapper + 'def');
- assert.throws(builder._getTabWrapper.bind(
- builder,
- '"><img src="/" onerror="alert(1);"><span class="',
- true));
- });
-
- test('comments', function() {
- var line = new GrDiffLine(GrDiffLine.Type.BOTH);
- line.beforeNumber = 3;
- line.afterNumber = 5;
-
- var comments = {left: [], right: []};
- assert.deepEqual(builder._getCommentsForLine(comments, line), []);
- assert.deepEqual(builder._getCommentsForLine(comments, line,
- GrDiffBuilder.Side.LEFT), []);
- assert.deepEqual(builder._getCommentsForLine(comments, line,
- GrDiffBuilder.Side.RIGHT), []);
-
- comments = {
- left: [
- {id: 'l3', line: 3},
- {id: 'l5', line: 5},
- ],
- right: [
- {id: 'r3', line: 3},
- {id: 'r5', line: 5},
- ],
- };
- assert.deepEqual(builder._getCommentsForLine(comments, line),
- [{id: 'l3', line: 3}, {id: 'r5', line: 5}]);
- assert.deepEqual(builder._getCommentsForLine(comments, line,
- GrDiffBuilder.Side.LEFT), [{id: 'l3', line: 3}]);
- assert.deepEqual(builder._getCommentsForLine(comments, line,
- GrDiffBuilder.Side.RIGHT), [{id: 'r5', line: 5}]);
- });
-
- test('comment thread creation', function() {
- builder._comments = {
- meta: {
- changeNum: '42',
- patchRange: {
- basePatchNum: 'PARENT',
- patchNum: '3',
- },
- path: '/path/to/foo',
- projectConfig: {foo: 'bar'},
- },
- left: [
- {id: 'l3', line: 3},
- {id: 'l5', line: 5},
- ],
- right: [
- {id: 'r5', line: 5},
- ],
- };
-
- function checkThreadProps(threadEl, patchNum, side, comments) {
- assert.equal(threadEl.changeNum, '42');
- assert.equal(threadEl.patchNum, patchNum);
- assert.equal(threadEl.path, '/path/to/foo');
- assert.equal(threadEl.side, side);
- assert.deepEqual(threadEl.projectConfig, {foo: 'bar'});
- assert.deepEqual(threadEl.comments, comments);
- }
-
- var line = new GrDiffLine(GrDiffLine.Type.BOTH);
- line.beforeNumber = 5;
- line.afterNumber = 5;
- var threadEl = builder._commentThreadForLine(line);
- checkThreadProps(threadEl, '3', 'REVISION',
- [{id: 'l5', line: 5}, {id: 'r5', line: 5}]);
-
- threadEl = builder._commentThreadForLine(line, GrDiffBuilder.Side.RIGHT);
- checkThreadProps(threadEl, '3', 'REVISION', [{id: 'r5', line: 5}]);
-
- threadEl = builder._commentThreadForLine(line, GrDiffBuilder.Side.LEFT);
- checkThreadProps(threadEl, '3', 'PARENT', [{id: 'l5', line: 5}]);
-
- builder._comments.meta.patchRange.basePatchNum = '1';
-
- threadEl = builder._commentThreadForLine(line);
- checkThreadProps(threadEl, '3', 'REVISION',
- [{id: 'l5', line: 5}, {id: 'r5', line: 5}]);
-
- threadEl = builder._commentThreadForLine(line, GrDiffBuilder.Side.LEFT);
- checkThreadProps(threadEl, '1', 'REVISION', [{id: 'l5', line: 5}]);
-
- threadEl = builder._commentThreadForLine(line, GrDiffBuilder.Side.RIGHT);
- checkThreadProps(threadEl, '3', 'REVISION', [{id: 'r5', line: 5}]);
-
- builder._comments.meta.patchRange.basePatchNum = 'PARENT';
-
- line = new GrDiffLine(GrDiffLine.Type.REMOVE);
- line.beforeNumber = 5;
- line.afterNumber = 5;
- threadEl = builder._commentThreadForLine(line);
- checkThreadProps(threadEl, '3', 'PARENT',
- [{id: 'l5', line: 5}, {id: 'r5', line: 5}]);
-
- line = new GrDiffLine(GrDiffLine.Type.ADD);
- line.beforeNumber = 3;
- line.afterNumber = 5;
- threadEl = builder._commentThreadForLine(line);
- checkThreadProps(threadEl, '3', 'REVISION',
- [{id: 'l3', line: 3}, {id: 'r5', line: 5}]);
- });
-
- test('break up common diff chunks', function() {
- builder._commentLocations = {
- left: {1: true},
- right: {10: true},
- };
- var lineNums = {
- left: 0,
- right: 0,
- };
- var content = [
- {
- ab: [
- 'Copyright (C) 2015 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.',
- ]
- }
- ];
- var result = builder._splitCommonGroupsWithComments(content, lineNums);
- assert.deepEqual(result, [
- {
- ab: ['Copyright (C) 2015 The Android Open Source Project'],
- },
- {
- ab: [
- '',
- '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, ',
- ]
- },
- {
- ab: ['software distributed under the License is distributed on an '],
- },
- {
- ab: [
- '"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.',
- ]
- }
- ]);
- });
-
- test('intraline normalization', function() {
- // The content and highlights are in the format returned by the Gerrit
- // REST API.
- var content = [
- ' <section class="summary">',
- ' <gr-linked-text content="' +
- '[[_computeCurrentRevisionMessage(change)]]"></gr-linked-text>',
- ' </section>',
- ];
- var highlights = [
- [31, 34], [42, 26]
- ];
- var results = GrDiffBuilder.prototype._normalizeIntralineHighlights(
- content, highlights);
- assert.deepEqual(results, [
- {
- contentIndex: 0,
- startIndex: 31,
- },
- {
- contentIndex: 1,
- startIndex: 0,
- endIndex: 33,
- },
- {
- contentIndex: 1,
- startIndex: 75,
- },
- {
- contentIndex: 2,
- startIndex: 0,
- endIndex: 6,
- }
- ]);
-
- content = [
- ' this._path = value.path;',
- '',
- ' // When navigating away from the page, there is a possibility that the',
- ' // patch number is no longer a part of the URL (say when navigating to',
- ' // the top-level change info view) and therefore undefined in `params`.',
- ' if (!this._patchRange.patchNum) {',
- ];
- highlights = [
- [14, 17],
- [11, 70],
- [12, 67],
- [12, 67],
- [14, 29],
- ];
- results = GrDiffBuilder.prototype._normalizeIntralineHighlights(content,
- highlights);
- assert.deepEqual(results, [
- {
- contentIndex: 0,
- startIndex: 14,
- endIndex: 31,
- },
- {
- contentIndex: 2,
- startIndex: 8,
- endIndex: 78,
- },
- {
- contentIndex: 3,
- startIndex: 11,
- endIndex: 78,
- },
- {
- contentIndex: 4,
- startIndex: 11,
- endIndex: 78,
- },
- {
- contentIndex: 5,
- startIndex: 12,
- endIndex: 41,
- }
- ]);
- });
-
- suite('rendering', function() {
- var content;
- var outputEl;
-
- setup(function() {
- var prefs = {
- line_length: 10,
- show_tabs: true,
- tab_size: 4,
- context: -1
- };
- content = [
- {ab: []},
- {a: ['all work and no play make andybons a dull boy']},
- {ab: []},
- {b: ['elgoog elgoog elgoog']},
- {ab: []},
- ];
- outputEl = document.createElement('out');
- builder =
- new GrDiffBuilder(
- {content: content}, {left: [], right: []}, prefs, outputEl);
- builder.buildSectionElement = function(group) {
- var section = document.createElement('stub');
- section.textContent = group.lines.reduce(function(acc, line) {
- return acc + line.text;
- }, '');
- return section;
- };
- builder.emitDiff();
- });
-
- test('renderSection', function() {
- var section = outputEl.querySelector('stub:nth-of-type(2)');
- var prevInnerHTML = section.innerHTML;
- section.innerHTML = 'wiped';
- builder.renderSection(section);
- section = outputEl.querySelector('stub:nth-of-type(2)');
- assert.equal(section.innerHTML, prevInnerHTML);
- });
-
- test('getSectionsByLineRange', function() {
- var section = outputEl.querySelector('stub:nth-of-type(2)');
- var sections = builder.getSectionsByLineRange(1, 1, 'left');
- assert.equal(sections.length, 1);
- assert.strictEqual(sections[0], section);
- });
- });
- });
-</script>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
index 1913270..cfe5d66 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
@@ -18,6 +18,7 @@
<link rel="import" href="../../shared/gr-button/gr-button.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../gr-diff-comment-thread/gr-diff-comment-thread.html">
+<link rel="import" href="../gr-diff-builder/gr-diff-builder.html">
<dom-module id="gr-diff">
<template>
@@ -153,15 +154,18 @@
on-tap="_handleTap"
on-mousedown="_handleMouseDown"
on-copy="_handleCopy">
- <table id="diffTable"></table>
+ <gr-diff-builder
+ id="diffBuilder"
+ view-mode="[[viewMode]]"
+ is-image-diff="[[isImageDiff]]"
+ base-image="[[_baseImage]]"
+ revision-image="[[_revisionImage]]">
+ <table id="diffTable"></table>
+ </gr-diff-builder>
</div>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="gr-diff-line.js"></script>
<script src="gr-diff-group.js"></script>
- <script src="gr-diff-builder.js"></script>
- <script src="gr-diff-builder-side-by-side.js"></script>
- <script src="gr-diff-builder-unified.js"></script>
- <script src="gr-diff-builder-image.js"></script>
<script src="gr-diff.js"></script>
</dom-module>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
index 0056808..ea64581 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
@@ -27,12 +27,6 @@
Polymer({
is: 'gr-diff',
- /**
- * Fired when the diff is rendered.
- *
- * @event render
- */
-
properties: {
changeNum: String,
patchRange: Object,
@@ -59,7 +53,6 @@
value: DiffViewMode.SIDE_BY_SIDE,
},
_diff: Object,
- _diffBuilder: Object,
_selectionSide: {
type: String,
observer: '_selectionSideChanged',
@@ -195,7 +188,7 @@
var el = Polymer.dom(e).rootTarget;
if (el.classList.contains('showContext')) {
- this._showContext(e.detail.groups, e.detail.section);
+ this.$.diffBuilder.showContext(e.detail.groups, e.detail.section);
} else if (el.classList.contains('lineNum')) {
this.addDraftAtLine(el);
}
@@ -223,8 +216,8 @@
patchNum = this.patchRange.basePatchNum;
}
}
- threadEl = this._builder.createCommentThread(this.changeNum, patchNum,
- this.path, side, this.projectConfig);
+ threadEl = this.$.diffBuilder.createCommentThread(
+ this.changeNum, patchNum, this.path, side, this.projectConfig);
contentEl.appendChild(threadEl);
}
threadEl.addDraft(opt_lineNum);
@@ -363,25 +356,6 @@
return text;
},
- _showContext: function(newGroups, sectionEl) {
- var groups = this._builder._groups;
- // TODO(viktard): Polyfill findIndex for IE10.
- var contextIndex = groups.findIndex(function(group) {
- return group.element == sectionEl;
- });
-
- groups.splice.apply(groups, [contextIndex, 1].concat(newGroups));
-
- newGroups.forEach(function(newGroup) {
- this._builder.emitGroup(newGroup, sectionEl);
- }.bind(this));
- sectionEl.parentNode.removeChild(sectionEl);
-
- this.async(function() {
- this.fire('render', null, {bubbles: false});
- }.bind(this), 1);
- },
-
_prefsChanged: function(prefsChangeRecord) {
var prefs = prefsChangeRecord.base;
this.customStyle['--content-width'] = prefs.line_length + 'ch';
@@ -393,17 +367,7 @@
},
_render: function() {
- this._builder =
- this._getDiffBuilder(this._diff, this._comments, this.prefs);
- this._renderDiff();
- },
-
- _renderDiff: function() {
- this._clearDiffContent();
- this._builder.emitDiff();
- this.async(function() {
- this.fire('render', null, {bubbles: false});
- }, 1);
+ this.$.diffBuilder.render(this._diff, this._comments, this.prefs);
},
_clearDiffContent: function() {
@@ -508,19 +472,6 @@
this.changeNum, this._diff, this.patchRange);
},
- _getDiffBuilder: function(diff, comments, prefs) {
- if (this.isImageDiff) {
- return new GrDiffBuilderImage(diff, comments, prefs, this.$.diffTable,
- this._baseImage, this._revisionImage);
- } else if (this.viewMode === DiffViewMode.SIDE_BY_SIDE) {
- return new GrDiffBuilderSideBySide(diff, comments, prefs,
- this.$.diffTable);
- } else if (this.viewMode === DiffViewMode.UNIFIED) {
- return new GrDiffBuilderUnified(diff, comments, prefs,
- this.$.diffTable);
- }
- throw Error('Unsupported diff view mode: ' + this.viewMode);
- },
_projectConfigChanged: function(projectConfig) {
var threadEls = this._getCommentThreads();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
index aec32b6..613c7fa 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
@@ -226,8 +226,7 @@
var rendered = function() {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
- assert.instanceOf(element._getDiffBuilder(element._diff,
- element._comments, element.prefs), GrDiffBuilderImage);
+ assert.instanceOf(element.$.diffBuilder._builder, GrDiffBuilderImage);
// Left image rendered with the parent commit's version of the file.
var leftInmage = element.$.diffTable.querySelector('td.left img');
@@ -397,30 +396,5 @@
});
});
});
-
- suite('renderDiff', function() {
- setup(function(done) {
- sinon.stub(element, 'fire');
- element._builder = {
- emitDiff: sinon.stub(),
- };
- element._renderDiff();
- flush(function() {
- done();
- });
- });
-
- teardown(function() {
- element.fire.restore();
- });
-
- test('fires render', function() {
- assert(element.fire.calledWithExactly(
- 'render', null, {bubbles: false}));
- });
- test('calls emitDiff on builder', function() {
- assert(element._builder.emitDiff.calledOnce);
- });
- });
});
</script>