Merge "Move AccountState::fromAccountConfig to AccountsNoteDbImpl."
diff --git a/polygerrit-ui/app/api/diff.ts b/polygerrit-ui/app/api/diff.ts
index b968553..9963fdc 100644
--- a/polygerrit-ui/app/api/diff.ts
+++ b/polygerrit-ui/app/api/diff.ts
@@ -251,6 +251,10 @@
* property on <gr-diff>. TODO: Migrate usages to RenderPreferences.
*/
view_mode?: DiffViewMode;
+ can_comment?: boolean;
+ show_newline_warning_left?: boolean;
+ show_newline_warning_right?: boolean;
+ use_new_image_diff_ui?: boolean;
}
/**
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
index 1e1959d..914aa19 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
@@ -10,6 +10,7 @@
import {
anyLineTooLong,
getDiffLength,
+ isImageDiff,
SYNTAX_MAX_LINE_LENGTH,
} from '../../../utils/diff-util';
import {getAppContext} from '../../../services/app-context';
@@ -106,15 +107,6 @@
const EVENT_ZERO_REBASE = 'rebase-percent-zero';
const EVENT_NONZERO_REBASE = 'rebase-percent-nonzero';
-function isImageDiff(diff?: DiffInfo) {
- if (!diff) return false;
-
- const isA = diff.meta_a && diff.meta_a.content_type.startsWith('image/');
- const isB = diff.meta_b && diff.meta_b.content_type.startsWith('image/');
-
- return !!(diff.binary && (isA || isB));
-}
-
// visible for testing
export interface LineInfo {
beforeNumber?: LineNumber;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.ts b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.ts
index 7774264..df9a634 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.ts
@@ -317,19 +317,16 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
- assertIsDefined(element.diffElement);
// Left image rendered with the parent commit's version of the file.
assertIsDefined(element.diffElement);
- assertIsDefined(element.diffElement.diffTable);
- const diffTable = element.diffElement.diffTable;
- const leftImage = queryAndAssert(diffTable, 'td.left img');
- const leftLabel = queryAndAssert(diffTable, 'td.left label');
+ const leftImage = queryAndAssert(element.diffElement, 'td.left img');
+ const leftLabel = queryAndAssert(element.diffElement, 'td.left label');
const leftLabelContent = leftLabel.querySelector('.label');
const leftLabelName = leftLabel.querySelector('.name');
- const rightImage = queryAndAssert(diffTable, 'td.right img');
- const rightLabel = queryAndAssert(diffTable, 'td.right label');
+ const rightImage = queryAndAssert(element.diffElement, 'td.right img');
+ const rightLabel = queryAndAssert(element.diffElement, 'td.right label');
const rightLabelContent = rightLabel.querySelector('.label');
const rightLabelName = rightLabel.querySelector('.name');
@@ -391,15 +388,13 @@
assertIsDefined(element.diffElement);
// Left image rendered with the parent commit's version of the file.
- assertIsDefined(element.diffElement.diffTable);
- const diffTable = element.diffElement.diffTable;
- const leftImage = queryAndAssert(diffTable, 'td.left img');
- const leftLabel = queryAndAssert(diffTable, 'td.left label');
+ const leftImage = queryAndAssert(element.diffElement, 'td.left img');
+ const leftLabel = queryAndAssert(element.diffElement, 'td.left label');
const leftLabelContent = leftLabel.querySelector('.label');
const leftLabelName = leftLabel.querySelector('.name');
- const rightImage = queryAndAssert(diffTable, 'td.right img');
- const rightLabel = queryAndAssert(diffTable, 'td.right label');
+ const rightImage = queryAndAssert(element.diffElement, 'td.right img');
+ const rightLabel = queryAndAssert(element.diffElement, 'td.right label');
const rightLabelContent = rightLabel.querySelector('.label');
const rightLabelName = rightLabel.querySelector('.name');
@@ -456,11 +451,8 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assertIsDefined(element.diffElement);
- assertIsDefined(element.diffElement.diffTable);
- const diffTable = element.diffElement.diffTable;
-
- const leftImage = query(diffTable, 'td.left img');
- const rightImage = queryAndAssert(diffTable, 'td.right img');
+ const leftImage = query(element.diffElement, 'td.left img');
+ const rightImage = queryAndAssert(element.diffElement, 'td.right img');
assert.isNotOk(leftImage);
assert.isOk(rightImage);
@@ -500,11 +492,9 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assertIsDefined(element.diffElement);
- assertIsDefined(element.diffElement.diffTable);
- const diffTable = element.diffElement.diffTable;
- const leftImage = queryAndAssert(diffTable, 'td.left img');
- const rightImage = query(diffTable, 'td.right img');
+ const leftImage = queryAndAssert(element.diffElement, 'td.left img');
+ const rightImage = query(element.diffElement, 'td.right img');
assert.isOk(leftImage);
assert.isNotOk(rightImage);
@@ -549,10 +539,7 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assertIsDefined(element.diffElement);
- assertIsDefined(element.diffElement.diffTable);
- const diffTable = element.diffElement.diffTable;
-
- const leftImage = query(diffTable, 'td.left img');
+ const leftImage = query(element.diffElement, 'td.left img');
assert.isNotOk(leftImage);
});
});
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts
index aad7928..325f902 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts
@@ -39,16 +39,16 @@
@property({type: Object})
group?: GrDiffGroup;
- @property({type: Object})
+ @state()
diff?: DiffInfo;
- @property({type: Object})
+ @state()
renderPrefs?: RenderPreferences;
- @property({type: Object})
+ @state()
diffPrefs?: DiffPreferencesInfo;
- @property({type: Object})
+ @state()
layers: DiffLayer[] = [];
@state()
@@ -78,6 +78,26 @@
() => this.getDiffModel().viewMode$,
viewMode => (this.viewMode = viewMode)
);
+ subscribe(
+ this,
+ () => this.getDiffModel().diff$,
+ diff => (this.diff = diff)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().renderPrefs$,
+ renderPrefs => (this.renderPrefs = renderPrefs)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().diffPrefs$,
+ diffPrefs => (this.diffPrefs = diffPrefs)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().layers$,
+ layers => (this.layers = layers)
+ );
}
/**
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts
index 9478d13..01661fe 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts
@@ -11,14 +11,11 @@
getStringLength,
} from '../gr-diff-highlight/gr-annotation';
import {debounce, DelayedTask} from '../../../utils/async-util';
-
import {getLineElByChild, getSideByLineEl} from '../gr-diff/gr-diff-utils';
-
import {
getLineNumberByChild,
lineNumberToNumber,
} from '../gr-diff/gr-diff-utils';
-import {GrDiff} from '../gr-diff/gr-diff';
const tokenMatcher = new RegExp(/[\w]+/g);
@@ -120,18 +117,6 @@
this.getTokenQueryContainer = getTokenQueryContainer;
}
- static createTokenHighlightContainer(
- container: HTMLElement,
- getGrDiff: () => GrDiff,
- tokenHighlightListener?: TokenHighlightListener
- ): TokenHighlightLayer {
- return new TokenHighlightLayer(
- container,
- tokenHighlightListener,
- () => getGrDiff().diffTable!
- );
- }
-
annotate(el: HTMLElement, _1: HTMLElement, _2: GrDiffLine, _3: Side): void {
const text = el.textContent;
if (!text) return;
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor_test.ts b/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor_test.ts
index e5aaafd..d8406c0 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor_test.ts
@@ -24,17 +24,12 @@
suite('gr-diff-cursor tests', () => {
let cursor: GrDiffCursor;
let diffElement: GrDiff;
- let diff: DiffInfo;
setup(async () => {
diffElement = await fixture(html`<gr-diff></gr-diff>`);
cursor = new GrDiffCursor();
-
- // Register the diff with the cursor.
cursor.replaceDiffs([diffElement]);
- diffElement.loggedIn = false;
- diffElement.path = 'some/path.ts';
const promise = mockPromise();
const setupDone = () => {
cursor._updateStops();
@@ -44,9 +39,11 @@
};
diffElement.addEventListener('render', setupDone);
- diff = createDiff();
- diffElement.prefs = createDefaultDiffPrefs();
- diffElement.diff = diff;
+ diffElement.diffModel.updateState({
+ diff: createDiff(),
+ path: 'some/path.ts',
+ diffPrefs: createDefaultDiffPrefs(),
+ });
await promise;
});
@@ -98,10 +95,13 @@
],
};
- diffElement.diff = diff;
- // The file comment button, if present, is a cursor stop. Ensure
- // moveToFirstChunk() works correctly even if the button is not shown.
- diffElement.prefs!.show_file_comment_button = false;
+ diffElement.diffModel.updateState({
+ diff,
+ // The file comment button, if present, is a cursor stop. Ensure
+ // moveToFirstChunk() works correctly even if the button is not shown.
+ diffPrefs: {...createDefaultDiffPrefs(), show_file_comment_button: false},
+ });
+ await waitForEventOnce(diffElement, 'render');
await waitForEventOnce(diffElement, 'render');
cursor._updateStops();
@@ -161,8 +161,9 @@
{b: ['new line 3']},
],
};
+ diffElement.diffModel.updateState({diff});
- diffElement.diff = diff;
+ await waitForEventOnce(diffElement, 'render');
await waitForEventOnce(diffElement, 'render');
cursor._updateStops();
@@ -228,7 +229,9 @@
suite('unified diff', () => {
setup(async () => {
- diffElement.viewMode = DiffViewMode.UNIFIED;
+ diffElement.diffModel.updateState({
+ renderPrefs: {view_mode: DiffViewMode.UNIFIED},
+ });
await diffElement.updateComplete;
cursor.reInitCursor();
});
@@ -254,9 +257,9 @@
});
test('cursor side functionality', () => {
- // The side only applies to side-by-side mode, which should be the default
- // mode.
- assert.equal(diffElement.viewMode, 'SIDE_BY_SIDE');
+ diffElement.diffModel.updateState({
+ renderPrefs: {view_mode: DiffViewMode.SIDE_BY_SIDE},
+ });
const rows = [
...queryAll(diffElement, '.section tr.diff-row'),
@@ -312,143 +315,6 @@
assert.equal(cursor.side, Side.LEFT);
});
- suite('moved chunks without line range)', () => {
- setup(async () => {
- const promise = mockPromise();
- const renderHandler = function () {
- diffElement.removeEventListener('render', renderHandler);
- cursor.reInitCursor();
- promise.resolve();
- };
- diffElement.addEventListener('render', renderHandler);
- diffElement.diff = {
- ...diff,
- content: [
- {
- ab: ['Lorem ipsum dolor sit amet, suspendisse inceptos vehicula, '],
- },
- {
- b: [
- 'Nullam neque, ligula ac, id blandit.',
- 'Sagittis tincidunt torquent, tempor nunc amet.',
- 'At rhoncus id.',
- ],
- move_details: {changed: false},
- },
- {
- ab: ['Sem nascetur, erat ut, non in.'],
- },
- {
- a: [
- 'Nullam neque, ligula ac, id blandit.',
- 'Sagittis tincidunt torquent, tempor nunc amet.',
- 'At rhoncus id.',
- ],
- move_details: {changed: false},
- },
- {
- ab: ['Arcu eget, rhoncus amet cursus, ipsum elementum.'],
- },
- ],
- };
- await promise;
- });
-
- test('renders moveControls with simple descriptions', () => {
- const [movedIn, movedOut] = [
- ...queryAll<HTMLElement>(diffElement, '.dueToMove tr.moveControls'),
- ];
- assert.include(movedIn.innerText, 'Moved in');
- assert.include(movedOut.innerText, 'Moved out');
- });
- });
-
- suite('moved chunks (moveDetails)', () => {
- setup(async () => {
- const promise = mockPromise();
- const renderHandler = function () {
- diffElement.removeEventListener('render', renderHandler);
- cursor.reInitCursor();
- promise.resolve();
- };
- diffElement.addEventListener('render', renderHandler);
- diffElement.diff = {
- ...diff,
- content: [
- {
- ab: ['Lorem ipsum dolor sit amet, suspendisse inceptos vehicula, '],
- },
- {
- b: [
- 'Nullam neque, ligula ac, id blandit.',
- 'Sagittis tincidunt torquent, tempor nunc amet.',
- 'At rhoncus id.',
- ],
- move_details: {changed: false, range: {start: 4, end: 6}},
- },
- {
- ab: ['Sem nascetur, erat ut, non in.'],
- },
- {
- a: [
- 'Nullam neque, ligula ac, id blandit.',
- 'Sagittis tincidunt torquent, tempor nunc amet.',
- 'At rhoncus id.',
- ],
- move_details: {changed: false, range: {start: 2, end: 4}},
- },
- {
- ab: ['Arcu eget, rhoncus amet cursus, ipsum elementum.'],
- },
- ],
- };
- await promise;
- });
-
- test('renders moveControls with simple descriptions', () => {
- const [movedIn, movedOut] = [
- ...queryAll<HTMLElement>(diffElement, '.dueToMove tr.moveControls'),
- ];
- assert.include(movedIn.innerText, 'Moved from lines 4 - 6');
- assert.include(movedOut.innerText, 'Moved to lines 2 - 4');
- });
-
- test('startLineAnchor of movedIn chunk fires events', async () => {
- const [movedIn] = [...queryAll(diffElement, '.dueToMove .moveControls')];
- const [startLineAnchor] = movedIn.querySelectorAll('a');
-
- const promise = mockPromise();
- const onMovedLinkClicked = (e: CustomEvent) => {
- assert.deepEqual(e.detail, {lineNum: 4, side: Side.LEFT});
- promise.resolve();
- };
- assert.equal(startLineAnchor.textContent, '4');
- startLineAnchor.addEventListener(
- 'moved-link-clicked',
- onMovedLinkClicked
- );
- startLineAnchor.click();
- await promise;
- });
-
- test('endLineAnchor of movedOut fires events', async () => {
- const [, movedOut] = [
- ...queryAll(diffElement, '.dueToMove .moveControls'),
- ];
- const [, endLineAnchor] = movedOut.querySelectorAll('a');
-
- const promise = mockPromise();
- const onMovedLinkClicked = (e: CustomEvent) => {
- assert.deepEqual(e.detail, {lineNum: 4, side: Side.RIGHT});
- promise.resolve();
- };
- assert.equal(endLineAnchor.textContent, '4');
- endLineAnchor.addEventListener('moved-link-clicked', onMovedLinkClicked);
- endLineAnchor.click();
- await promise;
- });
- });
-
test('initialLineNumber not provided', async () => {
let scrollBehaviorDuringMove;
const moveToNumStub = sinon.stub(cursor, 'moveToLineNumber');
@@ -460,8 +326,8 @@
cursor.dispose();
const diff = createDiff();
diff.content.push({ab: ['one more line']});
- diffElement.diff = diff;
- diffElement.prefs = createDefaultDiffPrefs();
+ diffElement.diffModel.updateState({diff});
+
await Promise.all([
diffElement.updateComplete,
waitForEventOnce(diffElement, 'render'),
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-model/gr-diff-model.ts b/polygerrit-ui/app/embed/diff/gr-diff-model/gr-diff-model.ts
index 8dae154..b8539ef 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-model/gr-diff-model.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-model/gr-diff-model.ts
@@ -7,7 +7,9 @@
import {debounceTime, filter, switchMap, withLatestFrom} from 'rxjs/operators';
import {
DiffInfo,
+ DiffLayer,
DiffPreferencesInfo,
+ DiffResponsiveMode,
DiffViewMode,
DisplayLine,
RenderPreferences,
@@ -22,6 +24,7 @@
computeContext,
computeKeyLocations,
computeLineLength,
+ getResponsiveMode,
} from '../gr-diff/gr-diff-utils';
import {createDefaultDiffPrefs} from '../../../constants/constants';
import {
@@ -30,9 +33,13 @@
} from '../gr-diff-processor/gr-diff-processor';
import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
import {assert} from '../../../utils/common-util';
+import {isImageDiff} from '../../../utils/diff-util';
+import {ImageInfo} from '../../../types/common';
export interface DiffState {
diff?: DiffInfo;
+ baseImage?: ImageInfo;
+ revisionImage?: ImageInfo;
path?: string;
renderPrefs: RenderPreferences;
diffPrefs: DiffPreferencesInfo;
@@ -42,6 +49,8 @@
/** how much context to show for large files */
showFullContext: FullContext;
isImageDiff: boolean;
+ errorMessage?: string;
+ layers: DiffLayer[];
}
export const diffModelToken = define<DiffModel>('diff-model');
@@ -52,6 +61,16 @@
diffState => diffState.diff!
);
+ readonly baseImage$: Observable<ImageInfo | undefined> = select(
+ this.state$,
+ diffState => diffState.baseImage
+ );
+
+ readonly revisionImage$: Observable<ImageInfo | undefined> = select(
+ this.state$,
+ diffState => diffState.revisionImage
+ );
+
readonly path$: Observable<string | undefined> = select(
this.state$,
diffState => diffState.path
@@ -72,6 +91,16 @@
diffState => diffState.diffPrefs
);
+ readonly layers$: Observable<DiffLayer[]> = select(
+ this.state$,
+ diffState => diffState.layers
+ );
+
+ readonly showFullContext$: Observable<FullContext> = select(
+ this.state$,
+ diffState => diffState.showFullContext
+ );
+
readonly context$: Observable<number> = select(this.state$, state =>
computeContext(
state.diffPrefs.context,
@@ -80,9 +109,14 @@
)
);
- readonly isImageDiff$: Observable<boolean> = select(
+ readonly responsiveMode$: Observable<DiffResponsiveMode> = select(
this.state$,
- diffState => diffState.isImageDiff
+ diffState => getResponsiveMode(diffState.diffPrefs, diffState.renderPrefs)
+ );
+
+ readonly errorMessage$: Observable<string | undefined> = select(
+ this.state$,
+ diffState => diffState.errorMessage
);
readonly groups$: Observable<GrDiffGroup[]> = select(
@@ -90,6 +124,12 @@
diffState => diffState.groups ?? []
);
+ readonly loading$: Observable<boolean> = select(
+ this.state$,
+ diffState =>
+ (diffState.groups ?? []).length === 0 || diffState.diff === undefined
+ );
+
readonly lineLength$: Observable<number> = select(this.state$, state =>
computeLineLength(state.diffPrefs, state.path)
);
@@ -108,34 +148,28 @@
groups: [],
showFullContext: FullContext.UNDECIDED,
isImageDiff: false,
+ layers: [],
});
this.subscriptions = [this.processDiff()];
}
processDiff() {
- return combineLatest([
- this.diff$,
- this.context$,
- this.renderPrefs$,
- this.isImageDiff$,
- ])
+ return combineLatest([this.diff$, this.context$, this.renderPrefs$])
.pipe(
withLatestFrom(this.keyLocations$),
debounceTime(1),
- switchMap(
- ([[diff, context, renderPrefs, isImageDiff], keyLocations]) => {
- const options: ProcessingOptions = {
- context,
- keyLocations,
- isBinary: !!(isImageDiff || diff.binary),
- };
- if (renderPrefs?.num_lines_rendered_at_once) {
- options.asyncThreshold = renderPrefs.num_lines_rendered_at_once;
- }
- const processor = new GrDiffProcessor(options);
- return from(processor.process(diff.content));
+ switchMap(([[diff, context, renderPrefs], keyLocations]) => {
+ const options: ProcessingOptions = {
+ context,
+ keyLocations,
+ isBinary: !!(isImageDiff(diff) || diff.binary),
+ };
+ if (renderPrefs?.num_lines_rendered_at_once) {
+ options.asyncThreshold = renderPrefs.num_lines_rendered_at_once;
}
- )
+ const processor = new GrDiffProcessor(options);
+ return from(processor.process(diff.content));
+ })
)
.subscribe(groups => {
this.updateState({groups});
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element.ts
new file mode 100644
index 0000000..5061a8b
--- /dev/null
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element.ts
@@ -0,0 +1,424 @@
+/**
+ * @license
+ * Copyright 2023 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+import '../../../styles/shared-styles';
+import '../../../elements/shared/gr-button/gr-button';
+import '../../../elements/shared/gr-icon/gr-icon';
+import '../gr-diff-highlight/gr-diff-highlight';
+import '../gr-diff-selection/gr-diff-selection';
+import '../gr-syntax-themes/gr-syntax-theme';
+import '../gr-ranged-comment-themes/gr-ranged-comment-theme';
+import '../gr-ranged-comment-hint/gr-ranged-comment-hint';
+import '../gr-diff-builder/gr-diff-builder-image';
+import '../gr-diff-builder/gr-diff-section';
+import '../gr-diff-builder/gr-diff-row';
+import {
+ isResponsive,
+ isNewDiff,
+ FullContext,
+ diffClasses,
+ FULL_CONTEXT,
+} from './gr-diff-utils';
+import {ImageInfo} from '../../../types/common';
+import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
+import {
+ DiffViewMode,
+ Side,
+ createDefaultDiffPrefs,
+} from '../../../constants/constants';
+import {fire} from '../../../utils/event-util';
+import {RenderPreferences, LOST, DiffResponsiveMode} from '../../../api/diff';
+import {query, queryAll, state} from 'lit/decorators.js';
+import {html, LitElement, nothing} from 'lit';
+import {when} from 'lit/directives/when.js';
+import {classMap} from 'lit/directives/class-map.js';
+import {expandFileMode} from '../../../utils/file-util';
+import {diffModelToken} from '../gr-diff-model/gr-diff-model';
+import {resolve} from '../../../models/dependency';
+import {getDiffLength, isImageDiff} from '../../../utils/diff-util';
+import {GrDiffGroup} from './gr-diff-group';
+import {subscribe} from '../../../elements/lit/subscription-controller';
+import {GrDiffSection} from '../gr-diff-builder/gr-diff-section';
+import {repeat} from 'lit/directives/repeat.js';
+
+const LARGE_DIFF_THRESHOLD_LINES = 10000;
+
+export class GrDiffElement extends LitElement {
+ @query('#diffTable')
+ diffTable?: HTMLTableElement;
+
+ @queryAll('gr-diff-section')
+ diffSections?: NodeListOf<GrDiffSection>;
+
+ @state() diff?: DiffInfo;
+
+ @state() baseImage?: ImageInfo;
+
+ @state() revisionImage?: ImageInfo;
+
+ @state() diffPrefs: DiffPreferencesInfo = createDefaultDiffPrefs();
+
+ @state() renderPrefs: RenderPreferences = {};
+
+ @state() viewMode = DiffViewMode.SIDE_BY_SIDE;
+
+ @state() groups: GrDiffGroup[] = [];
+
+ @state() showFullContext: FullContext = FullContext.UNDECIDED;
+
+ @state() errorMessage?: string;
+
+ @state() responsiveMode: DiffResponsiveMode = 'NONE';
+
+ @state() loading = true;
+
+ private getDiffModel = resolve(this, diffModelToken);
+
+ /**
+ * The browser API for handling selection does not (yet) work for selection
+ * across multiple shadow DOM elements. So we are rendering gr-diff components
+ * into the light DOM instead of the shadow DOM by overriding this method,
+ * which was the recommended workaround by the lit team.
+ * See also https://github.com/WICG/webcomponents/issues/79.
+ */
+ override createRenderRoot() {
+ return this;
+ }
+
+ constructor() {
+ super();
+ subscribe(
+ this,
+ () => this.getDiffModel().diff$,
+ diff => (this.diff = diff)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().baseImage$,
+ baseImage => (this.baseImage = baseImage)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().revisionImage$,
+ revisionImage => (this.revisionImage = revisionImage)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().diffPrefs$,
+ diffPrefs => (this.diffPrefs = diffPrefs)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().renderPrefs$,
+ renderPrefs => (this.renderPrefs = renderPrefs)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().viewMode$,
+ viewMode => (this.viewMode = viewMode)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().showFullContext$,
+ showFullContext => (this.showFullContext = showFullContext)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().errorMessage$,
+ errorMessage => (this.errorMessage = errorMessage)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().groups$,
+ groups => (this.groups = groups)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().loading$,
+ loading => (this.loading = loading)
+ );
+ subscribe(
+ this,
+ () => this.getDiffModel().responsiveMode$,
+ responsiveMode => (this.responsiveMode = responsiveMode)
+ );
+ }
+
+ protected override async getUpdateComplete(): Promise<boolean> {
+ const result = await super.getUpdateComplete();
+ const sections = [...(this.diffSections ?? [])];
+ await Promise.all(sections.map(section => section.updateComplete));
+ return result;
+ }
+
+ protected override updated() {
+ if (this.diffSections?.length) {
+ this.fireRenderContent();
+ }
+ }
+
+ private async fireRenderContent() {
+ await this.updateComplete;
+ // TODO: Retire one of these two events.
+ fire(this, 'render-content', {});
+ fire(this, 'render', {});
+ }
+
+ override render() {
+ fire(this.diffTable, 'render-start', {});
+ return html`
+ ${this.renderHeader()} ${this.renderContainer()}
+ ${this.renderNewlineWarning()} ${this.renderLoadingError()}
+ `;
+ }
+
+ private renderHeader() {
+ const diffheaderItems = this.computeDiffHeaderItems();
+ if (diffheaderItems.length === 0) return nothing;
+ return html`
+ <div id="diffHeader">
+ ${diffheaderItems.map(item => html`<div>${item}</div>`)}
+ </div>
+ `;
+ }
+
+ private renderContainer() {
+ const cssClasses = {
+ newDiff: true,
+ diffContainer: true,
+ unified: this.viewMode === DiffViewMode.UNIFIED,
+ sideBySide: this.viewMode === DiffViewMode.SIDE_BY_SIDE,
+ canComment: !!this.renderPrefs.can_comment,
+ };
+ const tableClasses = {
+ responsive: isResponsive(this.responsiveMode),
+ };
+ const isBinary = !!this.diff?.binary;
+ const imageDiff = isImageDiff(this.diff);
+ return html`
+ <div class=${classMap(cssClasses)}>
+ <table
+ id="diffTable"
+ class=${classMap(tableClasses)}
+ ?contenteditable=${this.isContentEditable}
+ >
+ ${this.renderColumns()}
+ ${when(!this.showWarning(), () =>
+ repeat(
+ this.groups,
+ group => group.id(),
+ group => this.renderSectionElement(group)
+ )
+ )}
+ ${when(isBinary, () =>
+ imageDiff ? this.renderImageDiff() : this.renderBinaryDiff()
+ )}
+ </table>
+ ${when(
+ this.showNoChangeMessage(),
+ () => html`
+ <div class="whitespace-change-only-message">
+ This file only contains whitespace changes. Modify the whitespace
+ setting to see the changes.
+ </div>
+ `
+ )}
+ ${when(this.showWarning(), () => this.renderSizeWarning())}
+ </div>
+ `;
+ }
+
+ private renderNewlineWarning() {
+ const newlineWarning = this.computeNewlineWarning();
+ if (!newlineWarning) return nothing;
+ return html`<div class="newlineWarning">${newlineWarning}</div>`;
+ }
+
+ private renderLoadingError() {
+ if (!this.errorMessage) return nothing;
+ return html`<div id="loadingError">${this.errorMessage}</div>`;
+ }
+
+ private renderSizeWarning() {
+ if (!this.showWarning()) return nothing;
+ // TODO: Update comment about 'Whole file' as it's not in settings.
+ return html`
+ <div id="sizeWarning">
+ <p>
+ Prevented render because "Whole file" is enabled and this diff is very
+ large (about ${getDiffLength(this.diff)} lines).
+ </p>
+ <gr-button @click=${this.collapseContext}>
+ Render with limited context
+ </gr-button>
+ <gr-button @click=${this.handleFullBypass}>
+ Render anyway (may be slow)
+ </gr-button>
+ </div>
+ `;
+ }
+
+ // Private but used in tests.
+ showNoChangeMessage() {
+ return (
+ !this.loading &&
+ this.diff &&
+ !this.diff.binary &&
+ this.diffPrefs.ignore_whitespace !== 'IGNORE_NONE' &&
+ getDiffLength(this.diff) === 0
+ );
+ }
+
+ private showWarning() {
+ return (
+ this.diffPrefs?.context === FULL_CONTEXT &&
+ this.showFullContext === FullContext.UNDECIDED &&
+ getDiffLength(this.diff) >= LARGE_DIFF_THRESHOLD_LINES
+ );
+ }
+
+ // Private but used in tests.
+ computeDiffHeaderItems() {
+ return (this.diff?.diff_header ?? [])
+ .filter(
+ item =>
+ !(
+ item.startsWith('diff --git ') ||
+ item.startsWith('index ') ||
+ item.startsWith('+++ ') ||
+ item.startsWith('--- ') ||
+ item === 'Binary files differ'
+ )
+ )
+ .map(expandFileMode);
+ }
+
+ private handleFullBypass() {
+ this.getDiffModel().updateState({showFullContext: FullContext.YES});
+ }
+
+ private collapseContext() {
+ this.getDiffModel().updateState({showFullContext: FullContext.NO});
+ }
+
+ private computeNewlineWarning(): string | undefined {
+ const messages = [];
+ if (this.renderPrefs.show_newline_warning_left) {
+ messages.push('No newline at end of left file.');
+ }
+ if (this.renderPrefs.show_newline_warning_right) {
+ messages.push('No newline at end of right file.');
+ }
+ if (!messages.length) {
+ return undefined;
+ }
+ return messages.join(' \u2014 '); // \u2014 - '—'
+ }
+
+ private renderImageDiff() {
+ return when(
+ this.renderPrefs.use_new_image_diff_ui,
+ () => this.renderImageDiffNew(),
+ () => this.renderImageDiffOld()
+ );
+ }
+
+ private renderImageDiffNew() {
+ const autoBlink = !!this.renderPrefs?.image_diff_prefs?.automatic_blink;
+ return html`
+ <gr-diff-image-new
+ .automaticBlink=${autoBlink}
+ .baseImage=${this.baseImage ?? undefined}
+ .revisionImage=${this.revisionImage ?? undefined}
+ ></gr-diff-image-new>
+ `;
+ }
+
+ private renderImageDiffOld() {
+ return html`
+ <gr-diff-image-old
+ .baseImage=${this.baseImage ?? undefined}
+ .revisionImage=${this.revisionImage ?? undefined}
+ ></gr-diff-image-old>
+ `;
+ }
+
+ public renderBinaryDiff() {
+ return html`
+ <tbody class="gr-diff binary-diff">
+ <tr class="gr-diff">
+ <td colspan="5" class="gr-diff">
+ <span>Difference in binary files</span>
+ </td>
+ </tr>
+ </tbody>
+ `;
+ }
+
+ renderSectionElement(group: GrDiffGroup) {
+ const leftClass = `left-${group.startLine(Side.LEFT)}`;
+ const rightClass = `right-${group.startLine(Side.RIGHT)}`;
+ if (this.diff?.binary && group.startLine(Side.LEFT) === LOST) {
+ return nothing;
+ }
+ return html`
+ <gr-diff-section
+ class="${leftClass} ${rightClass}"
+ .group=${group}
+ ></gr-diff-section>
+ `;
+ }
+
+ renderColumns() {
+ const lineNumberWidth = getLineNumberCellWidth(
+ this.diffPrefs ?? createDefaultDiffPrefs()
+ );
+ return html`
+ <colgroup>
+ <col class=${diffClasses('blame')}></col>
+ ${when(
+ (this.renderPrefs?.view_mode ?? this.viewMode) ===
+ DiffViewMode.UNIFIED,
+ () => html` ${this.renderUnifiedColumns(lineNumberWidth)} `,
+ () => html`
+ ${this.renderSideBySideColumns(Side.LEFT, lineNumberWidth)}
+ ${this.renderSideBySideColumns(Side.RIGHT, lineNumberWidth)}
+ `
+ )}
+ </colgroup>
+ `;
+ }
+
+ private renderUnifiedColumns(lineNumberWidth: number) {
+ return html`
+ <col class=${diffClasses()} width=${lineNumberWidth}></col>
+ <col class=${diffClasses()} width=${lineNumberWidth}></col>
+ <col class=${diffClasses()}></col>
+ `;
+ }
+
+ private renderSideBySideColumns(side: Side, lineNumberWidth: number) {
+ return html`
+ <col class=${diffClasses(side)} width=${lineNumberWidth}></col>
+ <col class=${diffClasses(side, 'sign')}></col>
+ <col class=${diffClasses(side)}></col>
+ `;
+ }
+}
+
+function getLineNumberCellWidth(prefs: DiffPreferencesInfo) {
+ return prefs.font_size * 4;
+}
+
+// TODO(newdiff-cleanup): Remove once newdiff migration is completed.
+if (isNewDiff()) {
+ customElements.define('gr-diff-element', GrDiffElement);
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'gr-diff-element': GrDiffElement;
+ }
+}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element_test.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element_test.ts
new file mode 100644
index 0000000..6f476e5
--- /dev/null
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-element_test.ts
@@ -0,0 +1,3665 @@
+/**
+ * @license
+ * Copyright 2023 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+import '../../../test/common-test-setup';
+import {createDiff, createEmptyDiff} from '../../../test/test-data-generators';
+import './gr-diff-element';
+import {GrDiffElement} from './gr-diff-element';
+import {querySelectorAll} from '../../../utils/dom-util';
+import '@polymer/paper-button/paper-button';
+import {
+ DiffContent,
+ DiffInfo,
+ DiffPreferencesInfo,
+ DiffViewMode,
+ IgnoreWhitespaceType,
+} from '../../../api/diff';
+import {query, queryAndAssert, waitUntil} from '../../../test/test-utils';
+import {waitForEventOnce} from '../../../utils/event-util';
+import {ImageInfo} from '../../../types/common';
+import {fixture, html, assert} from '@open-wc/testing';
+import {createDefaultDiffPrefs} from '../../../constants/constants';
+import {DiffModel, diffModelToken} from '../gr-diff-model/gr-diff-model';
+import {wrapInProvider} from '../../../models/di-provider-element';
+
+const DEFAULT_PREFS = createDefaultDiffPrefs();
+
+suite('gr-diff-element tests', () => {
+ let element: GrDiffElement;
+ let model: DiffModel;
+
+ const MINIMAL_PREFS: DiffPreferencesInfo = {
+ tab_size: 2,
+ line_length: 80,
+ font_size: 12,
+ context: 3,
+ ignore_whitespace: 'IGNORE_NONE',
+ };
+
+ setup(async () => {
+ model = new DiffModel();
+ element = (
+ await fixture(
+ wrapInProvider(
+ html`<gr-diff-element></gr-diff-element>`,
+ diffModelToken,
+ model
+ )
+ )
+ ).querySelector('gr-diff-element')!;
+ });
+
+ suite('rendering', () => {
+ test('empty diff', async () => {
+ await element.updateComplete;
+ assert.lightDom.equal(
+ element,
+ /* HTML */ `
+ <div class="diffContainer newDiff sideBySide">
+ <table id="diffTable">
+ <colgroup>
+ <col class="blame gr-diff" />
+ <col class="gr-diff left" width="48" />
+ <col class="gr-diff left sign" />
+ <col class="gr-diff left" />
+ <col class="gr-diff right" width="48" />
+ <col class="gr-diff right sign" />
+ <col class="gr-diff right" />
+ </colgroup>
+ </table>
+ </div>
+ `
+ );
+ });
+
+ test('a unified diff lit', async () => {
+ model.updateState({
+ diff: createDiff(),
+ diffPrefs: {...MINIMAL_PREFS},
+ renderPrefs: {view_mode: DiffViewMode.UNIFIED},
+ });
+ await element.updateComplete;
+ await waitForEventOnce(element, 'render');
+ assert.lightDom.equal(
+ element,
+ /* HTML */ `
+ <div class="diffContainer newDiff unified">
+ <table id="diffTable">
+ <colgroup>
+ <col class="blame gr-diff" />
+ <col class="gr-diff" width="48" />
+ <col class="gr-diff" width="48" />
+ <col class="gr-diff" />
+ </colgroup>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-LOST right-button-LOST right-content-LOST"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="LOST"></td>
+ <td class="gr-diff left lineNum" data-value="LOST"></td>
+ <td class="gr-diff lineNum right" data-value="LOST"></td>
+ <td class="both content gr-diff lost no-intraline-info right">
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-FILE right-button-FILE right-content-FILE"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="FILE"></td>
+ <td class="gr-diff left lineNum" data-value="FILE">
+ <button
+ aria-label="Add file comment"
+ class="gr-diff left lineNumButton"
+ data-value="FILE"
+ id="left-button-FILE"
+ tabindex="-1"
+ >
+ File
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="FILE">
+ <button
+ aria-label="Add file comment"
+ class="gr-diff lineNumButton right"
+ data-value="FILE"
+ id="right-button-FILE"
+ tabindex="-1"
+ >
+ File
+ </button>
+ </td>
+ <td class="both content file gr-diff no-intraline-info right">
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-1 right-button-1 right-content-1"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="1"></td>
+ <td class="gr-diff left lineNum" data-value="1">
+ <button
+ aria-label="1 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="1"
+ id="left-button-1"
+ tabindex="-1"
+ >
+ 1
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="1">
+ <button
+ aria-label="1 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="1"
+ id="right-button-1"
+ tabindex="-1"
+ >
+ 1
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-1"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-2 right-button-2 right-content-2"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="2"></td>
+ <td class="gr-diff left lineNum" data-value="2">
+ <button
+ aria-label="2 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="2"
+ id="left-button-2"
+ tabindex="-1"
+ >
+ 2
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="2">
+ <button
+ aria-label="2 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="2"
+ id="right-button-2"
+ tabindex="-1"
+ >
+ 2
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-2"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-3 right-button-3 right-content-3"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="3"></td>
+ <td class="gr-diff left lineNum" data-value="3">
+ <button
+ aria-label="3 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="3"
+ id="left-button-3"
+ tabindex="-1"
+ >
+ 3
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="3">
+ <button
+ aria-label="3 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="3"
+ id="right-button-3"
+ tabindex="-1"
+ >
+ 3
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-3"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-4 right-button-4 right-content-4"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="4"></td>
+ <td class="gr-diff left lineNum" data-value="4">
+ <button
+ aria-label="4 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="4"
+ id="left-button-4"
+ tabindex="-1"
+ >
+ 4
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="4">
+ <button
+ aria-label="4 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="4"
+ id="right-button-4"
+ tabindex="-1"
+ >
+ 4
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-4"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="delta gr-diff section total">
+ <tr
+ aria-labelledby="right-button-5 right-content-5"
+ class="add diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="gr-diff left"></td>
+ <td class="gr-diff lineNum right" data-value="5">
+ <button
+ aria-label="5 added"
+ class="gr-diff lineNumButton right"
+ data-value="5"
+ id="right-button-5"
+ tabindex="-1"
+ >
+ 5
+ </button>
+ </td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-5"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="right-button-6 right-content-6"
+ class="add diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="gr-diff left"></td>
+ <td class="gr-diff lineNum right" data-value="6">
+ <button
+ aria-label="6 added"
+ class="gr-diff lineNumButton right"
+ data-value="6"
+ id="right-button-6"
+ tabindex="-1"
+ >
+ 6
+ </button>
+ </td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-6"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="right-button-7 right-content-7"
+ class="add diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="gr-diff left"></td>
+ <td class="gr-diff lineNum right" data-value="7">
+ <button
+ aria-label="7 added"
+ class="gr-diff lineNumButton right"
+ data-value="7"
+ id="right-button-7"
+ tabindex="-1"
+ >
+ 7
+ </button>
+ </td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-7"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-5 right-button-8 right-content-8"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="5"></td>
+ <td class="gr-diff left lineNum" data-value="5">
+ <button
+ aria-label="5 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="5"
+ id="left-button-5"
+ tabindex="-1"
+ >
+ 5
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="8">
+ <button
+ aria-label="8 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="8"
+ id="right-button-8"
+ tabindex="-1"
+ >
+ 8
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-8"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-6 right-button-9 right-content-9"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="6"></td>
+ <td class="gr-diff left lineNum" data-value="6">
+ <button
+ aria-label="6 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="6"
+ id="left-button-6"
+ tabindex="-1"
+ >
+ 6
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="9">
+ <button
+ aria-label="9 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="9"
+ id="right-button-9"
+ tabindex="-1"
+ >
+ 9
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-9"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-7 right-button-10 right-content-10"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="7"></td>
+ <td class="gr-diff left lineNum" data-value="7">
+ <button
+ aria-label="7 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="7"
+ id="left-button-7"
+ tabindex="-1"
+ >
+ 7
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="10">
+ <button
+ aria-label="10 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="10"
+ id="right-button-10"
+ tabindex="-1"
+ >
+ 10
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-10"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-8 right-button-11 right-content-11"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="8"></td>
+ <td class="gr-diff left lineNum" data-value="8">
+ <button
+ aria-label="8 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="8"
+ id="left-button-8"
+ tabindex="-1"
+ >
+ 8
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="11">
+ <button
+ aria-label="11 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="11"
+ id="right-button-11"
+ tabindex="-1"
+ >
+ 11
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-11"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-9 right-button-12 right-content-12"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="9"></td>
+ <td class="gr-diff left lineNum" data-value="9">
+ <button
+ aria-label="9 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="9"
+ id="left-button-9"
+ tabindex="-1"
+ >
+ 9
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="12">
+ <button
+ aria-label="12 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="12"
+ id="right-button-12"
+ tabindex="-1"
+ >
+ 12
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-12"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="delta gr-diff section total">
+ <tr
+ aria-labelledby="left-button-10 left-content-10"
+ class="diff-row gr-diff remove unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="10"></td>
+ <td class="gr-diff left lineNum" data-value="10">
+ <button
+ aria-label="10 removed"
+ class="gr-diff left lineNumButton"
+ data-value="10"
+ id="left-button-10"
+ tabindex="-1"
+ >
+ 10
+ </button>
+ </td>
+ <td class="gr-diff right"></td>
+ <td class="content gr-diff left no-intraline-info remove">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-10"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-11 left-content-11"
+ class="diff-row gr-diff remove unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="11"></td>
+ <td class="gr-diff left lineNum" data-value="11">
+ <button
+ aria-label="11 removed"
+ class="gr-diff left lineNumButton"
+ data-value="11"
+ id="left-button-11"
+ tabindex="-1"
+ >
+ 11
+ </button>
+ </td>
+ <td class="gr-diff right"></td>
+ <td class="content gr-diff left no-intraline-info remove">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-11"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-12 left-content-12"
+ class="diff-row gr-diff remove unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="12"></td>
+ <td class="gr-diff left lineNum" data-value="12">
+ <button
+ aria-label="12 removed"
+ class="gr-diff left lineNumButton"
+ data-value="12"
+ id="left-button-12"
+ tabindex="-1"
+ >
+ 12
+ </button>
+ </td>
+ <td class="gr-diff right"></td>
+ <td class="content gr-diff left no-intraline-info remove">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-12"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-13 left-content-13"
+ class="diff-row gr-diff remove unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="13"></td>
+ <td class="gr-diff left lineNum" data-value="13">
+ <button
+ aria-label="13 removed"
+ class="gr-diff left lineNumButton"
+ data-value="13"
+ id="left-button-13"
+ tabindex="-1"
+ >
+ 13
+ </button>
+ </td>
+ <td class="gr-diff right"></td>
+ <td class="content gr-diff left no-intraline-info remove">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-13"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="delta gr-diff ignoredWhitespaceOnly section">
+ <tr
+ aria-labelledby="right-button-13 right-content-13"
+ class="add diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="gr-diff left"></td>
+ <td class="gr-diff lineNum right" data-value="13">
+ <button
+ aria-label="13 added"
+ class="gr-diff lineNumButton right"
+ data-value="13"
+ id="right-button-13"
+ tabindex="-1"
+ >
+ 13
+ </button>
+ </td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-13"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="right-button-14 right-content-14"
+ class="add diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="gr-diff left"></td>
+ <td class="gr-diff lineNum right" data-value="14">
+ <button
+ aria-label="14 added"
+ class="gr-diff lineNumButton right"
+ data-value="14"
+ id="right-button-14"
+ tabindex="-1"
+ >
+ 14
+ </button>
+ </td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-14"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="delta gr-diff section">
+ <tr
+ aria-labelledby="left-button-16 left-content-16"
+ class="diff-row gr-diff remove unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="16"></td>
+ <td class="gr-diff left lineNum" data-value="16">
+ <button
+ aria-label="16 removed"
+ class="gr-diff left lineNumButton"
+ data-value="16"
+ id="left-button-16"
+ tabindex="-1"
+ >
+ 16
+ </button>
+ </td>
+ <td class="gr-diff right"></td>
+ <td class="content gr-diff left remove">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-16"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="right-button-15 right-content-15"
+ class="add diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="gr-diff left"></td>
+ <td class="gr-diff lineNum right" data-value="15">
+ <button
+ aria-label="15 added"
+ class="gr-diff lineNumButton right"
+ data-value="15"
+ id="right-button-15"
+ tabindex="-1"
+ >
+ 15
+ </button>
+ </td>
+ <td class="add content gr-diff right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-15"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-17 right-button-16 right-content-16"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="17"></td>
+ <td class="gr-diff left lineNum" data-value="17">
+ <button
+ aria-label="17 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="17"
+ id="left-button-17"
+ tabindex="-1"
+ >
+ 17
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="16">
+ <button
+ aria-label="16 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="16"
+ id="right-button-16"
+ tabindex="-1"
+ >
+ 16
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-16"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-18 right-button-17 right-content-17"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="18"></td>
+ <td class="gr-diff left lineNum" data-value="18">
+ <button
+ aria-label="18 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="18"
+ id="left-button-18"
+ tabindex="-1"
+ >
+ 18
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="17">
+ <button
+ aria-label="17 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="17"
+ id="right-button-17"
+ tabindex="-1"
+ >
+ 17
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-17"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-19 right-button-18 right-content-18"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="19"></td>
+ <td class="gr-diff left lineNum" data-value="19">
+ <button
+ aria-label="19 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="19"
+ id="left-button-19"
+ tabindex="-1"
+ >
+ 19
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="18">
+ <button
+ aria-label="18 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="18"
+ id="right-button-18"
+ tabindex="-1"
+ >
+ 18
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-18"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="contextControl gr-diff section">
+ <tr class="above contextBackground gr-diff unified">
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="contextLineNum gr-diff"></td>
+ <td class="contextLineNum gr-diff"></td>
+ <td class="gr-diff"></td>
+ </tr>
+ <tr class="dividerRow gr-diff show-both">
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="dividerCell gr-diff" colspan="3">
+ <gr-context-controls class="gr-diff" showconfig="both">
+ </gr-context-controls>
+ </td>
+ </tr>
+ <tr class="below contextBackground gr-diff unified">
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="contextLineNum gr-diff"></td>
+ <td class="contextLineNum gr-diff"></td>
+ <td class="gr-diff"></td>
+ </tr>
+ </tbody>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-38 right-button-37 right-content-37"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="38"></td>
+ <td class="gr-diff left lineNum" data-value="38">
+ <button
+ aria-label="38 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="38"
+ id="left-button-38"
+ tabindex="-1"
+ >
+ 38
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="37">
+ <button
+ aria-label="37 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="37"
+ id="right-button-37"
+ tabindex="-1"
+ >
+ 37
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-37"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-39 right-button-38 right-content-38"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="39"></td>
+ <td class="gr-diff left lineNum" data-value="39">
+ <button
+ aria-label="39 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="39"
+ id="left-button-39"
+ tabindex="-1"
+ >
+ 39
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="38">
+ <button
+ aria-label="38 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="38"
+ id="right-button-38"
+ tabindex="-1"
+ >
+ 38
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-38"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-40 right-button-39 right-content-39"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="40"></td>
+ <td class="gr-diff left lineNum" data-value="40">
+ <button
+ aria-label="40 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="40"
+ id="left-button-40"
+ tabindex="-1"
+ >
+ 40
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="39">
+ <button
+ aria-label="39 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="39"
+ id="right-button-39"
+ tabindex="-1"
+ >
+ 39
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-39"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="delta gr-diff section total">
+ <tr
+ aria-labelledby="right-button-40 right-content-40"
+ class="add diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="gr-diff left"></td>
+ <td class="gr-diff lineNum right" data-value="40">
+ <button
+ aria-label="40 added"
+ class="gr-diff lineNumButton right"
+ data-value="40"
+ id="right-button-40"
+ tabindex="-1"
+ >
+ 40
+ </button>
+ </td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-40"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="right-button-41 right-content-41"
+ class="add diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="gr-diff left"></td>
+ <td class="gr-diff lineNum right" data-value="41">
+ <button
+ aria-label="41 added"
+ class="gr-diff lineNumButton right"
+ data-value="41"
+ id="right-button-41"
+ tabindex="-1"
+ >
+ 41
+ </button>
+ </td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-41"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="right-button-42 right-content-42"
+ class="add diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="gr-diff left"></td>
+ <td class="gr-diff lineNum right" data-value="42">
+ <button
+ aria-label="42 added"
+ class="gr-diff lineNumButton right"
+ data-value="42"
+ id="right-button-42"
+ tabindex="-1"
+ >
+ 42
+ </button>
+ </td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-42"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="right-button-43 right-content-43"
+ class="add diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="gr-diff left"></td>
+ <td class="gr-diff lineNum right" data-value="43">
+ <button
+ aria-label="43 added"
+ class="gr-diff lineNumButton right"
+ data-value="43"
+ id="right-button-43"
+ tabindex="-1"
+ >
+ 43
+ </button>
+ </td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-43"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-41 right-button-44 right-content-44"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="41"></td>
+ <td class="gr-diff left lineNum" data-value="41">
+ <button
+ aria-label="41 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="41"
+ id="left-button-41"
+ tabindex="-1"
+ >
+ 41
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="44">
+ <button
+ aria-label="44 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="44"
+ id="right-button-44"
+ tabindex="-1"
+ >
+ 44
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-44"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-42 right-button-45 right-content-45"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="42"></td>
+ <td class="gr-diff left lineNum" data-value="42">
+ <button
+ aria-label="42 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="42"
+ id="left-button-42"
+ tabindex="-1"
+ >
+ 42
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="45">
+ <button
+ aria-label="45 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="45"
+ id="right-button-45"
+ tabindex="-1"
+ >
+ 45
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-45"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-43 right-button-46 right-content-46"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="43"></td>
+ <td class="gr-diff left lineNum" data-value="43">
+ <button
+ aria-label="43 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="43"
+ id="left-button-43"
+ tabindex="-1"
+ >
+ 43
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="46">
+ <button
+ aria-label="46 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="46"
+ id="right-button-46"
+ tabindex="-1"
+ >
+ 46
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-46"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-44 right-button-47 right-content-47"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="44"></td>
+ <td class="gr-diff left lineNum" data-value="44">
+ <button
+ aria-label="44 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="44"
+ id="left-button-44"
+ tabindex="-1"
+ >
+ 44
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="47">
+ <button
+ aria-label="47 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="47"
+ id="right-button-47"
+ tabindex="-1"
+ >
+ 47
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-47"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-45 right-button-48 right-content-48"
+ class="both diff-row gr-diff unified"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="45"></td>
+ <td class="gr-diff left lineNum" data-value="45">
+ <button
+ aria-label="45 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="45"
+ id="left-button-45"
+ tabindex="-1"
+ >
+ 45
+ </button>
+ </td>
+ <td class="gr-diff lineNum right" data-value="48">
+ <button
+ aria-label="48 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="48"
+ id="right-button-48"
+ tabindex="-1"
+ >
+ 48
+ </button>
+ </td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-48"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ `,
+ {
+ ignoreTags: [
+ 'gr-context-controls-section',
+ 'gr-diff-section',
+ 'gr-diff-row',
+ 'gr-diff-text',
+ 'gr-legacy-text',
+ 'slot',
+ ],
+ }
+ );
+ });
+
+ test('a normal diff lit', async () => {
+ model.updateState({
+ diff: createDiff(),
+ diffPrefs: {...MINIMAL_PREFS},
+ renderPrefs: {view_mode: DiffViewMode.SIDE_BY_SIDE},
+ });
+ await element.updateComplete;
+ await waitForEventOnce(element, 'render');
+ assert.lightDom.equal(
+ element,
+ /* HTML */ `
+ <div class="diffContainer newDiff sideBySide">
+ <table id="diffTable">
+ <colgroup>
+ <col class="blame gr-diff" />
+ <col class="gr-diff left" width="48" />
+ <col class="gr-diff left sign" />
+ <col class="gr-diff left" />
+ <col class="gr-diff right" width="48" />
+ <col class="gr-diff right sign" />
+ <col class="gr-diff right" />
+ </colgroup>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-LOST left-content-LOST right-button-LOST right-content-LOST"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="LOST"></td>
+ <td class="gr-diff left lineNum" data-value="LOST"></td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left lost no-intraline-info">
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="LOST"></td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff lost no-intraline-info right">
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-FILE left-content-FILE right-button-FILE right-content-FILE"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="FILE"></td>
+ <td class="gr-diff left lineNum" data-value="FILE">
+ <button
+ aria-label="Add file comment"
+ class="gr-diff left lineNumButton"
+ data-value="FILE"
+ id="left-button-FILE"
+ tabindex="-1"
+ >
+ File
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content file gr-diff left no-intraline-info">
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="FILE">
+ <button
+ aria-label="Add file comment"
+ class="gr-diff lineNumButton right"
+ data-value="FILE"
+ id="right-button-FILE"
+ tabindex="-1"
+ >
+ File
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content file gr-diff no-intraline-info right">
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-1 left-content-1 right-button-1 right-content-1"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="1"></td>
+ <td class="gr-diff left lineNum" data-value="1">
+ <button
+ aria-label="1 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="1"
+ id="left-button-1"
+ tabindex="-1"
+ >
+ 1
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-1"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="1">
+ <button
+ aria-label="1 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="1"
+ id="right-button-1"
+ tabindex="-1"
+ >
+ 1
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-1"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-2 left-content-2 right-button-2 right-content-2"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="2"></td>
+ <td class="gr-diff left lineNum" data-value="2">
+ <button
+ aria-label="2 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="2"
+ id="left-button-2"
+ tabindex="-1"
+ >
+ 2
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-2"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="2">
+ <button
+ aria-label="2 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="2"
+ id="right-button-2"
+ tabindex="-1"
+ >
+ 2
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-2"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-3 left-content-3 right-button-3 right-content-3"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="3"></td>
+ <td class="gr-diff left lineNum" data-value="3">
+ <button
+ aria-label="3 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="3"
+ id="left-button-3"
+ tabindex="-1"
+ >
+ 3
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-3"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="3">
+ <button
+ aria-label="3 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="3"
+ id="right-button-3"
+ tabindex="-1"
+ >
+ 3
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-3"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-4 left-content-4 right-button-4 right-content-4"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="4"></td>
+ <td class="gr-diff left lineNum" data-value="4">
+ <button
+ aria-label="4 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="4"
+ id="left-button-4"
+ tabindex="-1"
+ >
+ 4
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-4"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="4">
+ <button
+ aria-label="4 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="4"
+ id="right-button-4"
+ tabindex="-1"
+ >
+ 4
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-4"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="delta gr-diff section total">
+ <tr
+ aria-labelledby="right-button-5 right-content-5"
+ class="diff-row gr-diff side-by-side"
+ left-type="blank"
+ right-type="add"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="blankLineNum gr-diff left"></td>
+ <td class="blank gr-diff left no-intraline-info sign"></td>
+ <td class="blank gr-diff left no-intraline-info">
+ <div class="contentText gr-diff" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="5">
+ <button
+ aria-label="5 added"
+ class="gr-diff lineNumButton right"
+ data-value="5"
+ id="right-button-5"
+ tabindex="-1"
+ >
+ 5
+ </button>
+ </td>
+ <td class="add gr-diff no-intraline-info right sign">+</td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-5"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="right-button-6 right-content-6"
+ class="diff-row gr-diff side-by-side"
+ left-type="blank"
+ right-type="add"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="blankLineNum gr-diff left"></td>
+ <td class="blank gr-diff left no-intraline-info sign"></td>
+ <td class="blank gr-diff left no-intraline-info">
+ <div class="contentText gr-diff" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="6">
+ <button
+ aria-label="6 added"
+ class="gr-diff lineNumButton right"
+ data-value="6"
+ id="right-button-6"
+ tabindex="-1"
+ >
+ 6
+ </button>
+ </td>
+ <td class="add gr-diff no-intraline-info right sign">+</td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-6"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="right-button-7 right-content-7"
+ class="diff-row gr-diff side-by-side"
+ left-type="blank"
+ right-type="add"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="blankLineNum gr-diff left"></td>
+ <td class="blank gr-diff left no-intraline-info sign"></td>
+ <td class="blank gr-diff left no-intraline-info">
+ <div class="contentText gr-diff" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="7">
+ <button
+ aria-label="7 added"
+ class="gr-diff lineNumButton right"
+ data-value="7"
+ id="right-button-7"
+ tabindex="-1"
+ >
+ 7
+ </button>
+ </td>
+ <td class="add gr-diff no-intraline-info right sign">+</td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-7"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-5 left-content-5 right-button-8 right-content-8"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="5"></td>
+ <td class="gr-diff left lineNum" data-value="5">
+ <button
+ aria-label="5 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="5"
+ id="left-button-5"
+ tabindex="-1"
+ >
+ 5
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-5"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="8">
+ <button
+ aria-label="8 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="8"
+ id="right-button-8"
+ tabindex="-1"
+ >
+ 8
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-8"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-6 left-content-6 right-button-9 right-content-9"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="6"></td>
+ <td class="gr-diff left lineNum" data-value="6">
+ <button
+ aria-label="6 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="6"
+ id="left-button-6"
+ tabindex="-1"
+ >
+ 6
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-6"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="9">
+ <button
+ aria-label="9 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="9"
+ id="right-button-9"
+ tabindex="-1"
+ >
+ 9
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-9"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-7 left-content-7 right-button-10 right-content-10"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="7"></td>
+ <td class="gr-diff left lineNum" data-value="7">
+ <button
+ aria-label="7 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="7"
+ id="left-button-7"
+ tabindex="-1"
+ >
+ 7
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-7"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="10">
+ <button
+ aria-label="10 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="10"
+ id="right-button-10"
+ tabindex="-1"
+ >
+ 10
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-10"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-8 left-content-8 right-button-11 right-content-11"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="8"></td>
+ <td class="gr-diff left lineNum" data-value="8">
+ <button
+ aria-label="8 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="8"
+ id="left-button-8"
+ tabindex="-1"
+ >
+ 8
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-8"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="11">
+ <button
+ aria-label="11 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="11"
+ id="right-button-11"
+ tabindex="-1"
+ >
+ 11
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-11"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-9 left-content-9 right-button-12 right-content-12"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="9"></td>
+ <td class="gr-diff left lineNum" data-value="9">
+ <button
+ aria-label="9 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="9"
+ id="left-button-9"
+ tabindex="-1"
+ >
+ 9
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-9"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="12">
+ <button
+ aria-label="12 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="12"
+ id="right-button-12"
+ tabindex="-1"
+ >
+ 12
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-12"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="delta gr-diff section total">
+ <tr
+ aria-labelledby="left-button-10 left-content-10"
+ class="diff-row gr-diff side-by-side"
+ left-type="remove"
+ right-type="blank"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="10"></td>
+ <td class="gr-diff left lineNum" data-value="10">
+ <button
+ aria-label="10 removed"
+ class="gr-diff left lineNumButton"
+ data-value="10"
+ id="left-button-10"
+ tabindex="-1"
+ >
+ 10
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info remove sign">-</td>
+ <td class="content gr-diff left no-intraline-info remove">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-10"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="blankLineNum gr-diff right"></td>
+ <td class="blank gr-diff no-intraline-info right sign"></td>
+ <td class="blank gr-diff no-intraline-info right">
+ <div class="contentText gr-diff" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-11 left-content-11"
+ class="diff-row gr-diff side-by-side"
+ left-type="remove"
+ right-type="blank"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="11"></td>
+ <td class="gr-diff left lineNum" data-value="11">
+ <button
+ aria-label="11 removed"
+ class="gr-diff left lineNumButton"
+ data-value="11"
+ id="left-button-11"
+ tabindex="-1"
+ >
+ 11
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info remove sign">-</td>
+ <td class="content gr-diff left no-intraline-info remove">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-11"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="blankLineNum gr-diff right"></td>
+ <td class="blank gr-diff no-intraline-info right sign"></td>
+ <td class="blank gr-diff no-intraline-info right">
+ <div class="contentText gr-diff" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-12 left-content-12"
+ class="diff-row gr-diff side-by-side"
+ left-type="remove"
+ right-type="blank"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="12"></td>
+ <td class="gr-diff left lineNum" data-value="12">
+ <button
+ aria-label="12 removed"
+ class="gr-diff left lineNumButton"
+ data-value="12"
+ id="left-button-12"
+ tabindex="-1"
+ >
+ 12
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info remove sign">-</td>
+ <td class="content gr-diff left no-intraline-info remove">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-12"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="blankLineNum gr-diff right"></td>
+ <td class="blank gr-diff no-intraline-info right sign"></td>
+ <td class="blank gr-diff no-intraline-info right">
+ <div class="contentText gr-diff" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-13 left-content-13"
+ class="diff-row gr-diff side-by-side"
+ left-type="remove"
+ right-type="blank"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="13"></td>
+ <td class="gr-diff left lineNum" data-value="13">
+ <button
+ aria-label="13 removed"
+ class="gr-diff left lineNumButton"
+ data-value="13"
+ id="left-button-13"
+ tabindex="-1"
+ >
+ 13
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info remove sign">-</td>
+ <td class="content gr-diff left no-intraline-info remove">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-13"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="blankLineNum gr-diff right"></td>
+ <td class="blank gr-diff no-intraline-info right sign"></td>
+ <td class="blank gr-diff no-intraline-info right">
+ <div class="contentText gr-diff" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="delta gr-diff ignoredWhitespaceOnly section">
+ <tr
+ aria-labelledby="left-button-14 left-content-14 right-button-13 right-content-13"
+ class="diff-row gr-diff side-by-side"
+ left-type="remove"
+ right-type="add"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="14"></td>
+ <td class="gr-diff left lineNum" data-value="14">
+ <button
+ aria-label="14 removed"
+ class="gr-diff left lineNumButton"
+ data-value="14"
+ id="left-button-14"
+ tabindex="-1"
+ >
+ 14
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info remove sign">-</td>
+ <td class="content gr-diff left no-intraline-info remove">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-14"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="13">
+ <button
+ aria-label="13 added"
+ class="gr-diff lineNumButton right"
+ data-value="13"
+ id="right-button-13"
+ tabindex="-1"
+ >
+ 13
+ </button>
+ </td>
+ <td class="add gr-diff no-intraline-info right sign">+</td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-13"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-15 left-content-15 right-button-14 right-content-14"
+ class="diff-row gr-diff side-by-side"
+ left-type="remove"
+ right-type="add"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="15"></td>
+ <td class="gr-diff left lineNum" data-value="15">
+ <button
+ aria-label="15 removed"
+ class="gr-diff left lineNumButton"
+ data-value="15"
+ id="left-button-15"
+ tabindex="-1"
+ >
+ 15
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info remove sign">-</td>
+ <td class="content gr-diff left no-intraline-info remove">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-15"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="14">
+ <button
+ aria-label="14 added"
+ class="gr-diff lineNumButton right"
+ data-value="14"
+ id="right-button-14"
+ tabindex="-1"
+ >
+ 14
+ </button>
+ </td>
+ <td class="add gr-diff no-intraline-info right sign">+</td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-14"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="delta gr-diff section">
+ <tr
+ aria-labelledby="left-button-16 left-content-16 right-button-15 right-content-15"
+ class="diff-row gr-diff side-by-side"
+ left-type="remove"
+ right-type="add"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="16"></td>
+ <td class="gr-diff left lineNum" data-value="16">
+ <button
+ aria-label="16 removed"
+ class="gr-diff left lineNumButton"
+ data-value="16"
+ id="left-button-16"
+ tabindex="-1"
+ >
+ 16
+ </button>
+ </td>
+ <td class="gr-diff left remove sign">-</td>
+ <td class="content gr-diff left remove">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-16"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="15">
+ <button
+ aria-label="15 added"
+ class="gr-diff lineNumButton right"
+ data-value="15"
+ id="right-button-15"
+ tabindex="-1"
+ >
+ 15
+ </button>
+ </td>
+ <td class="add gr-diff right sign">+</td>
+ <td class="add content gr-diff right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-15"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-17 left-content-17 right-button-16 right-content-16"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="17"></td>
+ <td class="gr-diff left lineNum" data-value="17">
+ <button
+ aria-label="17 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="17"
+ id="left-button-17"
+ tabindex="-1"
+ >
+ 17
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-17"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="16">
+ <button
+ aria-label="16 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="16"
+ id="right-button-16"
+ tabindex="-1"
+ >
+ 16
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-16"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-18 left-content-18 right-button-17 right-content-17"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="18"></td>
+ <td class="gr-diff left lineNum" data-value="18">
+ <button
+ aria-label="18 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="18"
+ id="left-button-18"
+ tabindex="-1"
+ >
+ 18
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-18"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="17">
+ <button
+ aria-label="17 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="17"
+ id="right-button-17"
+ tabindex="-1"
+ >
+ 17
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-17"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-19 left-content-19 right-button-18 right-content-18"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="19"></td>
+ <td class="gr-diff left lineNum" data-value="19">
+ <button
+ aria-label="19 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="19"
+ id="left-button-19"
+ tabindex="-1"
+ >
+ 19
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-19"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="18">
+ <button
+ aria-label="18 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="18"
+ id="right-button-18"
+ tabindex="-1"
+ >
+ 18
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-18"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="contextControl gr-diff section">
+ <tr
+ class="above contextBackground gr-diff side-by-side"
+ left-type="contextControl"
+ right-type="contextControl"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="contextLineNum gr-diff"></td>
+ <td class="gr-diff sign"></td>
+ <td class="gr-diff"></td>
+ <td class="contextLineNum gr-diff"></td>
+ <td class="gr-diff sign"></td>
+ <td class="gr-diff"></td>
+ </tr>
+ <tr class="dividerRow gr-diff show-both">
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="gr-diff"></td>
+ <td class="dividerCell gr-diff" colspan="3">
+ <gr-context-controls
+ class="gr-diff"
+ showconfig="both"
+ ></gr-context-controls>
+ </td>
+ </tr>
+ <tr
+ class="below contextBackground gr-diff side-by-side"
+ left-type="contextControl"
+ right-type="contextControl"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="contextLineNum gr-diff"></td>
+ <td class="gr-diff sign"></td>
+ <td class="gr-diff"></td>
+ <td class="contextLineNum gr-diff"></td>
+ <td class="gr-diff sign"></td>
+ <td class="gr-diff"></td>
+ </tr>
+ </tbody>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-38 left-content-38 right-button-37 right-content-37"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="38"></td>
+ <td class="gr-diff left lineNum" data-value="38">
+ <button
+ aria-label="38 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="38"
+ id="left-button-38"
+ tabindex="-1"
+ >
+ 38
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-38"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="37">
+ <button
+ aria-label="37 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="37"
+ id="right-button-37"
+ tabindex="-1"
+ >
+ 37
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-37"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-39 left-content-39 right-button-38 right-content-38"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="39"></td>
+ <td class="gr-diff left lineNum" data-value="39">
+ <button
+ aria-label="39 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="39"
+ id="left-button-39"
+ tabindex="-1"
+ >
+ 39
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-39"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="38">
+ <button
+ aria-label="38 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="38"
+ id="right-button-38"
+ tabindex="-1"
+ >
+ 38
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-38"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-40 left-content-40 right-button-39 right-content-39"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="40"></td>
+ <td class="gr-diff left lineNum" data-value="40">
+ <button
+ aria-label="40 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="40"
+ id="left-button-40"
+ tabindex="-1"
+ >
+ 40
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-40"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="39">
+ <button
+ aria-label="39 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="39"
+ id="right-button-39"
+ tabindex="-1"
+ >
+ 39
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-39"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="delta gr-diff section total">
+ <tr
+ aria-labelledby="right-button-40 right-content-40"
+ class="diff-row gr-diff side-by-side"
+ left-type="blank"
+ right-type="add"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="blankLineNum gr-diff left"></td>
+ <td class="blank gr-diff left no-intraline-info sign"></td>
+ <td class="blank gr-diff left no-intraline-info">
+ <div class="contentText gr-diff" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="40">
+ <button
+ aria-label="40 added"
+ class="gr-diff lineNumButton right"
+ data-value="40"
+ id="right-button-40"
+ tabindex="-1"
+ >
+ 40
+ </button>
+ </td>
+ <td class="add gr-diff no-intraline-info right sign">+</td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-40"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="right-button-41 right-content-41"
+ class="diff-row gr-diff side-by-side"
+ left-type="blank"
+ right-type="add"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="blankLineNum gr-diff left"></td>
+ <td class="blank gr-diff left no-intraline-info sign"></td>
+ <td class="blank gr-diff left no-intraline-info">
+ <div class="contentText gr-diff" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="41">
+ <button
+ aria-label="41 added"
+ class="gr-diff lineNumButton right"
+ data-value="41"
+ id="right-button-41"
+ tabindex="-1"
+ >
+ 41
+ </button>
+ </td>
+ <td class="add gr-diff no-intraline-info right sign">+</td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-41"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="right-button-42 right-content-42"
+ class="diff-row gr-diff side-by-side"
+ left-type="blank"
+ right-type="add"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="blankLineNum gr-diff left"></td>
+ <td class="blank gr-diff left no-intraline-info sign"></td>
+ <td class="blank gr-diff left no-intraline-info">
+ <div class="contentText gr-diff" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="42">
+ <button
+ aria-label="42 added"
+ class="gr-diff lineNumButton right"
+ data-value="42"
+ id="right-button-42"
+ tabindex="-1"
+ >
+ 42
+ </button>
+ </td>
+ <td class="add gr-diff no-intraline-info right sign">+</td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-42"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="right-button-43 right-content-43"
+ class="diff-row gr-diff side-by-side"
+ left-type="blank"
+ right-type="add"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="0"></td>
+ <td class="blankLineNum gr-diff left"></td>
+ <td class="blank gr-diff left no-intraline-info sign"></td>
+ <td class="blank gr-diff left no-intraline-info">
+ <div class="contentText gr-diff" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="43">
+ <button
+ aria-label="43 added"
+ class="gr-diff lineNumButton right"
+ data-value="43"
+ id="right-button-43"
+ tabindex="-1"
+ >
+ 43
+ </button>
+ </td>
+ <td class="add gr-diff no-intraline-info right sign">+</td>
+ <td class="add content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-43"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-41 left-content-41 right-button-44 right-content-44"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="41"></td>
+ <td class="gr-diff left lineNum" data-value="41">
+ <button
+ aria-label="41 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="41"
+ id="left-button-41"
+ tabindex="-1"
+ >
+ 41
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-41"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="44">
+ <button
+ aria-label="44 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="44"
+ id="right-button-44"
+ tabindex="-1"
+ >
+ 44
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-44"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-42 left-content-42 right-button-45 right-content-45"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="42"></td>
+ <td class="gr-diff left lineNum" data-value="42">
+ <button
+ aria-label="42 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="42"
+ id="left-button-42"
+ tabindex="-1"
+ >
+ 42
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-42"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="45">
+ <button
+ aria-label="45 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="45"
+ id="right-button-45"
+ tabindex="-1"
+ >
+ 45
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-45"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-43 left-content-43 right-button-46 right-content-46"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="43"></td>
+ <td class="gr-diff left lineNum" data-value="43">
+ <button
+ aria-label="43 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="43"
+ id="left-button-43"
+ tabindex="-1"
+ >
+ 43
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-43"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="46">
+ <button
+ aria-label="46 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="46"
+ id="right-button-46"
+ tabindex="-1"
+ >
+ 46
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-46"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-44 left-content-44 right-button-47 right-content-47"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="44"></td>
+ <td class="gr-diff left lineNum" data-value="44">
+ <button
+ aria-label="44 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="44"
+ id="left-button-44"
+ tabindex="-1"
+ >
+ 44
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-44"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="47">
+ <button
+ aria-label="47 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="47"
+ id="right-button-47"
+ tabindex="-1"
+ >
+ 47
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-47"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ <tr
+ aria-labelledby="left-button-45 left-content-45 right-button-48 right-content-48"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="45"></td>
+ <td class="gr-diff left lineNum" data-value="45">
+ <button
+ aria-label="45 unmodified"
+ class="gr-diff left lineNumButton"
+ data-value="45"
+ id="left-button-45"
+ tabindex="-1"
+ >
+ 45
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td class="both content gr-diff left no-intraline-info">
+ <div
+ class="contentText gr-diff"
+ data-side="left"
+ id="left-content-45"
+ ></div>
+ <div class="thread-group" data-side="left"></div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="48">
+ <button
+ aria-label="48 unmodified"
+ class="gr-diff lineNumButton right"
+ data-value="48"
+ id="right-button-48"
+ tabindex="-1"
+ >
+ 48
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td class="both content gr-diff no-intraline-info right">
+ <div
+ class="contentText gr-diff"
+ data-side="right"
+ id="right-content-48"
+ ></div>
+ <div class="thread-group" data-side="right"></div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ `,
+ {
+ ignoreTags: [
+ 'gr-context-controls-section',
+ 'gr-diff-section',
+ 'gr-diff-row',
+ 'gr-diff-text',
+ 'gr-legacy-text',
+ 'slot',
+ ],
+ }
+ );
+ });
+ });
+
+ suite('not logged in', () => {
+ setup(async () => {
+ await element.updateComplete;
+ });
+
+ suite('binary diffs', () => {
+ test('render binary diff', async () => {
+ model.updateState({
+ diff: {
+ meta_a: {name: 'carrot.exe', content_type: 'binary', lines: 0},
+ meta_b: {name: 'carrot.exe', content_type: 'binary', lines: 0},
+ change_type: 'MODIFIED',
+ intraline_status: 'OK',
+ diff_header: [],
+ content: [],
+ binary: true,
+ },
+ diffPrefs: {...MINIMAL_PREFS},
+ });
+ await waitForEventOnce(element, 'render');
+
+ assert.lightDom.equal(
+ element,
+ /* HTML */ `
+ <div class="diffContainer newDiff sideBySide">
+ <gr-diff-section class="left-FILE right-FILE"> </gr-diff-section>
+ <gr-diff-row class="left-FILE right-FILE"> </gr-diff-row>
+ <table id="diffTable">
+ <colgroup>
+ <col class="blame gr-diff" />
+ <col class="gr-diff left" width="48" />
+ <col class="gr-diff left sign" />
+ <col class="gr-diff left" />
+ <col class="gr-diff right" width="48" />
+ <col class="gr-diff right sign" />
+ <col class="gr-diff right" />
+ </colgroup>
+ <tbody class="both gr-diff section">
+ <tr
+ aria-labelledby="left-button-FILE left-content-FILE right-button-FILE right-content-FILE"
+ class="diff-row gr-diff side-by-side"
+ left-type="both"
+ right-type="both"
+ tabindex="-1"
+ >
+ <td class="blame gr-diff" data-line-number="FILE"></td>
+ <td class="gr-diff left lineNum" data-value="FILE">
+ <button
+ aria-label="Add file comment"
+ class="gr-diff left lineNumButton"
+ data-value="FILE"
+ id="left-button-FILE"
+ tabindex="-1"
+ >
+ File
+ </button>
+ </td>
+ <td class="gr-diff left no-intraline-info sign"></td>
+ <td
+ class="both content file gr-diff left no-intraline-info"
+ >
+ <div class="thread-group" data-side="left">
+ <slot name="left-FILE"> </slot>
+ </div>
+ </td>
+ <td class="gr-diff lineNum right" data-value="FILE">
+ <button
+ aria-label="Add file comment"
+ class="gr-diff lineNumButton right"
+ data-value="FILE"
+ id="right-button-FILE"
+ tabindex="-1"
+ >
+ File
+ </button>
+ </td>
+ <td class="gr-diff no-intraline-info right sign"></td>
+ <td
+ class="both content file gr-diff no-intraline-info right"
+ >
+ <div class="thread-group" data-side="right">
+ <slot name="right-FILE"> </slot>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody class="binary-diff gr-diff">
+ <tr class="gr-diff">
+ <td class="gr-diff" colspan="5">
+ <span> Difference in binary files </span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ `
+ );
+ });
+ });
+
+ suite('image diffs', () => {
+ let mockFile1: ImageInfo;
+ let mockFile2: ImageInfo;
+ setup(() => {
+ mockFile1 = {
+ body:
+ 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' +
+ 'wsAAAAAAAAAAAAAAAAA/w==',
+ type: 'image/bmp',
+ };
+ mockFile2 = {
+ body:
+ 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' +
+ 'wsAAAAAAAAAAAAA/////w==',
+ type: 'image/bmp',
+ };
+
+ element.diffPrefs = {
+ context: 10,
+ cursor_blink_rate: 0,
+ font_size: 12,
+ ignore_whitespace: 'IGNORE_NONE',
+ line_length: 100,
+ line_wrapping: false,
+ show_line_endings: true,
+ show_tabs: true,
+ show_whitespace_errors: true,
+ syntax_highlighting: true,
+ tab_size: 8,
+ };
+ });
+
+ test('render image diff', async () => {
+ model.updateState({
+ diff: {
+ meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
+ meta_b: {
+ name: 'carrot.jpg',
+ content_type: 'image/jpeg',
+ lines: 560,
+ },
+ intraline_status: 'OK',
+ change_type: 'MODIFIED',
+ diff_header: [
+ 'diff --git a/carrot.jpg b/carrot.jpg',
+ 'index 2adc47d..f9c2f2c 100644',
+ '--- a/carrot.jpg',
+ '+++ b/carrot.jpg',
+ 'Binary files differ',
+ ],
+ content: [{skip: 66}],
+ binary: true,
+ },
+ diffPrefs: {...MINIMAL_PREFS},
+ renderPrefs: {view_mode: DiffViewMode.SIDE_BY_SIDE},
+ baseImage: mockFile1,
+ revisionImage: mockFile2,
+ });
+
+ await waitForEventOnce(element, 'render');
+ const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
+ assert.lightDom.equal(
+ imageDiffSection,
+ /* HTML */ `
+ <tbody class="gr-diff image-diff">
+ <tr class="gr-diff">
+ <td class="blank gr-diff left lineNum"></td>
+ <td class="gr-diff left">
+ <img
+ class="gr-diff left"
+ src="data:image/bmp;base64,${mockFile1.body}"
+ />
+ </td>
+ <td class="blank gr-diff lineNum right"></td>
+ <td class="gr-diff right">
+ <img
+ class="gr-diff right"
+ src="data:image/bmp;base64,${mockFile2.body}"
+ />
+ </td>
+ </tr>
+ <tr class="gr-diff">
+ <td class="blank gr-diff left lineNum"></td>
+ <td class="gr-diff left">
+ <label class="gr-diff">
+ <span class="gr-diff label"> 1×1 image/bmp </span>
+ </label>
+ </td>
+ <td class="blank gr-diff lineNum right"></td>
+ <td class="gr-diff right">
+ <label class="gr-diff">
+ <span class="gr-diff label"> 1×1 image/bmp </span>
+ </label>
+ </td>
+ </tr>
+ </tbody>
+ `
+ );
+ const endpoint = queryAndAssert(element, 'tbody.endpoint');
+ assert.dom.equal(
+ endpoint,
+ /* HTML */ `
+ <tbody class="gr-diff endpoint">
+ <tr class="gr-diff">
+ <gr-endpoint-decorator class="gr-diff" name="image-diff">
+ <gr-endpoint-param class="gr-diff" name="baseImage">
+ </gr-endpoint-param>
+ <gr-endpoint-param class="gr-diff" name="revisionImage">
+ </gr-endpoint-param>
+ </gr-endpoint-decorator>
+ </tr>
+ </tbody>
+ `
+ );
+ });
+
+ test('renders image diffs with a different file name', async () => {
+ model.updateState({
+ diff: {
+ meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
+ meta_b: {
+ name: 'carrot2.jpg',
+ content_type: 'image/jpeg',
+ lines: 560,
+ },
+ intraline_status: 'OK',
+ change_type: 'MODIFIED',
+ diff_header: [
+ 'diff --git a/carrot.jpg b/carrot2.jpg',
+ 'index 2adc47d..f9c2f2c 100644',
+ '--- a/carrot.jpg',
+ '+++ b/carrot2.jpg',
+ 'Binary files differ',
+ ],
+ content: [{skip: 66}],
+ binary: true,
+ },
+ diffPrefs: {...MINIMAL_PREFS},
+ renderPrefs: {view_mode: DiffViewMode.SIDE_BY_SIDE},
+ baseImage: {...mockFile1, _name: 'carrot.jpg'},
+ revisionImage: {...mockFile1, _name: 'carrot2.jpg'},
+ });
+
+ await waitForEventOnce(element, 'render');
+ const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
+ const leftLabel = queryAndAssert(imageDiffSection, 'td.left label');
+ const rightLabel = queryAndAssert(imageDiffSection, 'td.right label');
+ assert.dom.equal(
+ leftLabel,
+ /* HTML */ `
+ <label class="gr-diff">
+ <span class="gr-diff name"> carrot.jpg </span>
+ <br class="gr-diff" />
+ <span class="gr-diff label"> 1×1 image/bmp </span>
+ </label>
+ `
+ );
+ assert.dom.equal(
+ rightLabel,
+ /* HTML */ `
+ <label class="gr-diff">
+ <span class="gr-diff name"> carrot2.jpg </span>
+ <br class="gr-diff" />
+ <span class="gr-diff label"> 1×1 image/bmp </span>
+ </label>
+ `
+ );
+ });
+
+ test('renders added image', async () => {
+ model.updateState({
+ diff: {
+ meta_b: {
+ name: 'carrot.jpg',
+ content_type: 'image/jpeg',
+ lines: 560,
+ },
+ intraline_status: 'OK',
+ change_type: 'ADDED',
+ diff_header: [
+ 'diff --git a/carrot.jpg b/carrot.jpg',
+ 'index 0000000..f9c2f2c 100644',
+ '--- /dev/null',
+ '+++ b/carrot.jpg',
+ 'Binary files differ',
+ ],
+ content: [{skip: 66}],
+ binary: true,
+ },
+ diffPrefs: {...MINIMAL_PREFS},
+ renderPrefs: {view_mode: DiffViewMode.SIDE_BY_SIDE},
+ revisionImage: mockFile2,
+ });
+
+ await waitForEventOnce(element, 'render');
+ const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
+ const leftImage = query(imageDiffSection, 'td.left img');
+ const rightImage = queryAndAssert(imageDiffSection, 'td.right img');
+ assert.isNotOk(leftImage);
+ assert.dom.equal(
+ rightImage,
+ /* HTML */ `
+ <img
+ class="gr-diff right"
+ src="data:image/bmp;base64,${mockFile2.body}"
+ />
+ `
+ );
+ });
+
+ test('renders removed image', async () => {
+ model.updateState({
+ diff: {
+ meta_a: {
+ name: 'carrot.jpg',
+ content_type: 'image/jpeg',
+ lines: 560,
+ },
+ intraline_status: 'OK',
+ change_type: 'DELETED',
+ diff_header: [
+ 'diff --git a/carrot.jpg b/carrot.jpg',
+ 'index f9c2f2c..0000000 100644',
+ '--- a/carrot.jpg',
+ '+++ /dev/null',
+ 'Binary files differ',
+ ],
+ content: [{skip: 66}],
+ binary: true,
+ },
+ diffPrefs: {...MINIMAL_PREFS},
+ renderPrefs: {view_mode: DiffViewMode.SIDE_BY_SIDE},
+ baseImage: mockFile1,
+ });
+
+ await waitForEventOnce(element, 'render');
+ const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
+ const leftImage = queryAndAssert(imageDiffSection, 'td.left img');
+ const rightImage = query(imageDiffSection, 'td.right img');
+ assert.isNotOk(rightImage);
+ assert.dom.equal(
+ leftImage,
+ /* HTML */ `
+ <img
+ class="gr-diff left"
+ src="data:image/bmp;base64,${mockFile1.body}"
+ />
+ `
+ );
+ });
+
+ test('does not render disallowed image type', async () => {
+ model.updateState({
+ diff: {
+ meta_a: {
+ name: 'carrot.jpg',
+ content_type: 'image/jpeg-evil',
+ lines: 560,
+ },
+ intraline_status: 'OK',
+ change_type: 'DELETED',
+ diff_header: [
+ 'diff --git a/carrot.jpg b/carrot.jpg',
+ 'index f9c2f2c..0000000 100644',
+ '--- a/carrot.jpg',
+ '+++ /dev/null',
+ 'Binary files differ',
+ ],
+ content: [{skip: 66}],
+ binary: true,
+ },
+ diffPrefs: {...MINIMAL_PREFS},
+ renderPrefs: {view_mode: DiffViewMode.SIDE_BY_SIDE},
+ baseImage: {...mockFile1, type: 'image/jpeg-evil'},
+ });
+
+ await waitForEventOnce(element, 'render');
+ const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
+ const leftImage = query(imageDiffSection, 'td.left img');
+ assert.isNotOk(leftImage);
+ });
+ });
+ });
+
+ suite('diff header', () => {
+ setup(async () => {
+ model.updateState({
+ diff: {
+ meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
+ meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 560},
+ diff_header: [],
+ intraline_status: 'OK',
+ change_type: 'MODIFIED',
+ content: [{skip: 66}],
+ },
+ diffPrefs: {...MINIMAL_PREFS},
+ renderPrefs: {view_mode: DiffViewMode.SIDE_BY_SIDE},
+ });
+ await element.updateComplete;
+ });
+
+ test('hidden', async () => {
+ assert.equal(element.computeDiffHeaderItems().length, 0);
+ element.diff?.diff_header?.push('diff --git a/test.jpg b/test.jpg');
+ assert.equal(element.computeDiffHeaderItems().length, 0);
+ element.diff?.diff_header?.push('index 2adc47d..f9c2f2c 100644');
+ assert.equal(element.computeDiffHeaderItems().length, 0);
+ element.diff?.diff_header?.push('--- a/test.jpg');
+ assert.equal(element.computeDiffHeaderItems().length, 0);
+ element.diff?.diff_header?.push('+++ b/test.jpg');
+ assert.equal(element.computeDiffHeaderItems().length, 0);
+ element.diff?.diff_header?.push('test');
+ assert.equal(element.computeDiffHeaderItems().length, 1);
+ element.requestUpdate('diff');
+ await element.updateComplete;
+
+ const header = queryAndAssert(element, '#diffHeader');
+ assert.equal(header.textContent?.trim(), 'test');
+ });
+
+ test('binary files', () => {
+ element.diff!.binary = true;
+ assert.equal(element.computeDiffHeaderItems().length, 0);
+ element.diff?.diff_header?.push('diff --git a/test.jpg b/test.jpg');
+ assert.equal(element.computeDiffHeaderItems().length, 0);
+ element.diff?.diff_header?.push('test');
+ assert.equal(element.computeDiffHeaderItems().length, 1);
+ element.diff?.diff_header?.push('Binary files differ');
+ assert.equal(element.computeDiffHeaderItems().length, 1);
+ });
+ });
+
+ suite('trailing newline warnings', () => {
+ const NO_NEWLINE_LEFT = 'No newline at end of left file.';
+ const NO_NEWLINE_RIGHT = 'No newline at end of right file.';
+
+ const getWarning = (element: GrDiffElement) => {
+ const warningElement = query(element, '.newlineWarning');
+ return warningElement?.textContent ?? '';
+ };
+
+ test('shows combined warning if both sides set to warn', async () => {
+ model.updateState({
+ renderPrefs: {
+ show_newline_warning_left: true,
+ show_newline_warning_right: true,
+ },
+ });
+ await element.updateComplete;
+ assert.include(
+ getWarning(element),
+ NO_NEWLINE_LEFT + ' \u2014 ' + NO_NEWLINE_RIGHT
+ ); // \u2014 - '—'
+ });
+
+ suite('showNewlineWarningLeft', () => {
+ test('show warning if true', async () => {
+ model.updateState({
+ renderPrefs: {show_newline_warning_left: true},
+ });
+ await element.updateComplete;
+ assert.include(getWarning(element), NO_NEWLINE_LEFT);
+ });
+
+ test('hide warning if false', async () => {
+ model.updateState({
+ renderPrefs: {show_newline_warning_left: false},
+ });
+ await element.updateComplete;
+ assert.notInclude(getWarning(element), NO_NEWLINE_LEFT);
+ });
+ });
+
+ suite('showNewlineWarningRight', () => {
+ test('show warning if true', async () => {
+ model.updateState({
+ renderPrefs: {show_newline_warning_right: true},
+ });
+ await element.updateComplete;
+ assert.include(getWarning(element), NO_NEWLINE_RIGHT);
+ });
+
+ test('hide warning if false', async () => {
+ model.updateState({
+ renderPrefs: {show_newline_warning_right: false},
+ });
+ await element.updateComplete;
+ assert.notInclude(getWarning(element), NO_NEWLINE_RIGHT);
+ });
+ });
+ });
+
+ const setupSampleDiff = async function (params: {
+ content: DiffContent[];
+ ignore_whitespace?: IgnoreWhitespaceType;
+ binary?: boolean;
+ }) {
+ const {ignore_whitespace, content} = params;
+ // binary can't be undefined, use false if not set
+ const binary = params.binary || false;
+ const diffPrefs = {
+ ignore_whitespace: ignore_whitespace || 'IGNORE_ALL',
+ context: 10,
+ cursor_blink_rate: 0,
+ font_size: 12,
+
+ line_length: 100,
+ line_wrapping: false,
+ show_line_endings: true,
+ show_tabs: true,
+ show_whitespace_errors: true,
+ syntax_highlighting: true,
+ tab_size: 8,
+ };
+ const diff: DiffInfo = {
+ intraline_status: 'OK',
+ change_type: 'MODIFIED',
+ diff_header: [
+ 'diff --git a/carrot.js b/carrot.js',
+ 'index 2adc47d..f9c2f2c 100644',
+ '--- a/carrot.js',
+ '+++ b/carrot.jjs',
+ 'file differ',
+ ],
+ content,
+ binary,
+ };
+ model.updateState({diff, diffPrefs});
+ await waitUntil(() => element.groups.length > 1);
+ await element.updateComplete;
+ };
+
+ suite('whitespace changes only message', () => {
+ test('show the message if ignore_whitespace is criteria matches', async () => {
+ await setupSampleDiff({content: [{skip: 100}]});
+ element.loading = false;
+ assert.isTrue(element.showNoChangeMessage());
+ });
+
+ test('do not show the message for binary files', async () => {
+ await setupSampleDiff({content: [{skip: 100}], binary: true});
+ element.loading = false;
+ assert.isFalse(element.showNoChangeMessage());
+ });
+
+ test('do not show the message if still loading', async () => {
+ await setupSampleDiff({content: [{skip: 100}]});
+ element.loading = true;
+ assert.isFalse(element.showNoChangeMessage());
+ });
+
+ test('do not show the message if contains valid changes', async () => {
+ const content = [
+ {
+ a: ['all work and no play make andybons a dull boy'],
+ b: ['elgoog elgoog elgoog'],
+ },
+ {
+ ab: [
+ 'Non eram nescius, Brute, cum, quae summis ingeniis ',
+ 'exquisitaque doctrina philosophi Graeco sermone tractavissent',
+ ],
+ },
+ ];
+ await setupSampleDiff({content});
+ element.loading = false;
+ assert.isFalse(element.showNoChangeMessage());
+ });
+
+ test('do not show message if ignore whitespace is disabled', async () => {
+ const content = [
+ {
+ a: ['all work and no play make andybons a dull boy'],
+ b: ['elgoog elgoog elgoog'],
+ },
+ {
+ ab: [
+ 'Non eram nescius, Brute, cum, quae summis ingeniis ',
+ 'exquisitaque doctrina philosophi Graeco sermone tractavissent',
+ ],
+ },
+ ];
+ await setupSampleDiff({ignore_whitespace: 'IGNORE_NONE', content});
+ element.loading = false;
+ assert.isFalse(element.showNoChangeMessage());
+ });
+ });
+
+ suite('rendering text, images and binary files', () => {
+ let content: DiffContent[] = [];
+
+ setup(() => {
+ element.viewMode = DiffViewMode.SIDE_BY_SIDE;
+ element.diffPrefs = {
+ ...DEFAULT_PREFS,
+ context: -1,
+ syntax_highlighting: true,
+ };
+ content = [
+ {
+ a: ['all work and no play make andybons a dull boy'],
+ b: ['elgoog elgoog elgoog'],
+ },
+ {
+ ab: [
+ 'Non eram nescius, Brute, cum, quae summis ingeniis ',
+ 'exquisitaque doctrina philosophi Graeco sermone tractavissent',
+ ],
+ },
+ ];
+ });
+
+ test('text', async () => {
+ model.updateState({diff: {...createEmptyDiff(), content}});
+ await waitUntil(() => element.groups.length > 2);
+ await element.updateComplete;
+ const bodies = [...(querySelectorAll(element, 'tbody') ?? [])];
+ assert.equal(bodies.length, 4);
+ assert.isTrue(bodies[0].innerHTML.includes('LOST'));
+ assert.isTrue(bodies[1].innerHTML.includes('FILE'));
+ assert.isTrue(bodies[2].innerHTML.includes('andybons a dull boy'));
+ assert.isTrue(bodies[3].innerHTML.includes('Non eram nescius'));
+ });
+
+ test('image', async () => {
+ model.updateState({
+ diff: {
+ ...createEmptyDiff(),
+ content,
+ binary: true,
+ meta_a: {name: 'carrot1.jpg', content_type: 'image/jpeg', lines: 0},
+ meta_b: {name: 'carrot2.jpg', content_type: 'image/jpeg', lines: 0},
+ },
+ });
+ await element.updateComplete;
+ const body = queryAndAssert(element, 'tbody.image-diff');
+ assert.lightDom.equal(
+ body,
+ /* HTML */ `
+ <label class="gr-diff">
+ <span class="gr-diff label"> No image </span>
+ </label>
+ <label class="gr-diff">
+ <span class="gr-diff label"> No image </span>
+ </label>
+ `
+ );
+ });
+
+ test('binary', async () => {
+ element.diff = {...createEmptyDiff(), content, binary: true};
+ await element.updateComplete;
+ const body = queryAndAssert(element, 'tbody.binary-diff');
+ assert.lightDom.equal(
+ body,
+ /* HTML */ '<span>Difference in binary files</span>'
+ );
+ });
+ });
+});
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
index 2834f08..c118dd9 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
@@ -13,6 +13,7 @@
import '../gr-ranged-comment-hint/gr-ranged-comment-hint';
import '../gr-diff-builder/gr-diff-builder-image';
import '../gr-diff-builder/gr-diff-section';
+import './gr-diff-element';
import '../gr-diff-builder/gr-diff-row';
import {
getLine,
@@ -31,7 +32,6 @@
compareComments,
toCommentThreadModel,
FullContext,
- diffClasses,
DiffContextExpandedEventDetail,
} from '../gr-diff/gr-diff-utils';
import {BlameInfo, CommentRange, ImageInfo} from '../../../types/common';
@@ -45,11 +45,7 @@
CommentRangeLayer,
GrRangedCommentLayer,
} from '../gr-ranged-comment-layer/gr-ranged-comment-layer';
-import {
- DiffViewMode,
- Side,
- createDefaultDiffPrefs,
-} from '../../../constants/constants';
+import {DiffViewMode, Side} from '../../../constants/constants';
import {fire, fireAlert} from '../../../utils/event-util';
import {MovedLinkClickedEvent, ValueChangedEvent} from '../../../types/events';
import {getContentEditableRange} from '../../../utils/safari-selection-util';
@@ -65,19 +61,15 @@
import {isHtmlElement, isSafari, toggleClass} from '../../../utils/dom-util';
import {assertIsDefined} from '../../../utils/common-util';
import {GrDiffSelection} from '../gr-diff-selection/gr-diff-selection';
-import {property, query, queryAll, state} from 'lit/decorators.js';
+import {property, query, state} from 'lit/decorators.js';
import {sharedStyles} from '../../../styles/shared-styles';
-import {html, LitElement, nothing, PropertyValues} from 'lit';
-import {when} from 'lit/directives/when.js';
+import {html, LitElement, PropertyValues} from 'lit';
import {grSyntaxTheme} from '../gr-syntax-themes/gr-syntax-theme';
import {grRangedCommentTheme} from '../gr-ranged-comment-themes/gr-ranged-comment-theme';
-import {classMap} from 'lit/directives/class-map.js';
import {iconStyles} from '../../../styles/gr-icon-styles';
-import {expandFileMode} from '../../../utils/file-util';
import {DiffModel, diffModelToken} from '../gr-diff-model/gr-diff-model';
import {provide} from '../../../models/dependency';
import {grDiffStyles} from './gr-diff-styles';
-import {getDiffLength} from '../../../utils/diff-util';
import {GrCoverageLayer} from '../gr-coverage-layer/gr-coverage-layer';
import {
GrAnnotationImpl,
@@ -92,16 +84,10 @@
import {subscribe} from '../../../elements/lit/subscription-controller';
import {GrDiffSection} from '../gr-diff-builder/gr-diff-section';
import {GrDiffRow} from '../gr-diff-builder/gr-diff-row';
-import {repeat} from 'lit/directives/repeat.js';
+import {GrDiffElement} from './gr-diff-element';
const TRAILING_WHITESPACE_PATTERN = /\s+$/;
-const NO_NEWLINE_LEFT = 'No newline at end of left file.';
-const NO_NEWLINE_RIGHT = 'No newline at end of right file.';
-
-const LARGE_DIFF_THRESHOLD_LINES = 10000;
-const FULL_CONTEXT = -1;
-
const COMMIT_MSG_PATH = '/COMMIT_MSG';
/**
* 72 is the unofficial length standard for git commit messages.
@@ -146,11 +132,17 @@
* @event diff-context-expanded
*/
- @query('#diffTable')
- diffTable?: HTMLTableElement;
+ /**
+ * Deprecated. Use `diffElement` instead.
+ *
+ * TODO: Migrate to new diff. Remove dependency on this property from external
+ * gr-diff users that instantiate TokenHighlightLayer.
+ */
+ @query('gr-diff-element')
+ diffTable?: HTMLElement;
- @queryAll('gr-diff-section')
- diffSections?: NodeListOf<GrDiffSection>;
+ @query('gr-diff-element')
+ diffElement?: GrDiffElement;
@property({type: Boolean})
noAutoRender = false;
@@ -217,9 +209,6 @@
@property({type: Object})
diff?: DiffInfo;
- @state()
- private diffTableClass = '';
-
@property({type: Object})
baseImage?: ImageInfo;
@@ -262,11 +251,12 @@
// Private but used in tests.
highlights = new GrDiffHighlight();
- private diffModel = new DiffModel();
+ // Private but used in tests.
+ diffModel = new DiffModel();
/**
- * Just the layers that are passed in from the outside. See `layersAll`
- * for an array of all layers.
+ * Just the layers that are passed in from the outside. Will be joined with
+ * `layersInternal` and sent to the diff model.
*/
@property({type: Array})
layers: DiffLayer[] = [];
@@ -275,12 +265,7 @@
* Just the internal default layers. See `layers` for the property that can
* be set from the outside.
*/
- @state() layersInternal: DiffLayer[] = [];
-
- /**
- * All layers, just combines `layers` and `layersInternal`.
- */
- @state() layersAll: DiffLayer[] = [];
+ private layersInternal: DiffLayer[] = [];
private coverageLayerLeft = new GrCoverageLayer(Side.LEFT);
@@ -346,11 +331,11 @@
if (this.loggedIn) {
this.addSelectionListeners();
}
- if (this.diff && this.diffTable) {
- this.diffSelection.init(this.diff, this.diffTable);
+ if (this.diff && this.diffElement) {
+ this.diffSelection.init(this.diff, this.diffElement);
}
- if (this.diffTable) {
- this.highlights.init(this.diffTable, this);
+ if (this.diffElement) {
+ this.highlights.init(this.diffElement, this);
}
}
@@ -385,6 +370,12 @@
});
}
}
+ if (changedProperties.has('baseImage')) {
+ this.diffModel.updateState({baseImage: this.baseImage});
+ }
+ if (changedProperties.has('revisionImage')) {
+ this.diffModel.updateState({revisionImage: this.revisionImage});
+ }
if (
changedProperties.has('path') ||
changedProperties.has('lineWrapping') ||
@@ -418,119 +409,28 @@
}
}
- private async fireRenderContent() {
- await this.updateComplete;
- this.loading = false;
- this.observeNodes();
- // TODO: Retire one of these two events.
- fire(this, 'render-content', {});
- fire(this, 'render', {});
- }
-
protected override async getUpdateComplete(): Promise<boolean> {
const result = await super.getUpdateComplete();
- const sections = [...(this.diffSections ?? [])];
- await Promise.all(sections.map(section => section.updateComplete));
+ await this.diffElement?.updateComplete;
return result;
}
protected override updated(changedProperties: PropertyValues<this>) {
if (changedProperties.has('diff')) {
- // diffChanged relies on diffTable having been rendered.
+ // diffChanged relies on diffElement having been rendered.
this.diffChanged();
}
if (changedProperties.has('groups')) {
- if (this.groups?.length > 0) this.fireRenderContent();
+ if (this.groups?.length > 0) {
+ this.loading = false;
+ this.observeNodes();
+ }
}
}
override render() {
- fire(this.diffTable, 'render-start', {});
- return html`
- ${this.renderHeader()} ${this.renderContainer()}
- ${this.renderNewlineWarning()} ${this.renderLoadingError()}
- `;
- }
-
- private renderHeader() {
- const diffheaderItems = this.computeDiffHeaderItems();
- if (diffheaderItems.length === 0) return nothing;
- return html`
- <div id="diffHeader">
- ${diffheaderItems.map(item => html`<div>${item}</div>`)}
- </div>
- `;
- }
-
- private renderContainer() {
- const cssClasses = {
- newDiff: true,
- diffContainer: true,
- unified: this.viewMode === DiffViewMode.UNIFIED,
- sideBySide: this.viewMode === DiffViewMode.SIDE_BY_SIDE,
- canComment: this.loggedIn,
- };
- return html`
- <div class=${classMap(cssClasses)} @click=${this.handleTap}>
- <table
- id="diffTable"
- class=${this.diffTableClass}
- ?contenteditable=${this.isContentEditable}
- >
- ${this.renderColumns()}
- ${when(!this.showWarning(), () =>
- repeat(
- this.groups,
- group => group.id(),
- group => this.renderSectionElement(group)
- )
- )}
- ${when(this.diff?.binary, () =>
- this.isImageDiff ? this.renderImageDiff() : this.renderBinaryDiff()
- )}
- </table>
- ${when(
- this.showNoChangeMessage(),
- () => html`
- <div class="whitespace-change-only-message">
- This file only contains whitespace changes. Modify the whitespace
- setting to see the changes.
- </div>
- `
- )}
- ${when(this.showWarning(), () => this.renderSizeWarning())}
- </div>
- `;
- }
-
- private renderNewlineWarning() {
- const newlineWarning = this.computeNewlineWarning();
- if (!newlineWarning) return nothing;
- return html`<div class="newlineWarning">${newlineWarning}</div>`;
- }
-
- private renderLoadingError() {
- if (!this.errorMessage) return nothing;
- return html`<div id="loadingError">${this.errorMessage}</div>`;
- }
-
- private renderSizeWarning() {
- if (!this.showWarning()) return nothing;
- // TODO: Update comment about 'Whole file' as it's not in settings.
- return html`
- <div id="sizeWarning">
- <p>
- Prevented render because "Whole file" is enabled and this diff is very
- large (about ${this.diffLength} lines).
- </p>
- <gr-button @click=${this.collapseContext}>
- Render with limited context
- </gr-button>
- <gr-button @click=${this.handleFullBypass}>
- Render anyway (may be slow)
- </gr-button>
- </div>
- `;
+ fire(this, 'render-start', {});
+ return html`<gr-diff-element @click=${this.handleTap}></gr-diff-element>`;
}
private addSelectionListeners() {
@@ -543,18 +443,6 @@
document.removeEventListener('mouseup', this.handleMouseUp);
}
- // Private but used in tests.
- showNoChangeMessage() {
- return (
- !this.loading &&
- this.diff &&
- !this.diff.binary &&
- this.prefs &&
- this.prefs.ignore_whitespace !== 'IGNORE_NONE' &&
- this.diffLength === 0
- );
- }
-
private readonly handleSelectionChange = () => {
// Because of shadow DOM selections, we handle the selectionchange here,
// and pass the shadow DOM selection into gr-diff-highlight, where the
@@ -813,7 +701,6 @@
const responsiveMode = getResponsiveMode(this.prefs, this.renderPrefs);
const responsive = isResponsive(responsiveMode);
- this.diffTableClass = responsive ? 'responsive' : '';
const lineLimit = `${lineLength}ch`;
this.style.setProperty(
'--line-limit-marker',
@@ -884,27 +771,12 @@
private diffChanged() {
this.loading = true;
if (this.diff) {
- this.diffLength = this.getDiffLength(this.diff);
- assertIsDefined(this.diffTable, 'diffTable');
- this.diffSelection.init(this.diff, this.diffTable);
- this.highlights.init(this.diffTable, this);
+ assertIsDefined(this.diffElement, 'diffElement');
+ this.diffSelection.init(this.diff, this.diffElement);
+ this.highlights.init(this.diffElement, this);
}
}
- // Implemented so the test can stub it.
- getDiffLength(diff?: DiffInfo) {
- return getDiffLength(diff);
- }
-
- private showWarning() {
- return (
- this.prefs?.context === FULL_CONTEXT &&
- this.diffModel.getState().showFullContext === FullContext.UNDECIDED &&
- this.diffLength &&
- this.diffLength >= LARGE_DIFF_THRESHOLD_LINES
- );
- }
-
/**
* This must be called once, but only after diff lines are rendered. Otherwise
* `processNodes()` will fail to lookup the HTML elements that it wants to
@@ -1009,30 +881,6 @@
/** TODO: Can be removed when diff-old is gone. */
clearDiffContent() {}
- // Private but used in tests.
- computeDiffHeaderItems() {
- return (this.diff?.diff_header ?? [])
- .filter(
- item =>
- !(
- item.startsWith('diff --git ') ||
- item.startsWith('index ') ||
- item.startsWith('+++ ') ||
- item.startsWith('--- ') ||
- item === 'Binary files differ'
- )
- )
- .map(expandFileMode);
- }
-
- private handleFullBypass() {
- this.diffModel.updateState({showFullContext: FullContext.YES});
- }
-
- private collapseContext() {
- this.diffModel.updateState({showFullContext: FullContext.NO});
- }
-
// TODO: Migrate callers to just update prefs.context.
toggleAllContext() {
const current = this.diffModel.getState().showFullContext;
@@ -1042,65 +890,11 @@
});
}
- private computeNewlineWarning(): string | undefined {
- const messages = [];
- if (this.showNewlineWarningLeft) {
- messages.push(NO_NEWLINE_LEFT);
- }
- if (this.showNewlineWarningRight) {
- messages.push(NO_NEWLINE_RIGHT);
- }
- if (!messages.length) {
- return undefined;
- }
- return messages.join(' \u2014 '); // \u2014 - '—'
- }
-
private updateCoverageRanges(rs: CoverageRange[]) {
this.coverageLayerLeft.setRanges(rs.filter(r => r?.side === Side.LEFT));
this.coverageLayerRight.setRanges(rs.filter(r => r?.side === Side.RIGHT));
}
- public renderImageDiff() {
- return when(
- this.useNewImageDiffUi,
- () => this.renderImageDiffNew(),
- () => this.renderImageDiffOld()
- );
- }
-
- private renderImageDiffNew() {
- const autoBlink = !!this.renderPrefs?.image_diff_prefs?.automatic_blink;
- return html`
- <gr-diff-image-new
- .automaticBlink=${autoBlink}
- .baseImage=${this.baseImage ?? undefined}
- .revisionImage=${this.revisionImage ?? undefined}
- ></gr-diff-image-new>
- `;
- }
-
- private renderImageDiffOld() {
- return html`
- <gr-diff-image-old
- .baseImage=${this.baseImage ?? undefined}
- .revisionImage=${this.revisionImage ?? undefined}
- ></gr-diff-image-old>
- `;
- }
-
- public renderBinaryDiff() {
- return html`
- <tbody class="gr-diff binary-diff">
- <tr class="gr-diff">
- <td colspan="5" class="gr-diff">
- <span>Difference in binary files</span>
- </td>
- </tr>
- </tbody>
- `;
- }
-
private onDiffContextExpanded = (
e: CustomEvent<DiffContextExpandedEventDetail>
) => {
@@ -1110,11 +904,12 @@
};
private layersChanged() {
- this.layersAll = [...this.layersInternal, ...this.layers];
- for (const layer of this.layersAll) {
+ const layers = [...this.layersInternal, ...this.layers];
+ for (const layer of layers) {
layer.removeListener?.(this.layerUpdateListener);
layer.addListener?.(this.layerUpdateListener);
}
+ this.diffModel.updateState({layers});
}
private layersInternalInit() {
@@ -1298,10 +1093,8 @@
}
private getDiffRows() {
- assertIsDefined(this.diffTable, 'diffTable');
- const sections = [
- ...this.diffTable.querySelectorAll<GrDiffSection>('gr-diff-section'),
- ];
+ assertIsDefined(this.diffElement, 'diffElement');
+ const sections = [...(this.diffElement.diffSections ?? [])];
return sections.map(s => s.getDiffRows()).flat();
}
@@ -1327,70 +1120,16 @@
}
private findSection(group: GrDiffGroup): GrDiffSection | undefined {
- assertIsDefined(this.diffTable, 'diffTable');
+ assertIsDefined(this.diffElement, 'diffElement');
const leftClass = `left-${group.startLine(Side.LEFT)}`;
const rightClass = `right-${group.startLine(Side.RIGHT)}`;
return (
- this.diffTable.querySelector<GrDiffSection>(
+ this.diffElement.querySelector<GrDiffSection>(
`gr-diff-section.${leftClass}.${rightClass}`
) ?? undefined
);
}
- renderSectionElement(group: GrDiffGroup) {
- const leftClass = `left-${group.startLine(Side.LEFT)}`;
- const rightClass = `right-${group.startLine(Side.RIGHT)}`;
- if (this.diff?.binary && group.startLine(Side.LEFT) === LOST) {
- return nothing;
- }
- return html`
- <gr-diff-section
- class="${leftClass} ${rightClass}"
- .group=${group}
- .diff=${this.diff}
- .layers=${this.layersAll}
- .diffPrefs=${this.prefs}
- .renderPrefs=${this.renderPrefs}
- ></gr-diff-section>
- `;
- }
-
- renderColumns() {
- const lineNumberWidth = getLineNumberCellWidth(
- this.prefs ?? createDefaultDiffPrefs()
- );
- return html`
- <colgroup>
- <col class=${diffClasses('blame')}></col>
- ${when(
- (this.renderPrefs?.view_mode ?? this.viewMode) ===
- DiffViewMode.UNIFIED,
- () => html` ${this.renderUnifiedColumns(lineNumberWidth)} `,
- () => html`
- ${this.renderSideBySideColumns(Side.LEFT, lineNumberWidth)}
- ${this.renderSideBySideColumns(Side.RIGHT, lineNumberWidth)}
- `
- )}
- </colgroup>
- `;
- }
-
- private renderUnifiedColumns(lineNumberWidth: number) {
- return html`
- <col class=${diffClasses()} width=${lineNumberWidth}></col>
- <col class=${diffClasses()} width=${lineNumberWidth}></col>
- <col class=${diffClasses()}></col>
- `;
- }
-
- private renderSideBySideColumns(side: Side, lineNumberWidth: number) {
- return html`
- <col class=${diffClasses(side)} width=${lineNumberWidth}></col>
- <col class=${diffClasses(side, 'sign')}></col>
- <col class=${diffClasses(side)}></col>
- `;
- }
-
findGroup(side: Side, line: LineNumber) {
return this.groups.find(group => group.containsLine(side, line));
}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.ts
index 30f85cc..48370411 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.ts
@@ -10,11 +10,10 @@
createEmptyDiff,
} from '../../../test/test-data-generators';
import './gr-diff';
-import {getComputedStyleValue, querySelectorAll} from '../../../utils/dom-util';
+import {getComputedStyleValue} from '../../../utils/dom-util';
import '@polymer/paper-button/paper-button';
import {
DiffContent,
- DiffInfo,
DiffLayer,
DiffPreferencesInfo,
DiffViewMode,
@@ -25,22 +24,17 @@
import {
mockPromise,
mouseDown,
- query,
queryAll,
- queryAndAssert,
stubBaseUrl,
stubRestApi,
waitQueryAndAssert,
waitUntil,
} from '../../../test/test-utils';
import {AbortStop} from '../../../api/core';
-import {waitForEventOnce} from '../../../utils/event-util';
import {GrDiff} from './gr-diff';
-import {ImageInfo} from '../../../types/common';
import {GrRangedCommentHint} from '../gr-ranged-comment-hint/gr-ranged-comment-hint';
import {fixture, html, assert} from '@open-wc/testing';
import {createDefaultDiffPrefs} from '../../../constants/constants';
-import {GrDiffRow} from '../gr-diff-builder/gr-diff-row';
import {
GrAnnotationImpl,
getStringLength,
@@ -70,2953 +64,6 @@
element = await fixture<GrDiff>(html`<gr-diff></gr-diff>`);
});
- suite('rendering', () => {
- test('empty diff', async () => {
- await element.updateComplete;
- assert.shadowDom.equal(
- element,
- /* HTML */ `
- <div class="diffContainer newDiff sideBySide">
- <table id="diffTable">
- <colgroup>
- <col class="blame gr-diff" />
- <col class="gr-diff left" width="48" />
- <col class="gr-diff left sign" />
- <col class="gr-diff left" />
- <col class="gr-diff right" width="48" />
- <col class="gr-diff right sign" />
- <col class="gr-diff right" />
- </colgroup>
- </table>
- </div>
- `
- );
- });
-
- test('a unified diff lit', async () => {
- element.viewMode = DiffViewMode.UNIFIED;
- element.prefs = {...MINIMAL_PREFS};
- element.diff = createDiff();
- await element.updateComplete;
- await waitForEventOnce(element, 'render');
- assert.shadowDom.equal(
- element,
- /* HTML */ `
- <div class="diffContainer newDiff unified">
- <table class="selected-right" id="diffTable">
- <colgroup>
- <col class="blame gr-diff" />
- <col class="gr-diff" width="48" />
- <col class="gr-diff" width="48" />
- <col class="gr-diff" />
- </colgroup>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-LOST right-button-LOST right-content-LOST"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="LOST"></td>
- <td class="gr-diff left lineNum" data-value="LOST"></td>
- <td class="gr-diff lineNum right" data-value="LOST"></td>
- <td class="both content gr-diff lost no-intraline-info right">
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-FILE right-button-FILE right-content-FILE"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="FILE"></td>
- <td class="gr-diff left lineNum" data-value="FILE">
- <button
- aria-label="Add file comment"
- class="gr-diff left lineNumButton"
- data-value="FILE"
- id="left-button-FILE"
- tabindex="-1"
- >
- File
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="FILE">
- <button
- aria-label="Add file comment"
- class="gr-diff lineNumButton right"
- data-value="FILE"
- id="right-button-FILE"
- tabindex="-1"
- >
- File
- </button>
- </td>
- <td class="both content file gr-diff no-intraline-info right">
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-1 right-button-1 right-content-1"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="1"></td>
- <td class="gr-diff left lineNum" data-value="1">
- <button
- aria-label="1 unmodified"
- class="gr-diff left lineNumButton"
- data-value="1"
- id="left-button-1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="1">
- <button
- aria-label="1 unmodified"
- class="gr-diff lineNumButton right"
- data-value="1"
- id="right-button-1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-1"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-2 right-button-2 right-content-2"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="2"></td>
- <td class="gr-diff left lineNum" data-value="2">
- <button
- aria-label="2 unmodified"
- class="gr-diff left lineNumButton"
- data-value="2"
- id="left-button-2"
- tabindex="-1"
- >
- 2
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="2">
- <button
- aria-label="2 unmodified"
- class="gr-diff lineNumButton right"
- data-value="2"
- id="right-button-2"
- tabindex="-1"
- >
- 2
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-2"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-3 right-button-3 right-content-3"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="3"></td>
- <td class="gr-diff left lineNum" data-value="3">
- <button
- aria-label="3 unmodified"
- class="gr-diff left lineNumButton"
- data-value="3"
- id="left-button-3"
- tabindex="-1"
- >
- 3
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="3">
- <button
- aria-label="3 unmodified"
- class="gr-diff lineNumButton right"
- data-value="3"
- id="right-button-3"
- tabindex="-1"
- >
- 3
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-3"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-4 right-button-4 right-content-4"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="4"></td>
- <td class="gr-diff left lineNum" data-value="4">
- <button
- aria-label="4 unmodified"
- class="gr-diff left lineNumButton"
- data-value="4"
- id="left-button-4"
- tabindex="-1"
- >
- 4
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="4">
- <button
- aria-label="4 unmodified"
- class="gr-diff lineNumButton right"
- data-value="4"
- id="right-button-4"
- tabindex="-1"
- >
- 4
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-4"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="delta gr-diff section total">
- <tr
- aria-labelledby="right-button-5 right-content-5"
- class="add diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="gr-diff left"></td>
- <td class="gr-diff lineNum right" data-value="5">
- <button
- aria-label="5 added"
- class="gr-diff lineNumButton right"
- data-value="5"
- id="right-button-5"
- tabindex="-1"
- >
- 5
- </button>
- </td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-5"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="right-button-6 right-content-6"
- class="add diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="gr-diff left"></td>
- <td class="gr-diff lineNum right" data-value="6">
- <button
- aria-label="6 added"
- class="gr-diff lineNumButton right"
- data-value="6"
- id="right-button-6"
- tabindex="-1"
- >
- 6
- </button>
- </td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-6"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="right-button-7 right-content-7"
- class="add diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="gr-diff left"></td>
- <td class="gr-diff lineNum right" data-value="7">
- <button
- aria-label="7 added"
- class="gr-diff lineNumButton right"
- data-value="7"
- id="right-button-7"
- tabindex="-1"
- >
- 7
- </button>
- </td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-7"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-5 right-button-8 right-content-8"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="5"></td>
- <td class="gr-diff left lineNum" data-value="5">
- <button
- aria-label="5 unmodified"
- class="gr-diff left lineNumButton"
- data-value="5"
- id="left-button-5"
- tabindex="-1"
- >
- 5
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="8">
- <button
- aria-label="8 unmodified"
- class="gr-diff lineNumButton right"
- data-value="8"
- id="right-button-8"
- tabindex="-1"
- >
- 8
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-8"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-6 right-button-9 right-content-9"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="6"></td>
- <td class="gr-diff left lineNum" data-value="6">
- <button
- aria-label="6 unmodified"
- class="gr-diff left lineNumButton"
- data-value="6"
- id="left-button-6"
- tabindex="-1"
- >
- 6
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="9">
- <button
- aria-label="9 unmodified"
- class="gr-diff lineNumButton right"
- data-value="9"
- id="right-button-9"
- tabindex="-1"
- >
- 9
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-9"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-7 right-button-10 right-content-10"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="7"></td>
- <td class="gr-diff left lineNum" data-value="7">
- <button
- aria-label="7 unmodified"
- class="gr-diff left lineNumButton"
- data-value="7"
- id="left-button-7"
- tabindex="-1"
- >
- 7
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="10">
- <button
- aria-label="10 unmodified"
- class="gr-diff lineNumButton right"
- data-value="10"
- id="right-button-10"
- tabindex="-1"
- >
- 10
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-10"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-8 right-button-11 right-content-11"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="8"></td>
- <td class="gr-diff left lineNum" data-value="8">
- <button
- aria-label="8 unmodified"
- class="gr-diff left lineNumButton"
- data-value="8"
- id="left-button-8"
- tabindex="-1"
- >
- 8
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="11">
- <button
- aria-label="11 unmodified"
- class="gr-diff lineNumButton right"
- data-value="11"
- id="right-button-11"
- tabindex="-1"
- >
- 11
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-11"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-9 right-button-12 right-content-12"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="9"></td>
- <td class="gr-diff left lineNum" data-value="9">
- <button
- aria-label="9 unmodified"
- class="gr-diff left lineNumButton"
- data-value="9"
- id="left-button-9"
- tabindex="-1"
- >
- 9
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="12">
- <button
- aria-label="12 unmodified"
- class="gr-diff lineNumButton right"
- data-value="12"
- id="right-button-12"
- tabindex="-1"
- >
- 12
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-12"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="delta gr-diff section total">
- <tr
- aria-labelledby="left-button-10 left-content-10"
- class="diff-row gr-diff remove unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="10"></td>
- <td class="gr-diff left lineNum" data-value="10">
- <button
- aria-label="10 removed"
- class="gr-diff left lineNumButton"
- data-value="10"
- id="left-button-10"
- tabindex="-1"
- >
- 10
- </button>
- </td>
- <td class="gr-diff right"></td>
- <td class="content gr-diff left no-intraline-info remove">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-10"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-11 left-content-11"
- class="diff-row gr-diff remove unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="11"></td>
- <td class="gr-diff left lineNum" data-value="11">
- <button
- aria-label="11 removed"
- class="gr-diff left lineNumButton"
- data-value="11"
- id="left-button-11"
- tabindex="-1"
- >
- 11
- </button>
- </td>
- <td class="gr-diff right"></td>
- <td class="content gr-diff left no-intraline-info remove">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-11"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-12 left-content-12"
- class="diff-row gr-diff remove unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="12"></td>
- <td class="gr-diff left lineNum" data-value="12">
- <button
- aria-label="12 removed"
- class="gr-diff left lineNumButton"
- data-value="12"
- id="left-button-12"
- tabindex="-1"
- >
- 12
- </button>
- </td>
- <td class="gr-diff right"></td>
- <td class="content gr-diff left no-intraline-info remove">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-12"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-13 left-content-13"
- class="diff-row gr-diff remove unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="13"></td>
- <td class="gr-diff left lineNum" data-value="13">
- <button
- aria-label="13 removed"
- class="gr-diff left lineNumButton"
- data-value="13"
- id="left-button-13"
- tabindex="-1"
- >
- 13
- </button>
- </td>
- <td class="gr-diff right"></td>
- <td class="content gr-diff left no-intraline-info remove">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-13"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="delta gr-diff ignoredWhitespaceOnly section">
- <tr
- aria-labelledby="right-button-13 right-content-13"
- class="add diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="gr-diff left"></td>
- <td class="gr-diff lineNum right" data-value="13">
- <button
- aria-label="13 added"
- class="gr-diff lineNumButton right"
- data-value="13"
- id="right-button-13"
- tabindex="-1"
- >
- 13
- </button>
- </td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-13"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="right-button-14 right-content-14"
- class="add diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="gr-diff left"></td>
- <td class="gr-diff lineNum right" data-value="14">
- <button
- aria-label="14 added"
- class="gr-diff lineNumButton right"
- data-value="14"
- id="right-button-14"
- tabindex="-1"
- >
- 14
- </button>
- </td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-14"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="delta gr-diff section">
- <tr
- aria-labelledby="left-button-16 left-content-16"
- class="diff-row gr-diff remove unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="16"></td>
- <td class="gr-diff left lineNum" data-value="16">
- <button
- aria-label="16 removed"
- class="gr-diff left lineNumButton"
- data-value="16"
- id="left-button-16"
- tabindex="-1"
- >
- 16
- </button>
- </td>
- <td class="gr-diff right"></td>
- <td class="content gr-diff left remove">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-16"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="right-button-15 right-content-15"
- class="add diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="gr-diff left"></td>
- <td class="gr-diff lineNum right" data-value="15">
- <button
- aria-label="15 added"
- class="gr-diff lineNumButton right"
- data-value="15"
- id="right-button-15"
- tabindex="-1"
- >
- 15
- </button>
- </td>
- <td class="add content gr-diff right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-15"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-17 right-button-16 right-content-16"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="17"></td>
- <td class="gr-diff left lineNum" data-value="17">
- <button
- aria-label="17 unmodified"
- class="gr-diff left lineNumButton"
- data-value="17"
- id="left-button-17"
- tabindex="-1"
- >
- 17
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="16">
- <button
- aria-label="16 unmodified"
- class="gr-diff lineNumButton right"
- data-value="16"
- id="right-button-16"
- tabindex="-1"
- >
- 16
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-16"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-18 right-button-17 right-content-17"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="18"></td>
- <td class="gr-diff left lineNum" data-value="18">
- <button
- aria-label="18 unmodified"
- class="gr-diff left lineNumButton"
- data-value="18"
- id="left-button-18"
- tabindex="-1"
- >
- 18
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="17">
- <button
- aria-label="17 unmodified"
- class="gr-diff lineNumButton right"
- data-value="17"
- id="right-button-17"
- tabindex="-1"
- >
- 17
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-17"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-19 right-button-18 right-content-18"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="19"></td>
- <td class="gr-diff left lineNum" data-value="19">
- <button
- aria-label="19 unmodified"
- class="gr-diff left lineNumButton"
- data-value="19"
- id="left-button-19"
- tabindex="-1"
- >
- 19
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="18">
- <button
- aria-label="18 unmodified"
- class="gr-diff lineNumButton right"
- data-value="18"
- id="right-button-18"
- tabindex="-1"
- >
- 18
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-18"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="contextControl gr-diff section">
- <tr class="above contextBackground gr-diff unified">
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="contextLineNum gr-diff"></td>
- <td class="contextLineNum gr-diff"></td>
- <td class="gr-diff"></td>
- </tr>
- <tr class="dividerRow gr-diff show-both">
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="dividerCell gr-diff" colspan="3">
- <gr-context-controls class="gr-diff" showconfig="both">
- </gr-context-controls>
- </td>
- </tr>
- <tr class="below contextBackground gr-diff unified">
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="contextLineNum gr-diff"></td>
- <td class="contextLineNum gr-diff"></td>
- <td class="gr-diff"></td>
- </tr>
- </tbody>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-38 right-button-37 right-content-37"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="38"></td>
- <td class="gr-diff left lineNum" data-value="38">
- <button
- aria-label="38 unmodified"
- class="gr-diff left lineNumButton"
- data-value="38"
- id="left-button-38"
- tabindex="-1"
- >
- 38
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="37">
- <button
- aria-label="37 unmodified"
- class="gr-diff lineNumButton right"
- data-value="37"
- id="right-button-37"
- tabindex="-1"
- >
- 37
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-37"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-39 right-button-38 right-content-38"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="39"></td>
- <td class="gr-diff left lineNum" data-value="39">
- <button
- aria-label="39 unmodified"
- class="gr-diff left lineNumButton"
- data-value="39"
- id="left-button-39"
- tabindex="-1"
- >
- 39
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="38">
- <button
- aria-label="38 unmodified"
- class="gr-diff lineNumButton right"
- data-value="38"
- id="right-button-38"
- tabindex="-1"
- >
- 38
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-38"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-40 right-button-39 right-content-39"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="40"></td>
- <td class="gr-diff left lineNum" data-value="40">
- <button
- aria-label="40 unmodified"
- class="gr-diff left lineNumButton"
- data-value="40"
- id="left-button-40"
- tabindex="-1"
- >
- 40
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="39">
- <button
- aria-label="39 unmodified"
- class="gr-diff lineNumButton right"
- data-value="39"
- id="right-button-39"
- tabindex="-1"
- >
- 39
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-39"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="delta gr-diff section total">
- <tr
- aria-labelledby="right-button-40 right-content-40"
- class="add diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="gr-diff left"></td>
- <td class="gr-diff lineNum right" data-value="40">
- <button
- aria-label="40 added"
- class="gr-diff lineNumButton right"
- data-value="40"
- id="right-button-40"
- tabindex="-1"
- >
- 40
- </button>
- </td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-40"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="right-button-41 right-content-41"
- class="add diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="gr-diff left"></td>
- <td class="gr-diff lineNum right" data-value="41">
- <button
- aria-label="41 added"
- class="gr-diff lineNumButton right"
- data-value="41"
- id="right-button-41"
- tabindex="-1"
- >
- 41
- </button>
- </td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-41"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="right-button-42 right-content-42"
- class="add diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="gr-diff left"></td>
- <td class="gr-diff lineNum right" data-value="42">
- <button
- aria-label="42 added"
- class="gr-diff lineNumButton right"
- data-value="42"
- id="right-button-42"
- tabindex="-1"
- >
- 42
- </button>
- </td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-42"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="right-button-43 right-content-43"
- class="add diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="gr-diff left"></td>
- <td class="gr-diff lineNum right" data-value="43">
- <button
- aria-label="43 added"
- class="gr-diff lineNumButton right"
- data-value="43"
- id="right-button-43"
- tabindex="-1"
- >
- 43
- </button>
- </td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-43"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-41 right-button-44 right-content-44"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="41"></td>
- <td class="gr-diff left lineNum" data-value="41">
- <button
- aria-label="41 unmodified"
- class="gr-diff left lineNumButton"
- data-value="41"
- id="left-button-41"
- tabindex="-1"
- >
- 41
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="44">
- <button
- aria-label="44 unmodified"
- class="gr-diff lineNumButton right"
- data-value="44"
- id="right-button-44"
- tabindex="-1"
- >
- 44
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-44"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-42 right-button-45 right-content-45"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="42"></td>
- <td class="gr-diff left lineNum" data-value="42">
- <button
- aria-label="42 unmodified"
- class="gr-diff left lineNumButton"
- data-value="42"
- id="left-button-42"
- tabindex="-1"
- >
- 42
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="45">
- <button
- aria-label="45 unmodified"
- class="gr-diff lineNumButton right"
- data-value="45"
- id="right-button-45"
- tabindex="-1"
- >
- 45
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-45"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-43 right-button-46 right-content-46"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="43"></td>
- <td class="gr-diff left lineNum" data-value="43">
- <button
- aria-label="43 unmodified"
- class="gr-diff left lineNumButton"
- data-value="43"
- id="left-button-43"
- tabindex="-1"
- >
- 43
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="46">
- <button
- aria-label="46 unmodified"
- class="gr-diff lineNumButton right"
- data-value="46"
- id="right-button-46"
- tabindex="-1"
- >
- 46
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-46"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-44 right-button-47 right-content-47"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="44"></td>
- <td class="gr-diff left lineNum" data-value="44">
- <button
- aria-label="44 unmodified"
- class="gr-diff left lineNumButton"
- data-value="44"
- id="left-button-44"
- tabindex="-1"
- >
- 44
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="47">
- <button
- aria-label="47 unmodified"
- class="gr-diff lineNumButton right"
- data-value="47"
- id="right-button-47"
- tabindex="-1"
- >
- 47
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-47"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-45 right-button-48 right-content-48"
- class="both diff-row gr-diff unified"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="45"></td>
- <td class="gr-diff left lineNum" data-value="45">
- <button
- aria-label="45 unmodified"
- class="gr-diff left lineNumButton"
- data-value="45"
- id="left-button-45"
- tabindex="-1"
- >
- 45
- </button>
- </td>
- <td class="gr-diff lineNum right" data-value="48">
- <button
- aria-label="48 unmodified"
- class="gr-diff lineNumButton right"
- data-value="48"
- id="right-button-48"
- tabindex="-1"
- >
- 48
- </button>
- </td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-48"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- `,
- {
- ignoreTags: [
- 'gr-context-controls-section',
- 'gr-diff-section',
- 'gr-diff-row',
- 'gr-diff-text',
- 'gr-legacy-text',
- 'slot',
- ],
- }
- );
- });
-
- test('a normal diff lit', async () => {
- element.prefs = {...MINIMAL_PREFS};
- element.diff = createDiff();
- await element.updateComplete;
- await waitForEventOnce(element, 'render');
- assert.shadowDom.equal(
- element,
- /* HTML */ `
- <div class="diffContainer newDiff sideBySide">
- <table class="selected-right" id="diffTable">
- <colgroup>
- <col class="blame gr-diff" />
- <col class="gr-diff left" width="48" />
- <col class="gr-diff left sign" />
- <col class="gr-diff left" />
- <col class="gr-diff right" width="48" />
- <col class="gr-diff right sign" />
- <col class="gr-diff right" />
- </colgroup>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-LOST left-content-LOST right-button-LOST right-content-LOST"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="LOST"></td>
- <td class="gr-diff left lineNum" data-value="LOST"></td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left lost no-intraline-info">
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="LOST"></td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff lost no-intraline-info right">
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-FILE left-content-FILE right-button-FILE right-content-FILE"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="FILE"></td>
- <td class="gr-diff left lineNum" data-value="FILE">
- <button
- aria-label="Add file comment"
- class="gr-diff left lineNumButton"
- data-value="FILE"
- id="left-button-FILE"
- tabindex="-1"
- >
- File
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content file gr-diff left no-intraline-info">
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="FILE">
- <button
- aria-label="Add file comment"
- class="gr-diff lineNumButton right"
- data-value="FILE"
- id="right-button-FILE"
- tabindex="-1"
- >
- File
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content file gr-diff no-intraline-info right">
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-1 left-content-1 right-button-1 right-content-1"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="1"></td>
- <td class="gr-diff left lineNum" data-value="1">
- <button
- aria-label="1 unmodified"
- class="gr-diff left lineNumButton"
- data-value="1"
- id="left-button-1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-1"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="1">
- <button
- aria-label="1 unmodified"
- class="gr-diff lineNumButton right"
- data-value="1"
- id="right-button-1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-1"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-2 left-content-2 right-button-2 right-content-2"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="2"></td>
- <td class="gr-diff left lineNum" data-value="2">
- <button
- aria-label="2 unmodified"
- class="gr-diff left lineNumButton"
- data-value="2"
- id="left-button-2"
- tabindex="-1"
- >
- 2
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-2"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="2">
- <button
- aria-label="2 unmodified"
- class="gr-diff lineNumButton right"
- data-value="2"
- id="right-button-2"
- tabindex="-1"
- >
- 2
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-2"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-3 left-content-3 right-button-3 right-content-3"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="3"></td>
- <td class="gr-diff left lineNum" data-value="3">
- <button
- aria-label="3 unmodified"
- class="gr-diff left lineNumButton"
- data-value="3"
- id="left-button-3"
- tabindex="-1"
- >
- 3
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-3"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="3">
- <button
- aria-label="3 unmodified"
- class="gr-diff lineNumButton right"
- data-value="3"
- id="right-button-3"
- tabindex="-1"
- >
- 3
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-3"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-4 left-content-4 right-button-4 right-content-4"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="4"></td>
- <td class="gr-diff left lineNum" data-value="4">
- <button
- aria-label="4 unmodified"
- class="gr-diff left lineNumButton"
- data-value="4"
- id="left-button-4"
- tabindex="-1"
- >
- 4
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-4"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="4">
- <button
- aria-label="4 unmodified"
- class="gr-diff lineNumButton right"
- data-value="4"
- id="right-button-4"
- tabindex="-1"
- >
- 4
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-4"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="delta gr-diff section total">
- <tr
- aria-labelledby="right-button-5 right-content-5"
- class="diff-row gr-diff side-by-side"
- left-type="blank"
- right-type="add"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="blankLineNum gr-diff left"></td>
- <td class="blank gr-diff left no-intraline-info sign"></td>
- <td class="blank gr-diff left no-intraline-info">
- <div class="contentText gr-diff" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="5">
- <button
- aria-label="5 added"
- class="gr-diff lineNumButton right"
- data-value="5"
- id="right-button-5"
- tabindex="-1"
- >
- 5
- </button>
- </td>
- <td class="add gr-diff no-intraline-info right sign">+</td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-5"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="right-button-6 right-content-6"
- class="diff-row gr-diff side-by-side"
- left-type="blank"
- right-type="add"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="blankLineNum gr-diff left"></td>
- <td class="blank gr-diff left no-intraline-info sign"></td>
- <td class="blank gr-diff left no-intraline-info">
- <div class="contentText gr-diff" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="6">
- <button
- aria-label="6 added"
- class="gr-diff lineNumButton right"
- data-value="6"
- id="right-button-6"
- tabindex="-1"
- >
- 6
- </button>
- </td>
- <td class="add gr-diff no-intraline-info right sign">+</td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-6"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="right-button-7 right-content-7"
- class="diff-row gr-diff side-by-side"
- left-type="blank"
- right-type="add"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="blankLineNum gr-diff left"></td>
- <td class="blank gr-diff left no-intraline-info sign"></td>
- <td class="blank gr-diff left no-intraline-info">
- <div class="contentText gr-diff" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="7">
- <button
- aria-label="7 added"
- class="gr-diff lineNumButton right"
- data-value="7"
- id="right-button-7"
- tabindex="-1"
- >
- 7
- </button>
- </td>
- <td class="add gr-diff no-intraline-info right sign">+</td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-7"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-5 left-content-5 right-button-8 right-content-8"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="5"></td>
- <td class="gr-diff left lineNum" data-value="5">
- <button
- aria-label="5 unmodified"
- class="gr-diff left lineNumButton"
- data-value="5"
- id="left-button-5"
- tabindex="-1"
- >
- 5
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-5"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="8">
- <button
- aria-label="8 unmodified"
- class="gr-diff lineNumButton right"
- data-value="8"
- id="right-button-8"
- tabindex="-1"
- >
- 8
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-8"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-6 left-content-6 right-button-9 right-content-9"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="6"></td>
- <td class="gr-diff left lineNum" data-value="6">
- <button
- aria-label="6 unmodified"
- class="gr-diff left lineNumButton"
- data-value="6"
- id="left-button-6"
- tabindex="-1"
- >
- 6
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-6"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="9">
- <button
- aria-label="9 unmodified"
- class="gr-diff lineNumButton right"
- data-value="9"
- id="right-button-9"
- tabindex="-1"
- >
- 9
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-9"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-7 left-content-7 right-button-10 right-content-10"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="7"></td>
- <td class="gr-diff left lineNum" data-value="7">
- <button
- aria-label="7 unmodified"
- class="gr-diff left lineNumButton"
- data-value="7"
- id="left-button-7"
- tabindex="-1"
- >
- 7
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-7"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="10">
- <button
- aria-label="10 unmodified"
- class="gr-diff lineNumButton right"
- data-value="10"
- id="right-button-10"
- tabindex="-1"
- >
- 10
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-10"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-8 left-content-8 right-button-11 right-content-11"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="8"></td>
- <td class="gr-diff left lineNum" data-value="8">
- <button
- aria-label="8 unmodified"
- class="gr-diff left lineNumButton"
- data-value="8"
- id="left-button-8"
- tabindex="-1"
- >
- 8
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-8"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="11">
- <button
- aria-label="11 unmodified"
- class="gr-diff lineNumButton right"
- data-value="11"
- id="right-button-11"
- tabindex="-1"
- >
- 11
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-11"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-9 left-content-9 right-button-12 right-content-12"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="9"></td>
- <td class="gr-diff left lineNum" data-value="9">
- <button
- aria-label="9 unmodified"
- class="gr-diff left lineNumButton"
- data-value="9"
- id="left-button-9"
- tabindex="-1"
- >
- 9
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-9"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="12">
- <button
- aria-label="12 unmodified"
- class="gr-diff lineNumButton right"
- data-value="12"
- id="right-button-12"
- tabindex="-1"
- >
- 12
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-12"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="delta gr-diff section total">
- <tr
- aria-labelledby="left-button-10 left-content-10"
- class="diff-row gr-diff side-by-side"
- left-type="remove"
- right-type="blank"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="10"></td>
- <td class="gr-diff left lineNum" data-value="10">
- <button
- aria-label="10 removed"
- class="gr-diff left lineNumButton"
- data-value="10"
- id="left-button-10"
- tabindex="-1"
- >
- 10
- </button>
- </td>
- <td class="gr-diff left no-intraline-info remove sign">-</td>
- <td class="content gr-diff left no-intraline-info remove">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-10"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="blankLineNum gr-diff right"></td>
- <td class="blank gr-diff no-intraline-info right sign"></td>
- <td class="blank gr-diff no-intraline-info right">
- <div class="contentText gr-diff" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-11 left-content-11"
- class="diff-row gr-diff side-by-side"
- left-type="remove"
- right-type="blank"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="11"></td>
- <td class="gr-diff left lineNum" data-value="11">
- <button
- aria-label="11 removed"
- class="gr-diff left lineNumButton"
- data-value="11"
- id="left-button-11"
- tabindex="-1"
- >
- 11
- </button>
- </td>
- <td class="gr-diff left no-intraline-info remove sign">-</td>
- <td class="content gr-diff left no-intraline-info remove">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-11"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="blankLineNum gr-diff right"></td>
- <td class="blank gr-diff no-intraline-info right sign"></td>
- <td class="blank gr-diff no-intraline-info right">
- <div class="contentText gr-diff" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-12 left-content-12"
- class="diff-row gr-diff side-by-side"
- left-type="remove"
- right-type="blank"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="12"></td>
- <td class="gr-diff left lineNum" data-value="12">
- <button
- aria-label="12 removed"
- class="gr-diff left lineNumButton"
- data-value="12"
- id="left-button-12"
- tabindex="-1"
- >
- 12
- </button>
- </td>
- <td class="gr-diff left no-intraline-info remove sign">-</td>
- <td class="content gr-diff left no-intraline-info remove">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-12"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="blankLineNum gr-diff right"></td>
- <td class="blank gr-diff no-intraline-info right sign"></td>
- <td class="blank gr-diff no-intraline-info right">
- <div class="contentText gr-diff" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-13 left-content-13"
- class="diff-row gr-diff side-by-side"
- left-type="remove"
- right-type="blank"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="13"></td>
- <td class="gr-diff left lineNum" data-value="13">
- <button
- aria-label="13 removed"
- class="gr-diff left lineNumButton"
- data-value="13"
- id="left-button-13"
- tabindex="-1"
- >
- 13
- </button>
- </td>
- <td class="gr-diff left no-intraline-info remove sign">-</td>
- <td class="content gr-diff left no-intraline-info remove">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-13"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="blankLineNum gr-diff right"></td>
- <td class="blank gr-diff no-intraline-info right sign"></td>
- <td class="blank gr-diff no-intraline-info right">
- <div class="contentText gr-diff" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="delta gr-diff ignoredWhitespaceOnly section">
- <tr
- aria-labelledby="left-button-14 left-content-14 right-button-13 right-content-13"
- class="diff-row gr-diff side-by-side"
- left-type="remove"
- right-type="add"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="14"></td>
- <td class="gr-diff left lineNum" data-value="14">
- <button
- aria-label="14 removed"
- class="gr-diff left lineNumButton"
- data-value="14"
- id="left-button-14"
- tabindex="-1"
- >
- 14
- </button>
- </td>
- <td class="gr-diff left no-intraline-info remove sign">-</td>
- <td class="content gr-diff left no-intraline-info remove">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-14"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="13">
- <button
- aria-label="13 added"
- class="gr-diff lineNumButton right"
- data-value="13"
- id="right-button-13"
- tabindex="-1"
- >
- 13
- </button>
- </td>
- <td class="add gr-diff no-intraline-info right sign">+</td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-13"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-15 left-content-15 right-button-14 right-content-14"
- class="diff-row gr-diff side-by-side"
- left-type="remove"
- right-type="add"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="15"></td>
- <td class="gr-diff left lineNum" data-value="15">
- <button
- aria-label="15 removed"
- class="gr-diff left lineNumButton"
- data-value="15"
- id="left-button-15"
- tabindex="-1"
- >
- 15
- </button>
- </td>
- <td class="gr-diff left no-intraline-info remove sign">-</td>
- <td class="content gr-diff left no-intraline-info remove">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-15"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="14">
- <button
- aria-label="14 added"
- class="gr-diff lineNumButton right"
- data-value="14"
- id="right-button-14"
- tabindex="-1"
- >
- 14
- </button>
- </td>
- <td class="add gr-diff no-intraline-info right sign">+</td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-14"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="delta gr-diff section">
- <tr
- aria-labelledby="left-button-16 left-content-16 right-button-15 right-content-15"
- class="diff-row gr-diff side-by-side"
- left-type="remove"
- right-type="add"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="16"></td>
- <td class="gr-diff left lineNum" data-value="16">
- <button
- aria-label="16 removed"
- class="gr-diff left lineNumButton"
- data-value="16"
- id="left-button-16"
- tabindex="-1"
- >
- 16
- </button>
- </td>
- <td class="gr-diff left remove sign">-</td>
- <td class="content gr-diff left remove">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-16"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="15">
- <button
- aria-label="15 added"
- class="gr-diff lineNumButton right"
- data-value="15"
- id="right-button-15"
- tabindex="-1"
- >
- 15
- </button>
- </td>
- <td class="add gr-diff right sign">+</td>
- <td class="add content gr-diff right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-15"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-17 left-content-17 right-button-16 right-content-16"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="17"></td>
- <td class="gr-diff left lineNum" data-value="17">
- <button
- aria-label="17 unmodified"
- class="gr-diff left lineNumButton"
- data-value="17"
- id="left-button-17"
- tabindex="-1"
- >
- 17
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-17"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="16">
- <button
- aria-label="16 unmodified"
- class="gr-diff lineNumButton right"
- data-value="16"
- id="right-button-16"
- tabindex="-1"
- >
- 16
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-16"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-18 left-content-18 right-button-17 right-content-17"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="18"></td>
- <td class="gr-diff left lineNum" data-value="18">
- <button
- aria-label="18 unmodified"
- class="gr-diff left lineNumButton"
- data-value="18"
- id="left-button-18"
- tabindex="-1"
- >
- 18
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-18"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="17">
- <button
- aria-label="17 unmodified"
- class="gr-diff lineNumButton right"
- data-value="17"
- id="right-button-17"
- tabindex="-1"
- >
- 17
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-17"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-19 left-content-19 right-button-18 right-content-18"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="19"></td>
- <td class="gr-diff left lineNum" data-value="19">
- <button
- aria-label="19 unmodified"
- class="gr-diff left lineNumButton"
- data-value="19"
- id="left-button-19"
- tabindex="-1"
- >
- 19
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-19"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="18">
- <button
- aria-label="18 unmodified"
- class="gr-diff lineNumButton right"
- data-value="18"
- id="right-button-18"
- tabindex="-1"
- >
- 18
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-18"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="contextControl gr-diff section">
- <tr
- class="above contextBackground gr-diff side-by-side"
- left-type="contextControl"
- right-type="contextControl"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="contextLineNum gr-diff"></td>
- <td class="gr-diff sign"></td>
- <td class="gr-diff"></td>
- <td class="contextLineNum gr-diff"></td>
- <td class="gr-diff sign"></td>
- <td class="gr-diff"></td>
- </tr>
- <tr class="dividerRow gr-diff show-both">
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="gr-diff"></td>
- <td class="dividerCell gr-diff" colspan="3">
- <gr-context-controls
- class="gr-diff"
- showconfig="both"
- ></gr-context-controls>
- </td>
- </tr>
- <tr
- class="below contextBackground gr-diff side-by-side"
- left-type="contextControl"
- right-type="contextControl"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="contextLineNum gr-diff"></td>
- <td class="gr-diff sign"></td>
- <td class="gr-diff"></td>
- <td class="contextLineNum gr-diff"></td>
- <td class="gr-diff sign"></td>
- <td class="gr-diff"></td>
- </tr>
- </tbody>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-38 left-content-38 right-button-37 right-content-37"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="38"></td>
- <td class="gr-diff left lineNum" data-value="38">
- <button
- aria-label="38 unmodified"
- class="gr-diff left lineNumButton"
- data-value="38"
- id="left-button-38"
- tabindex="-1"
- >
- 38
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-38"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="37">
- <button
- aria-label="37 unmodified"
- class="gr-diff lineNumButton right"
- data-value="37"
- id="right-button-37"
- tabindex="-1"
- >
- 37
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-37"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-39 left-content-39 right-button-38 right-content-38"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="39"></td>
- <td class="gr-diff left lineNum" data-value="39">
- <button
- aria-label="39 unmodified"
- class="gr-diff left lineNumButton"
- data-value="39"
- id="left-button-39"
- tabindex="-1"
- >
- 39
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-39"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="38">
- <button
- aria-label="38 unmodified"
- class="gr-diff lineNumButton right"
- data-value="38"
- id="right-button-38"
- tabindex="-1"
- >
- 38
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-38"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-40 left-content-40 right-button-39 right-content-39"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="40"></td>
- <td class="gr-diff left lineNum" data-value="40">
- <button
- aria-label="40 unmodified"
- class="gr-diff left lineNumButton"
- data-value="40"
- id="left-button-40"
- tabindex="-1"
- >
- 40
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-40"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="39">
- <button
- aria-label="39 unmodified"
- class="gr-diff lineNumButton right"
- data-value="39"
- id="right-button-39"
- tabindex="-1"
- >
- 39
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-39"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="delta gr-diff section total">
- <tr
- aria-labelledby="right-button-40 right-content-40"
- class="diff-row gr-diff side-by-side"
- left-type="blank"
- right-type="add"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="blankLineNum gr-diff left"></td>
- <td class="blank gr-diff left no-intraline-info sign"></td>
- <td class="blank gr-diff left no-intraline-info">
- <div class="contentText gr-diff" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="40">
- <button
- aria-label="40 added"
- class="gr-diff lineNumButton right"
- data-value="40"
- id="right-button-40"
- tabindex="-1"
- >
- 40
- </button>
- </td>
- <td class="add gr-diff no-intraline-info right sign">+</td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-40"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="right-button-41 right-content-41"
- class="diff-row gr-diff side-by-side"
- left-type="blank"
- right-type="add"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="blankLineNum gr-diff left"></td>
- <td class="blank gr-diff left no-intraline-info sign"></td>
- <td class="blank gr-diff left no-intraline-info">
- <div class="contentText gr-diff" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="41">
- <button
- aria-label="41 added"
- class="gr-diff lineNumButton right"
- data-value="41"
- id="right-button-41"
- tabindex="-1"
- >
- 41
- </button>
- </td>
- <td class="add gr-diff no-intraline-info right sign">+</td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-41"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="right-button-42 right-content-42"
- class="diff-row gr-diff side-by-side"
- left-type="blank"
- right-type="add"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="blankLineNum gr-diff left"></td>
- <td class="blank gr-diff left no-intraline-info sign"></td>
- <td class="blank gr-diff left no-intraline-info">
- <div class="contentText gr-diff" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="42">
- <button
- aria-label="42 added"
- class="gr-diff lineNumButton right"
- data-value="42"
- id="right-button-42"
- tabindex="-1"
- >
- 42
- </button>
- </td>
- <td class="add gr-diff no-intraline-info right sign">+</td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-42"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="right-button-43 right-content-43"
- class="diff-row gr-diff side-by-side"
- left-type="blank"
- right-type="add"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="0"></td>
- <td class="blankLineNum gr-diff left"></td>
- <td class="blank gr-diff left no-intraline-info sign"></td>
- <td class="blank gr-diff left no-intraline-info">
- <div class="contentText gr-diff" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="43">
- <button
- aria-label="43 added"
- class="gr-diff lineNumButton right"
- data-value="43"
- id="right-button-43"
- tabindex="-1"
- >
- 43
- </button>
- </td>
- <td class="add gr-diff no-intraline-info right sign">+</td>
- <td class="add content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-43"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-41 left-content-41 right-button-44 right-content-44"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="41"></td>
- <td class="gr-diff left lineNum" data-value="41">
- <button
- aria-label="41 unmodified"
- class="gr-diff left lineNumButton"
- data-value="41"
- id="left-button-41"
- tabindex="-1"
- >
- 41
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-41"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="44">
- <button
- aria-label="44 unmodified"
- class="gr-diff lineNumButton right"
- data-value="44"
- id="right-button-44"
- tabindex="-1"
- >
- 44
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-44"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-42 left-content-42 right-button-45 right-content-45"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="42"></td>
- <td class="gr-diff left lineNum" data-value="42">
- <button
- aria-label="42 unmodified"
- class="gr-diff left lineNumButton"
- data-value="42"
- id="left-button-42"
- tabindex="-1"
- >
- 42
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-42"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="45">
- <button
- aria-label="45 unmodified"
- class="gr-diff lineNumButton right"
- data-value="45"
- id="right-button-45"
- tabindex="-1"
- >
- 45
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-45"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-43 left-content-43 right-button-46 right-content-46"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="43"></td>
- <td class="gr-diff left lineNum" data-value="43">
- <button
- aria-label="43 unmodified"
- class="gr-diff left lineNumButton"
- data-value="43"
- id="left-button-43"
- tabindex="-1"
- >
- 43
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-43"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="46">
- <button
- aria-label="46 unmodified"
- class="gr-diff lineNumButton right"
- data-value="46"
- id="right-button-46"
- tabindex="-1"
- >
- 46
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-46"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-44 left-content-44 right-button-47 right-content-47"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="44"></td>
- <td class="gr-diff left lineNum" data-value="44">
- <button
- aria-label="44 unmodified"
- class="gr-diff left lineNumButton"
- data-value="44"
- id="left-button-44"
- tabindex="-1"
- >
- 44
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-44"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="47">
- <button
- aria-label="47 unmodified"
- class="gr-diff lineNumButton right"
- data-value="47"
- id="right-button-47"
- tabindex="-1"
- >
- 47
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-47"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- <tr
- aria-labelledby="left-button-45 left-content-45 right-button-48 right-content-48"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="45"></td>
- <td class="gr-diff left lineNum" data-value="45">
- <button
- aria-label="45 unmodified"
- class="gr-diff left lineNumButton"
- data-value="45"
- id="left-button-45"
- tabindex="-1"
- >
- 45
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td class="both content gr-diff left no-intraline-info">
- <div
- class="contentText gr-diff"
- data-side="left"
- id="left-content-45"
- ></div>
- <div class="thread-group" data-side="left"></div>
- </td>
- <td class="gr-diff lineNum right" data-value="48">
- <button
- aria-label="48 unmodified"
- class="gr-diff lineNumButton right"
- data-value="48"
- id="right-button-48"
- tabindex="-1"
- >
- 48
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td class="both content gr-diff no-intraline-info right">
- <div
- class="contentText gr-diff"
- data-side="right"
- id="right-content-48"
- ></div>
- <div class="thread-group" data-side="right"></div>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- `,
- {
- ignoreTags: [
- 'gr-context-controls-section',
- 'gr-diff-section',
- 'gr-diff-row',
- 'gr-diff-text',
- 'gr-legacy-text',
- 'slot',
- ],
- }
- );
- });
- });
-
suite('selectionchange event handling', () => {
let handleSelectionChangeStub: sinon.SinonSpy;
@@ -3141,357 +188,6 @@
assert.isFalse(element.classList.contains('no-left'));
});
- suite('binary diffs', () => {
- test('render binary diff', async () => {
- element.prefs = {
- ...MINIMAL_PREFS,
- };
- element.diff = {
- meta_a: {name: 'carrot.exe', content_type: 'binary', lines: 0},
- meta_b: {name: 'carrot.exe', content_type: 'binary', lines: 0},
- change_type: 'MODIFIED',
- intraline_status: 'OK',
- diff_header: [],
- content: [],
- binary: true,
- };
- await waitForEventOnce(element, 'render');
-
- assert.shadowDom.equal(
- element,
- /* HTML */ `
- <div class="diffContainer newDiff sideBySide">
- <gr-diff-section class="left-FILE right-FILE"> </gr-diff-section>
- <gr-diff-row class="left-FILE right-FILE"> </gr-diff-row>
- <table class="selected-right" id="diffTable">
- <colgroup>
- <col class="blame gr-diff" />
- <col class="gr-diff left" width="48" />
- <col class="gr-diff left sign" />
- <col class="gr-diff left" />
- <col class="gr-diff right" width="48" />
- <col class="gr-diff right sign" />
- <col class="gr-diff right" />
- </colgroup>
- <tbody class="both gr-diff section">
- <tr
- aria-labelledby="left-button-FILE left-content-FILE right-button-FILE right-content-FILE"
- class="diff-row gr-diff side-by-side"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff" data-line-number="FILE"></td>
- <td class="gr-diff left lineNum" data-value="FILE">
- <button
- aria-label="Add file comment"
- class="gr-diff left lineNumButton"
- data-value="FILE"
- id="left-button-FILE"
- tabindex="-1"
- >
- File
- </button>
- </td>
- <td class="gr-diff left no-intraline-info sign"></td>
- <td
- class="both content file gr-diff left no-intraline-info"
- >
- <div class="thread-group" data-side="left">
- <slot name="left-FILE"> </slot>
- </div>
- </td>
- <td class="gr-diff lineNum right" data-value="FILE">
- <button
- aria-label="Add file comment"
- class="gr-diff lineNumButton right"
- data-value="FILE"
- id="right-button-FILE"
- tabindex="-1"
- >
- File
- </button>
- </td>
- <td class="gr-diff no-intraline-info right sign"></td>
- <td
- class="both content file gr-diff no-intraline-info right"
- >
- <div class="thread-group" data-side="right">
- <slot name="right-FILE"> </slot>
- </div>
- </td>
- </tr>
- </tbody>
- <tbody class="binary-diff gr-diff">
- <tr class="gr-diff">
- <td class="gr-diff" colspan="5">
- <span> Difference in binary files </span>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- `
- );
- });
- });
-
- suite('image diffs', () => {
- let mockFile1: ImageInfo;
- let mockFile2: ImageInfo;
- setup(() => {
- mockFile1 = {
- body:
- 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' +
- 'wsAAAAAAAAAAAAAAAAA/w==',
- type: 'image/bmp',
- };
- mockFile2 = {
- body:
- 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' +
- 'wsAAAAAAAAAAAAA/////w==',
- type: 'image/bmp',
- };
-
- element.isImageDiff = true;
- element.prefs = {
- context: 10,
- cursor_blink_rate: 0,
- font_size: 12,
- ignore_whitespace: 'IGNORE_NONE',
- line_length: 100,
- line_wrapping: false,
- show_line_endings: true,
- show_tabs: true,
- show_whitespace_errors: true,
- syntax_highlighting: true,
- tab_size: 8,
- };
- });
-
- test('render image diff', async () => {
- element.baseImage = mockFile1;
- element.revisionImage = mockFile2;
- element.diff = {
- meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
- meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 560},
- intraline_status: 'OK',
- change_type: 'MODIFIED',
- diff_header: [
- 'diff --git a/carrot.jpg b/carrot.jpg',
- 'index 2adc47d..f9c2f2c 100644',
- '--- a/carrot.jpg',
- '+++ b/carrot.jpg',
- 'Binary files differ',
- ],
- content: [{skip: 66}],
- binary: true,
- };
-
- await waitForEventOnce(element, 'render');
- const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
- assert.lightDom.equal(
- imageDiffSection,
- /* HTML */ `
- <tbody class="gr-diff image-diff">
- <tr class="gr-diff">
- <td class="blank gr-diff left lineNum"></td>
- <td class="gr-diff left">
- <img
- class="gr-diff left"
- src="data:image/bmp;base64,${mockFile1.body}"
- />
- </td>
- <td class="blank gr-diff lineNum right"></td>
- <td class="gr-diff right">
- <img
- class="gr-diff right"
- src="data:image/bmp;base64,${mockFile2.body}"
- />
- </td>
- </tr>
- <tr class="gr-diff">
- <td class="blank gr-diff left lineNum"></td>
- <td class="gr-diff left">
- <label class="gr-diff">
- <span class="gr-diff label"> 1×1 image/bmp </span>
- </label>
- </td>
- <td class="blank gr-diff lineNum right"></td>
- <td class="gr-diff right">
- <label class="gr-diff">
- <span class="gr-diff label"> 1×1 image/bmp </span>
- </label>
- </td>
- </tr>
- </tbody>
- `
- );
- const endpoint = queryAndAssert(element, 'tbody.endpoint');
- assert.dom.equal(
- endpoint,
- /* HTML */ `
- <tbody class="gr-diff endpoint">
- <tr class="gr-diff">
- <gr-endpoint-decorator class="gr-diff" name="image-diff">
- <gr-endpoint-param class="gr-diff" name="baseImage">
- </gr-endpoint-param>
- <gr-endpoint-param class="gr-diff" name="revisionImage">
- </gr-endpoint-param>
- </gr-endpoint-decorator>
- </tr>
- </tbody>
- `
- );
- });
-
- test('renders image diffs with a different file name', async () => {
- const mockDiff: DiffInfo = {
- meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
- meta_b: {name: 'carrot2.jpg', content_type: 'image/jpeg', lines: 560},
- intraline_status: 'OK',
- change_type: 'MODIFIED',
- diff_header: [
- 'diff --git a/carrot.jpg b/carrot2.jpg',
- 'index 2adc47d..f9c2f2c 100644',
- '--- a/carrot.jpg',
- '+++ b/carrot2.jpg',
- 'Binary files differ',
- ],
- content: [{skip: 66}],
- binary: true,
- };
-
- element.baseImage = mockFile1;
- element.baseImage._name = mockDiff.meta_a!.name;
- element.revisionImage = mockFile2;
- element.revisionImage._name = mockDiff.meta_b!.name;
- element.diff = mockDiff;
-
- await waitForEventOnce(element, 'render');
- const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
- const leftLabel = queryAndAssert(imageDiffSection, 'td.left label');
- const rightLabel = queryAndAssert(imageDiffSection, 'td.right label');
- assert.dom.equal(
- leftLabel,
- /* HTML */ `
- <label class="gr-diff">
- <span class="gr-diff name"> carrot.jpg </span>
- <br class="gr-diff" />
- <span class="gr-diff label"> 1×1 image/bmp </span>
- </label>
- `
- );
- assert.dom.equal(
- rightLabel,
- /* HTML */ `
- <label class="gr-diff">
- <span class="gr-diff name"> carrot2.jpg </span>
- <br class="gr-diff" />
- <span class="gr-diff label"> 1×1 image/bmp </span>
- </label>
- `
- );
- });
-
- test('renders added image', async () => {
- const mockDiff: DiffInfo = {
- meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 560},
- intraline_status: 'OK',
- change_type: 'ADDED',
- diff_header: [
- 'diff --git a/carrot.jpg b/carrot.jpg',
- 'index 0000000..f9c2f2c 100644',
- '--- /dev/null',
- '+++ b/carrot.jpg',
- 'Binary files differ',
- ],
- content: [{skip: 66}],
- binary: true,
- };
- element.revisionImage = mockFile2;
- element.diff = mockDiff;
-
- await waitForEventOnce(element, 'render');
- const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
- const leftImage = query(imageDiffSection, 'td.left img');
- const rightImage = queryAndAssert(imageDiffSection, 'td.right img');
- assert.isNotOk(leftImage);
- assert.dom.equal(
- rightImage,
- /* HTML */ `
- <img
- class="gr-diff right"
- src="data:image/bmp;base64,${mockFile2.body}"
- />
- `
- );
- });
-
- test('renders removed image', async () => {
- const mockDiff: DiffInfo = {
- meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 560},
- intraline_status: 'OK',
- change_type: 'DELETED',
- diff_header: [
- 'diff --git a/carrot.jpg b/carrot.jpg',
- 'index f9c2f2c..0000000 100644',
- '--- a/carrot.jpg',
- '+++ /dev/null',
- 'Binary files differ',
- ],
- content: [{skip: 66}],
- binary: true,
- };
- element.baseImage = mockFile1;
- element.diff = mockDiff;
-
- await waitForEventOnce(element, 'render');
- const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
- const leftImage = queryAndAssert(imageDiffSection, 'td.left img');
- const rightImage = query(imageDiffSection, 'td.right img');
- assert.isNotOk(rightImage);
- assert.dom.equal(
- leftImage,
- /* HTML */ `
- <img
- class="gr-diff left"
- src="data:image/bmp;base64,${mockFile1.body}"
- />
- `
- );
- });
-
- test('does not render disallowed image type', async () => {
- const mockDiff: DiffInfo = {
- meta_a: {
- name: 'carrot.jpg',
- content_type: 'image/jpeg-evil',
- lines: 560,
- },
- intraline_status: 'OK',
- change_type: 'DELETED',
- diff_header: [
- 'diff --git a/carrot.jpg b/carrot.jpg',
- 'index f9c2f2c..0000000 100644',
- '--- a/carrot.jpg',
- '+++ /dev/null',
- 'Binary files differ',
- ],
- content: [{skip: 66}],
- binary: true,
- };
- mockFile1.type = 'image/jpeg-evil';
- element.baseImage = mockFile1;
- element.diff = mockDiff;
-
- await waitForEventOnce(element, 'render');
- const imageDiffSection = queryAndAssert(element, 'tbody.image-diff');
- const leftImage = query(imageDiffSection, 'td.left img');
- assert.isNotOk(leftImage);
- });
- });
-
test('handleTap lineNum', async () => {
const addDraftStub = sinon.stub(element, 'addDraftAtLine');
const el = document.createElement('div');
@@ -3707,50 +403,6 @@
});
});
- suite('diff header', () => {
- setup(async () => {
- element.diff = {
- meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
- meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 560},
- diff_header: [],
- intraline_status: 'OK',
- change_type: 'MODIFIED',
- content: [{skip: 66}],
- };
- await element.updateComplete;
- });
-
- test('hidden', async () => {
- assert.equal(element.computeDiffHeaderItems().length, 0);
- element.diff?.diff_header?.push('diff --git a/test.jpg b/test.jpg');
- assert.equal(element.computeDiffHeaderItems().length, 0);
- element.diff?.diff_header?.push('index 2adc47d..f9c2f2c 100644');
- assert.equal(element.computeDiffHeaderItems().length, 0);
- element.diff?.diff_header?.push('--- a/test.jpg');
- assert.equal(element.computeDiffHeaderItems().length, 0);
- element.diff?.diff_header?.push('+++ b/test.jpg');
- assert.equal(element.computeDiffHeaderItems().length, 0);
- element.diff?.diff_header?.push('test');
- assert.equal(element.computeDiffHeaderItems().length, 1);
- element.requestUpdate('diff');
- await element.updateComplete;
-
- const header = queryAndAssert(element, '#diffHeader');
- assert.equal(header.textContent?.trim(), 'test');
- });
-
- test('binary files', () => {
- element.diff!.binary = true;
- assert.equal(element.computeDiffHeaderItems().length, 0);
- element.diff?.diff_header?.push('diff --git a/test.jpg b/test.jpg');
- assert.equal(element.computeDiffHeaderItems().length, 0);
- element.diff?.diff_header?.push('test');
- assert.equal(element.computeDiffHeaderItems().length, 1);
- element.diff?.diff_header?.push('Binary files differ');
- assert.equal(element.computeDiffHeaderItems().length, 1);
- });
- });
-
suite('blame', () => {
test('unsetting', async () => {
element.blame = [];
@@ -3777,60 +429,6 @@
});
});
- suite('trailing newline warnings', () => {
- const NO_NEWLINE_LEFT = 'No newline at end of left file.';
- const NO_NEWLINE_RIGHT = 'No newline at end of right file.';
-
- const getWarning = (element: GrDiff) => {
- const warningElement = query(element, '.newlineWarning');
- return warningElement?.textContent ?? '';
- };
-
- setup(async () => {
- element.showNewlineWarningLeft = false;
- element.showNewlineWarningRight = false;
- await element.updateComplete;
- });
-
- test('shows combined warning if both sides set to warn', async () => {
- element.showNewlineWarningLeft = true;
- element.showNewlineWarningRight = true;
- await element.updateComplete;
- assert.include(
- getWarning(element),
- NO_NEWLINE_LEFT + ' \u2014 ' + NO_NEWLINE_RIGHT
- ); // \u2014 - '—'
- });
-
- suite('showNewlineWarningLeft', () => {
- test('show warning if true', async () => {
- element.showNewlineWarningLeft = true;
- await element.updateComplete;
- assert.include(getWarning(element), NO_NEWLINE_LEFT);
- });
-
- test('hide warning if false', async () => {
- element.showNewlineWarningLeft = false;
- await element.updateComplete;
- assert.notInclude(getWarning(element), NO_NEWLINE_LEFT);
- });
- });
-
- suite('showNewlineWarningRight', () => {
- test('show warning if true', async () => {
- element.showNewlineWarningRight = true;
- await element.updateComplete;
- assert.include(getWarning(element), NO_NEWLINE_RIGHT);
- });
-
- test('hide warning if false', async () => {
- element.showNewlineWarningRight = false;
- await element.updateComplete;
- assert.notInclude(getWarning(element), NO_NEWLINE_RIGHT);
- });
- });
- });
-
const setupSampleDiff = async function (params: {
content: DiffContent[];
ignore_whitespace?: IgnoreWhitespaceType;
@@ -3918,68 +516,6 @@
assert.equal(getComputedStyle(diffLine).userSelect, 'text');
});
});
-
- suite('whitespace changes only message', () => {
- test('show the message if ignore_whitespace is criteria matches', async () => {
- await setupSampleDiff({content: [{skip: 100}]});
- element.loading = false;
- assert.isTrue(element.showNoChangeMessage());
- });
-
- test('do not show the message for binary files', async () => {
- await setupSampleDiff({content: [{skip: 100}], binary: true});
- element.loading = false;
- assert.isFalse(element.showNoChangeMessage());
- });
-
- test('do not show the message if still loading', async () => {
- await setupSampleDiff({content: [{skip: 100}]});
- element.loading = true;
- assert.isFalse(element.showNoChangeMessage());
- });
-
- test('do not show the message if contains valid changes', async () => {
- const content = [
- {
- a: ['all work and no play make andybons a dull boy'],
- b: ['elgoog elgoog elgoog'],
- },
- {
- ab: [
- 'Non eram nescius, Brute, cum, quae summis ingeniis ',
- 'exquisitaque doctrina philosophi Graeco sermone tractavissent',
- ],
- },
- ];
- await setupSampleDiff({content});
- element.loading = false;
- assert.equal(element.diffLength, 3);
- assert.isFalse(element.showNoChangeMessage());
- });
-
- test('do not show message if ignore whitespace is disabled', async () => {
- const content = [
- {
- a: ['all work and no play make andybons a dull boy'],
- b: ['elgoog elgoog elgoog'],
- },
- {
- ab: [
- 'Non eram nescius, Brute, cum, quae summis ingeniis ',
- 'exquisitaque doctrina philosophi Graeco sermone tractavissent',
- ],
- },
- ];
- await setupSampleDiff({ignore_whitespace: 'IGNORE_NONE', content});
- element.loading = false;
- assert.isFalse(element.showNoChangeMessage());
- });
- });
-
- test('getDiffLength', () => {
- const diff = createDiff();
- assert.equal(element.getDiffLength(diff), 52);
- });
});
suite('former gr-diff-builder tests', () => {
@@ -4379,71 +915,6 @@
});
});
- suite('rendering text, images and binary files', () => {
- let content: DiffContent[] = [];
-
- setup(() => {
- element.viewMode = DiffViewMode.SIDE_BY_SIDE;
- element.prefs = {
- ...DEFAULT_PREFS,
- context: -1,
- syntax_highlighting: true,
- };
- content = [
- {
- a: ['all work and no play make andybons a dull boy'],
- b: ['elgoog elgoog elgoog'],
- },
- {
- ab: [
- 'Non eram nescius, Brute, cum, quae summis ingeniis ',
- 'exquisitaque doctrina philosophi Graeco sermone tractavissent',
- ],
- },
- ];
- });
-
- test('text', async () => {
- element.diff = {...createEmptyDiff(), content};
- await waitUntil(() => element.groups.length > 2);
- await element.updateComplete;
- const bodies = [...(querySelectorAll(element.diffTable!, 'tbody') ?? [])];
- assert.equal(bodies.length, 4);
- assert.isTrue(bodies[0].innerHTML.includes('LOST'));
- assert.isTrue(bodies[1].innerHTML.includes('FILE'));
- assert.isTrue(bodies[2].innerHTML.includes('andybons a dull boy'));
- assert.isTrue(bodies[3].innerHTML.includes('Non eram nescius'));
- });
-
- test('image', async () => {
- element.diff = {...createEmptyDiff(), content, binary: true};
- element.isImageDiff = true;
- await element.updateComplete;
- const body = queryAndAssert(element, 'tbody.image-diff');
- assert.lightDom.equal(
- body,
- /* HTML */ `
- <label class="gr-diff">
- <span class="gr-diff label"> No image </span>
- </label>
- <label class="gr-diff">
- <span class="gr-diff label"> No image </span>
- </label>
- `
- );
- });
-
- test('binary', async () => {
- element.diff = {...createEmptyDiff(), content, binary: true};
- await element.updateComplete;
- const body = queryAndAssert(element, 'tbody.binary-diff');
- assert.lightDom.equal(
- body,
- /* HTML */ '<span>Difference in binary files</span>'
- );
- });
- });
-
suite('context hiding and expanding', () => {
setup(async () => {
element.diff = {
@@ -4464,12 +935,10 @@
});
test('hides lines behind two context controls', () => {
- const contextControls = element.diffTable!.querySelectorAll(
- 'gr-context-controls'
- );
+ const contextControls = queryAll(element, 'gr-context-controls');
assert.equal(contextControls.length, 2);
- const diffRows = element.diffTable!.querySelectorAll('.diff-row');
+ const diffRows = queryAll(element, '.diff-row');
// The first two are LOST and FILE line
assert.equal(diffRows.length, 2 + 1 + 1 + 1);
assert.include(diffRows[2].textContent, 'unchanged 10');
@@ -4479,16 +948,14 @@
});
test('clicking +x common lines expands those lines', async () => {
- const contextControls = element.diffTable!.querySelectorAll(
- 'gr-context-controls'
- );
+ const contextControls = queryAll(element, 'gr-context-controls');
const topExpandCommonButton =
contextControls[0].shadowRoot?.querySelectorAll<HTMLElement>(
'.showContext'
)[0];
assert.isOk(topExpandCommonButton);
assert.include(topExpandCommonButton!.textContent, '+9 common lines');
- let diffRows = element.diffTable!.querySelectorAll('.diff-row');
+ let diffRows = queryAll(element, '.diff-row');
// 5 lines:
// FILE, LOST, the changed line plus one line of context in each direction
assert.equal(diffRows.length, 5);
@@ -4496,7 +963,7 @@
topExpandCommonButton!.click();
await waitUntil(() => {
- diffRows = element.diffTable!.querySelectorAll<GrDiffRow>('.diff-row');
+ diffRows = queryAll(element, '.diff-row');
return diffRows.length === 14;
});
// 14 lines: The 5 above plus the 9 unchanged lines that were expanded
@@ -4520,12 +987,11 @@
element.unhideLine(4, Side.LEFT);
await waitUntil(() => {
- const rows =
- element.diffTable!.querySelectorAll<GrDiffRow>('.diff-row');
+ const rows = queryAll(element, '.diff-row');
return rows.length === 2 + 5 + 1 + 1 + 1;
});
- const diffRows = element.diffTable!.querySelectorAll('.diff-row');
+ const diffRows = queryAll(element, '.diff-row');
// The first two are LOST and FILE line
// Lines 3-5 (Line 4 plus 1 context in each direction) will be expanded
// Because context expanders do not hide <3 lines, lines 1-2 will also
diff --git a/polygerrit-ui/app/utils/diff-util.ts b/polygerrit-ui/app/utils/diff-util.ts
index da674df..1e5abf9 100644
--- a/polygerrit-ui/app/utils/diff-util.ts
+++ b/polygerrit-ui/app/utils/diff-util.ts
@@ -42,7 +42,7 @@
* Get the approximate length of the diff as the sum of the maximum
* length of the chunks.
*/
-export function getDiffLength(diff?: DiffInfo) {
+export function getDiffLength(diff?: DiffInfo): number {
if (!diff) return 0;
return diff.content.reduce((sum, sec) => {
if (sec.ab) {
@@ -52,3 +52,12 @@
}
}, 0);
}
+
+export function isImageDiff(diff?: DiffInfo) {
+ if (!diff) return false;
+
+ const isA = diff.meta_a?.content_type.startsWith('image/');
+ const isB = diff.meta_b?.content_type.startsWith('image/');
+
+ return !!(diff.binary && (isA || isB));
+}