Migrate gr-diff-builder-element from Polymer to plain class
Release-Notes: skip
Change-Id: I2dc83705b66c3cb11d9861b578a6db04599d6f4a
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
index dda8490..88aae5c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
@@ -313,7 +313,7 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
- element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
+ element.$.diff.diffBuilder.builder, GrDiffBuilderImage);
// Left image rendered with the parent commit's version of the file.
const leftImage =
@@ -381,7 +381,7 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
- element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
+ element.$.diff.diffBuilder.builder, GrDiffBuilderImage);
// Left image rendered with the parent commit's version of the file.
const leftImage =
@@ -445,7 +445,7 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
- element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
+ element.$.diff.diffBuilder.builder, GrDiffBuilderImage);
const leftImage =
element.$.diff.$.diffTable.querySelector('td.left img');
@@ -493,7 +493,7 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
- element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
+ element.$.diff.diffBuilder.builder, GrDiffBuilderImage);
const leftImage =
element.$.diff.$.diffTable.querySelector('td.left img');
@@ -543,7 +543,7 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
- element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
+ element.$.diff.diffBuilder.builder, GrDiffBuilderImage);
const leftImage =
element.$.diff.$.diffTable.querySelector('td.left img');
assert.isNotOk(leftImage);
@@ -623,7 +623,7 @@
test('clearBlame', () => {
element._blame = [];
- const setBlameSpy = sinon.spy(element.$.diff.$.diffBuilder, 'setBlame');
+ const setBlameSpy = sinon.spy(element.$.diff.diffBuilder, 'setBlame');
element.clearBlame();
assert.isNull(element._blame);
assert.isTrue(setBlameSpy.calledWithExactly(null));
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-element.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-element.ts
index efd6f10..d200c75 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-element.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-element.ts
@@ -1,24 +1,11 @@
/**
* @license
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Copyright 2016 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
*/
import '../gr-diff-processor/gr-diff-processor';
import '../../../elements/shared/gr-hovercard/gr-hovercard';
import './gr-diff-builder-side-by-side';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-diff-builder-element_html';
import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
import {DiffBuilder, DiffContextExpandedEventDetail} from './gr-diff-builder';
import {GrDiffBuilderSideBySide} from './gr-diff-builder-side-by-side';
@@ -26,7 +13,6 @@
import {GrDiffBuilderUnified} from './gr-diff-builder-unified';
import {GrDiffBuilderBinary} from './gr-diff-builder-binary';
import {CancelablePromise, makeCancelable} from '../../../scripts/util';
-import {customElement, property, observe} from '@polymer/decorators';
import {BlameInfo, ImageInfo} from '../../../types/common';
import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
import {CoverageRange, DiffLayer} from '../../../types/types';
@@ -53,12 +39,15 @@
hideInContextControl,
} from '../gr-diff/gr-diff-group';
import {getLineNumber, getSideByLineEl} from '../gr-diff/gr-diff-utils';
-import {fireAlert, fireEvent, fire} from '../../../utils/event-util';
-import {afterNextRender} from '@polymer/polymer/lib/utils/render-status';
+import {
+ fireAlert,
+ fire,
+ HTMLElementEventDetailType,
+} from '../../../utils/event-util';
+import {assertIsDefined} from '../../../utils/common-util';
+import {afterNextRender} from '../../../utils/dom-util';
const TRAILING_WHITESPACE_PATTERN = /\s+$/;
-
-// https://gerrit.googlesource.com/gerrit/+/234616a8627334686769f1de989d286039f4d6a5/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js#740
const COMMIT_MSG_PATH = '/COMMIT_MSG';
const COMMIT_MSG_LINE_LENGTH = 72;
@@ -111,91 +100,59 @@
}
}
-@customElement('gr-diff-builder')
-export class GrDiffBuilderElement
- extends PolymerElement
- implements GroupConsumer
-{
- static get template() {
- return htmlTemplate;
- }
-
- @property({type: Object})
+// TODO: Rename the class and the file and remove "element". This is not an
+// element anymore.
+export class GrDiffBuilderElement implements GroupConsumer {
diff?: DiffInfo;
- @property({type: String})
+ diffElement?: HTMLTableElement;
+
viewMode?: string;
- @property({type: Boolean})
isImageDiff?: boolean;
- @property({type: Object})
baseImage: ImageInfo | null = null;
- @property({type: Object})
revisionImage: ImageInfo | null = null;
- @property({type: Number})
- parentIndex?: number;
-
- @property({type: String})
path?: string;
- @property({type: Object})
prefs: DiffPreferencesInfo = createDefaultDiffPrefs();
- @property({type: Object})
renderPrefs?: RenderPreferences;
- @property({type: Object})
- _builder?: DiffBuilder;
-
- /**
- * The gr-diff-processor adds (and only adds!) to this array. It does so by
- * using `this.push()` and Polymer's two-way data binding.
- * Below (@observe('_groups.splices')) we are observing the groups that the
- * processor adds, and pass them on to the builder for rendering. Henceforth
- * the builder groups are the source of truth, because when
- * expanding/collapsing groups only the builder is updated. This field and the
- * corresponsing one in the processor are not updated.
- */
- @property({type: Array})
- _groups: GrDiffGroup[] = [];
+ useNewImageDiffUi = false;
/**
* Layers passed in from the outside.
+ *
+ * See `layersInternal` for where these layers will end up together with the
+ * internal layers.
*/
- @property({type: Array})
layers: DiffLayer[] = [];
+ // visible for testing
+ builder?: DiffBuilder;
+
/**
- * All layers, both from the outside and the default ones.
+ * All layers, both from the outside and the default ones. See `layers` for
+ * the property that can be set from the outside.
*/
- @property({type: Array})
- _layers: DiffLayer[] = [];
+ // visible for testing
+ layersInternal: DiffLayer[] = [];
- @property({type: Boolean})
- _showTabs?: boolean;
+ // visible for testing
+ showTabs?: boolean;
- @property({type: Boolean})
- _showTrailingWhitespace?: boolean;
-
- @property({type: Array})
- commentRanges: CommentRangeLayer[] = [];
-
- @property({type: Array, observer: 'coverageObserver'})
- coverageRanges: CoverageRange[] = [];
-
- @property({type: Boolean})
- useNewImageDiffUi = false;
+ // visible for testing
+ showTrailingWhitespace?: boolean;
/**
* The promise last returned from `render()` while the asynchronous
* rendering is running - `null` otherwise. Provides a `cancel()`
* method that rejects it with `{isCancelled: true}`.
*/
- @property({type: Object})
- _cancelableRenderPromise: CancelablePromise<unknown> | null = null;
+ private cancelableRenderPromise: CancelablePromise<unknown> | null = null;
private coverageLayerLeft = new GrCoverageLayer(Side.LEFT);
@@ -207,48 +164,16 @@
processor = new GrDiffProcessor();
constructor() {
- super();
- afterNextRender(this, () => {
- this.addEventListener(
- 'diff-context-expanded',
- (e: CustomEvent<DiffContextExpandedEventDetail>) => {
- // Don't stop propagation. The host may listen for reporting or
- // resizing.
- this.replaceGroup(e.detail.contextGroup, e.detail.groups);
- }
- );
- });
this.processor.consumer = this;
}
- override disconnectedCallback() {
- this.processor.cancel();
- if (this._builder) {
- this._builder.clear();
- }
- super.disconnectedCallback();
+ updateCommentRanges(ranges: CommentRangeLayer[]) {
+ this.rangeLayer.updateRanges(ranges);
}
- get diffElement(): HTMLTableElement {
- // Not searching in shadowRoot, because the diff table is slotted!
- return this.querySelector('#diffTable') as HTMLTableElement;
- }
-
- @observe('commentRanges.*')
- rangeObserver() {
- this.rangeLayer.updateRanges(this.commentRanges);
- }
-
- coverageObserver(coverageRanges: CoverageRange[]) {
- const leftRanges = coverageRanges.filter(
- range => range && range.side === Side.LEFT
- );
- this.coverageLayerLeft.setRanges(leftRanges);
-
- const rightRanges = coverageRanges.filter(
- range => range && range.side === Side.RIGHT
- );
- this.coverageLayerRight.setRanges(rightRanges);
+ updateCoverageRanges(rs: CoverageRange[]) {
+ this.coverageLayerLeft.setRanges(rs.filter(r => r?.side === Side.LEFT));
+ this.coverageLayerRight.setRanges(rs.filter(r => r?.side === Side.RIGHT));
}
render(keyLocations: KeyLocations): void {
@@ -256,42 +181,44 @@
// installed, and |render| satisfies the requirement, however,
// |attached| doesn't because in the diff view page, the element is
// attached before plugins are installed.
- this._setupAnnotationLayers();
+ this.setupAnnotationLayers();
- this._showTabs = this.prefs.show_tabs;
- this._showTrailingWhitespace = this.prefs.show_whitespace_errors;
+ this.showTabs = this.prefs.show_tabs;
+ this.showTrailingWhitespace = this.prefs.show_whitespace_errors;
// Stop the processor if it's running.
this.cancel();
- if (this._builder) {
- this._builder.clear();
- }
- if (!this.diff) {
- throw Error('Cannot render a diff without DiffInfo.');
- }
- this._builder = this._getDiffBuilder();
+ this.builder?.clear();
+ assertIsDefined(this.diff, 'diff');
+ assertIsDefined(this.diffElement, 'diff table');
+ this.builder = this.getDiffBuilder();
this.processor.context = this.prefs.context;
this.processor.keyLocations = keyLocations;
- this._clearDiffContent();
- this._builder.addColumns(
+ this.diffElement.addEventListener(
+ 'diff-context-expanded',
+ this.onDiffContextExpanded
+ );
+
+ this.clearDiffContent();
+ this.builder.addColumns(
this.diffElement,
getLineNumberCellWidth(this.prefs)
);
const isBinary = !!(this.isImageDiff || this.diff.binary);
- fireEvent(this, 'render-start');
- this._cancelableRenderPromise = makeCancelable(
+ this.fireDiffEvent('render-start', {});
+ this.cancelableRenderPromise = makeCancelable(
this.processor
.process(this.diff.content, isBinary)
.then(() => {
if (this.isImageDiff) {
- (this._builder as GrDiffBuilderImage).renderDiff();
+ (this.builder as GrDiffBuilderImage).renderDiff();
}
- afterNextRender(this, () => fireEvent(this, 'render-content'));
+ afterNextRender(() => this.fireDiffEvent('render-content', {}));
})
// Mocha testing does not like uncaught rejections, so we catch
// the cancels which are expected and should not throw errors in
@@ -301,17 +228,39 @@
return;
})
.finally(() => {
- this._cancelableRenderPromise = null;
+ this.cancelableRenderPromise = null;
})
);
}
- _setupAnnotationLayers() {
+ private onDiffContextExpanded = (
+ e: CustomEvent<DiffContextExpandedEventDetail>
+ ) => {
+ // Don't stop propagation. The host may listen for reporting or
+ // resizing.
+ this.replaceGroup(e.detail.contextGroup, e.detail.groups);
+ };
+
+ private fireDiffEvent<K extends keyof HTMLElementEventMap>(
+ type: K,
+ detail: HTMLElementEventDetailType<K>
+ ) {
+ assertIsDefined(this.diffElement, 'diff table');
+ fire(this.diffElement, type, detail);
+ }
+
+ private fireDiffEventRenderProgress(detail: RenderProgressEventDetail) {
+ assertIsDefined(this.diffElement, 'diff table');
+ fire(this.diffElement, 'render-progress', detail);
+ }
+
+ // visible for testing
+ setupAnnotationLayers() {
const layers: DiffLayer[] = [
- this._createTrailingWhitespaceLayer(),
- this._createIntralineLayer(),
- this._createTabIndicatorLayer(),
- this._createSpecialCharacterIndicatorLayer(),
+ this.createTrailingWhitespaceLayer(),
+ this.createIntralineLayer(),
+ this.createTabIndicatorLayer(),
+ this.createSpecialCharacterIndicatorLayer(),
this.rangeLayer,
this.coverageLayerLeft,
this.coverageLayerRight,
@@ -320,15 +269,15 @@
if (this.layers) {
layers.push(...this.layers);
}
- this._layers = layers;
+ this.layersInternal = layers;
}
getContentTdByLine(lineNumber: LineNumber, side?: Side, root?: Element) {
- if (!this._builder) return null;
- return this._builder.getContentTdByLine(lineNumber, side, root);
+ if (!this.builder) return null;
+ return this.builder.getContentTdByLine(lineNumber, side, root);
}
- _getDiffRowByChild(child: Element) {
+ private getDiffRowByChild(child: Element) {
while (!child.classList.contains('diff-row') && child.parentElement) {
child = child.parentElement;
}
@@ -342,23 +291,23 @@
const side = getSideByLineEl(lineEl);
// Performance optimization because we already have an element in the
// correct row
- const row = this._getDiffRowByChild(lineEl);
+ const row = this.getDiffRowByChild(lineEl);
return this.getContentTdByLine(line, side, row);
}
getLineElByNumber(lineNumber: LineNumber, side?: Side) {
- if (!this._builder) return null;
- return this._builder.getLineElByNumber(lineNumber, side);
+ if (!this.builder) return null;
+ return this.builder.getLineElByNumber(lineNumber, side);
}
getLineNumberRows() {
- if (!this._builder) return [];
- return this._builder.getLineNumberRows();
+ if (!this.builder) return [];
+ return this.builder.getLineNumberRows();
}
getLineNumEls(side: Side) {
- if (!this._builder) return [];
- return this._builder.getLineNumEls(side);
+ if (!this.builder) return [];
+ return this.builder.getLineNumEls(side);
}
/**
@@ -370,8 +319,8 @@
* @param side The side the line number refer to.
*/
unhideLine(lineNum: number, side: Side) {
- if (!this._builder) return;
- const group = this._builder.findGroup(side, lineNum);
+ if (!this.builder) return;
+ const group = this.builder.findGroup(side, lineNum);
// Cannot unhide a line that is not part of the diff.
if (!group) return;
// If it's already visible, great!
@@ -414,45 +363,50 @@
contextGroup: GrDiffGroup,
newGroups: readonly GrDiffGroup[]
) {
- if (!this._builder) return;
- fireEvent(this, 'render-start');
+ if (!this.builder) return;
+ this.fireDiffEvent('render-start', {});
const linesRendered = newGroups.reduce(
(sum, group) => sum + group.lines.length,
0
);
- this._builder.replaceGroup(contextGroup, newGroups);
- afterNextRender(this, () => {
- fire(this, 'render-progress', {linesRendered});
- fireEvent(this, 'render-content');
+ this.builder.replaceGroup(contextGroup, newGroups);
+ afterNextRender(() => {
+ this.fireDiffEvent('render-progress', {linesRendered});
+ this.fireDiffEvent('render-content', {});
});
}
cancel() {
this.processor.cancel();
- if (this._cancelableRenderPromise) {
- this._cancelableRenderPromise.cancel();
- this._cancelableRenderPromise = null;
- }
+ this.builder?.clear();
+ this.cancelableRenderPromise?.cancel();
+ this.cancelableRenderPromise = null;
+ this.diffElement?.removeEventListener(
+ 'diff-context-expanded',
+ this.onDiffContextExpanded
+ );
}
- _handlePreferenceError(pref: string): never {
+ // visible for testing
+ handlePreferenceError(pref: string): never {
const message =
`The value of the '${pref}' user preference is ` +
'invalid. Fix in diff preferences';
- fireAlert(this, message);
+ assertIsDefined(this.diffElement, 'diff table');
+ fireAlert(this.diffElement, message);
throw Error(`Invalid preference value: ${pref}`);
}
- _getDiffBuilder(): DiffBuilder {
- if (!this.diff) {
- throw Error('Cannot render a diff without DiffInfo.');
- }
+ // visible for testing
+ getDiffBuilder(): DiffBuilder {
+ assertIsDefined(this.diff, 'diff');
+ assertIsDefined(this.diffElement, 'diff table');
if (isNaN(this.prefs.tab_size) || this.prefs.tab_size <= 0) {
- this._handlePreferenceError('tab size');
+ this.handlePreferenceError('tab size');
}
if (isNaN(this.prefs.line_length) || this.prefs.line_length <= 0) {
- this._handlePreferenceError('diff width');
+ this.handlePreferenceError('diff width');
}
const localPrefs = {...this.prefs};
@@ -481,7 +435,7 @@
this.diff,
localPrefs,
this.diffElement,
- this._layers,
+ this.layersInternal,
this.renderPrefs
);
} else if (this.viewMode === DiffViewMode.UNIFIED) {
@@ -489,7 +443,7 @@
this.diff,
localPrefs,
this.diffElement,
- this._layers,
+ this.layersInternal,
this.renderPrefs
);
}
@@ -499,7 +453,8 @@
return builder;
}
- _clearDiffContent() {
+ private clearDiffContent() {
+ assertIsDefined(this.diffElement, 'diff table');
this.diffElement.innerHTML = '';
}
@@ -508,22 +463,23 @@
* server into chunks.
*/
clearGroups() {
- if (!this._builder) return;
- this._builder.clearGroups();
+ if (!this.builder) return;
+ this.builder.clearGroups();
}
/**
* Called when the processor is done converting a chunk of the diff.
*/
addGroup(group: GrDiffGroup) {
- if (!this._builder) return;
- this._builder.addGroups([group]);
- afterNextRender(this, () =>
- fire(this, 'render-progress', {linesRendered: group.lines.length})
+ if (!this.builder) return;
+ this.builder.addGroups([group]);
+ afterNextRender(() =>
+ this.fireDiffEventRenderProgress({linesRendered: group.lines.length})
);
}
- _createIntralineLayer(): DiffLayer {
+ // visible for testing
+ createIntralineLayer(): DiffLayer {
return {
// Take a DIV.contentText element and a line object with intraline
// differences to highlight and apply them to the element as
@@ -555,8 +511,9 @@
};
}
- _createTabIndicatorLayer(): DiffLayer {
- const show = () => this._showTabs;
+ // visible for testing
+ createTabIndicatorLayer(): DiffLayer {
+ const show = () => this.showTabs;
return {
annotate(contentEl: HTMLElement, _: HTMLElement, line: GrDiffLine) {
// If visible tabs are disabled, do nothing.
@@ -570,7 +527,7 @@
};
}
- _createSpecialCharacterIndicatorLayer(): DiffLayer {
+ private createSpecialCharacterIndicatorLayer(): DiffLayer {
return {
annotate(contentEl: HTMLElement, _: HTMLElement, line: GrDiffLine) {
// Find and annotate the locations of soft hyphen (\u00AD)
@@ -586,8 +543,9 @@
};
}
- _createTrailingWhitespaceLayer(): DiffLayer {
- const show = () => this._showTrailingWhitespace;
+ // visible for testing
+ createTrailingWhitespaceLayer(): DiffLayer {
+ const show = () => this.showTrailingWhitespace;
return {
annotate(contentEl: HTMLElement, _: HTMLElement, line: GrDiffLine) {
@@ -615,18 +573,12 @@
}
setBlame(blame: BlameInfo[] | null) {
- if (!this._builder) return;
- this._builder.setBlame(blame ?? []);
+ if (!this.builder) return;
+ this.builder.setBlame(blame ?? []);
}
updateRenderPrefs(renderPrefs: RenderPreferences) {
- this._builder?.updateRenderPrefs(renderPrefs);
+ this.builder?.updateRenderPrefs(renderPrefs);
this.processor.updateRenderPrefs(renderPrefs);
}
}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'gr-diff-builder': GrDiffBuilderElement;
- }
-}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-element_html.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-element_html.ts
deleted file mode 100644
index bd0e034..0000000
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-element_html.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {html} from '@polymer/polymer/lib/utils/html-tag';
-
-export const htmlTemplate = html`
- <div class="contentWrapper">
- <slot></slot>
- </div>
-`;
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-element_test.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-element_test.ts
index b441ad3..8ae08f4 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-element_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-element_test.ts
@@ -10,11 +10,14 @@
createEmptyDiff,
} from '../../../test/test-data-generators';
import './gr-diff-builder-element';
-import {queryAndAssert, stubBaseUrl} from '../../../test/test-utils';
+import {
+ nextRender,
+ queryAndAssert,
+ stubBaseUrl,
+} from '../../../test/test-utils';
import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
import {GrDiffLine, GrDiffLineType} from '../gr-diff/gr-diff-line';
import {GrDiffBuilderSideBySide} from './gr-diff-builder-side-by-side';
-import {html} from '@polymer/polymer/lib/utils/html-tag';
import {
DiffContent,
DiffInfo,
@@ -24,35 +27,20 @@
Side,
} from '../../../api/diff';
import {stubRestApi} from '../../../test/test-utils';
-import {afterNextRender} from '@polymer/polymer/lib/utils/render-status';
import {GrDiffBuilderLegacy} from './gr-diff-builder-legacy';
import {waitForEventOnce} from '../../../utils/event-util';
import {GrDiffBuilderElement} from './gr-diff-builder-element';
import {createDefaultDiffPrefs} from '../../../constants/constants';
import {KeyLocations} from '../gr-diff-processor/gr-diff-processor';
import {BlameInfo} from '../../../types/common';
-
-const basicFixture = fixtureFromTemplate(html`
- <gr-diff-builder>
- <table id="diffTable"></table>
- </gr-diff-builder>
-`);
-
-const divWithTextFixture = fixtureFromTemplate(html`
- <div>Lorem ipsum dolor sit amet, suspendisse inceptos vehicula</div>
-`);
-
-const mockDiffFixture = fixtureFromTemplate(html`
- <gr-diff-builder view-mode="SIDE_BY_SIDE">
- <table id="diffTable"></table>
- </gr-diff-builder>
-`);
+import {fixture, html} from '@open-wc/testing-helpers';
const DEFAULT_PREFS = createDefaultDiffPrefs();
suite('gr-diff-builder tests', () => {
let element: GrDiffBuilderElement;
let builder: GrDiffBuilderLegacy;
+ let diffTable: HTMLTableElement;
const LINE_BREAK_HTML = '<span class="style-scope gr-diff br"></span>';
const WBR_HTML = '<wbr class="style-scope gr-diff">';
@@ -61,7 +49,7 @@
builder = new GrDiffBuilderSideBySide(
createEmptyDiff(),
{...createDefaultDiffPrefs(), ...prefs},
- element.diffElement
+ diffTable
);
};
@@ -71,8 +59,10 @@
return line;
};
- setup(() => {
- element = basicFixture.instantiate() as GrDiffBuilderElement;
+ setup(async () => {
+ diffTable = await fixture(html`<table id="diffTable"></table>`);
+ element = new GrDiffBuilderElement();
+ element.diffElement = diffTable;
stubRestApi('getLoggedIn').returns(Promise.resolve(false));
stubRestApi('getProjectConfig').returns(Promise.resolve(createConfig()));
stubBaseUrl('/r');
@@ -107,7 +97,7 @@
tab_size: 4,
line_length: 50,
};
- builder = element._getDiffBuilder() as GrDiffBuilderLegacy;
+ builder = element.getDiffBuilder() as GrDiffBuilderLegacy;
assert.equal(builder._prefs.line_length, 50);
});
@@ -120,7 +110,7 @@
tab_size: 4,
line_length: 50,
};
- builder = element._getDiffBuilder() as GrDiffBuilderLegacy;
+ builder = element.getDiffBuilder() as GrDiffBuilderLegacy;
assert.equal(builder._prefs.line_length, 72);
});
});
@@ -142,13 +132,13 @@
test('_handlePreferenceError throws with invalid preference', () => {
element.prefs = {...createDefaultDiffPrefs(), tab_size: 0};
- assert.throws(() => element._getDiffBuilder());
+ assert.throws(() => element.getDiffBuilder());
});
test('_handlePreferenceError triggers alert and javascript error', () => {
const errorStub = sinon.stub();
- element.addEventListener('show-alert', errorStub);
- assert.throws(() => element._handlePreferenceError('tab size'));
+ diffTable.addEventListener('show-alert', errorStub);
+ assert.throws(() => element.handlePreferenceError('tab size'));
assert.equal(
errorStub.lastCall.args[0].detail.message,
"The value of the 'tab size' user preference is invalid. " +
@@ -167,11 +157,13 @@
return Array.from(str).slice(start, end).join('');
}
- setup(() => {
- el = divWithTextFixture.instantiate() as HTMLElement;
+ setup(async () => {
+ el = await fixture(html`
+ <div>Lorem ipsum dolor sit amet, suspendisse inceptos vehicula</div>
+ `);
str = el.textContent ?? '';
annotateElementSpy = sinon.spy(GrAnnotation, 'annotateElement');
- layer = document.createElement('gr-diff-builder')._createIntralineLayer();
+ layer = element.createIntralineLayer();
});
test('annotate no highlights', () => {
@@ -297,14 +289,12 @@
});
suite('tab indicators', () => {
- let element: GrDiffBuilderElement;
let layer: DiffLayer;
const lineNumberEl = document.createElement('td');
setup(() => {
- element = basicFixture.instantiate() as GrDiffBuilderElement;
- element._showTabs = true;
- layer = element._createTabIndicatorLayer();
+ element.showTabs = true;
+ layer = element.createTabIndicatorLayer();
});
test('does nothing with empty line', () => {
@@ -347,7 +337,7 @@
});
test('does not annotate when disabled', () => {
- element._showTabs = false;
+ element.showTabs = false;
const str = '\tlorem upsum';
const l = line(str);
@@ -403,49 +393,44 @@
});
suite('layers', () => {
- let element: GrDiffBuilderElement;
let initialLayersCount = 0;
let withLayerCount = 0;
setup(() => {
const layers: DiffLayer[] = [];
- element = basicFixture.instantiate() as GrDiffBuilderElement;
element.layers = layers;
- element._showTrailingWhitespace = true;
- element._setupAnnotationLayers();
- initialLayersCount = element._layers.length;
+ element.showTrailingWhitespace = true;
+ element.setupAnnotationLayers();
+ initialLayersCount = element.layersInternal.length;
});
test('no layers', () => {
- element._setupAnnotationLayers();
- assert.equal(element._layers.length, initialLayersCount);
+ element.setupAnnotationLayers();
+ assert.equal(element.layersInternal.length, initialLayersCount);
});
suite('with layers', () => {
const layers: DiffLayer[] = [{annotate: () => {}}, {annotate: () => {}}];
setup(() => {
- element = basicFixture.instantiate() as GrDiffBuilderElement;
element.layers = layers;
- element._showTrailingWhitespace = true;
- element._setupAnnotationLayers();
- withLayerCount = element._layers.length;
+ element.showTrailingWhitespace = true;
+ element.setupAnnotationLayers();
+ withLayerCount = element.layersInternal.length;
});
test('with layers', () => {
- element._setupAnnotationLayers();
- assert.equal(element._layers.length, withLayerCount);
+ element.setupAnnotationLayers();
+ assert.equal(element.layersInternal.length, withLayerCount);
assert.equal(initialLayersCount + layers.length, withLayerCount);
});
});
});
suite('trailing whitespace', () => {
- let element: GrDiffBuilderElement;
let layer: DiffLayer;
const lineNumberEl = document.createElement('td');
setup(() => {
- element = basicFixture.instantiate() as GrDiffBuilderElement;
- element._showTrailingWhitespace = true;
- layer = element._createTrailingWhitespaceLayer();
+ element.showTrailingWhitespace = true;
+ layer = element.createTrailingWhitespaceLayer();
});
test('does nothing with empty line', () => {
@@ -515,7 +500,7 @@
});
test('does not annotate when disabled', () => {
- element._showTrailingWhitespace = false;
+ element.showTrailingWhitespace = false;
const str = 'lorem upsum\t \t ';
const l = line(str);
const el = document.createElement('div');
@@ -532,7 +517,6 @@
let content: DiffContent[] = [];
setup(() => {
- element = basicFixture.instantiate() as GrDiffBuilderElement;
element.viewMode = 'SIDE_BY_SIDE';
processStub = sinon
.stub(element.processor, 'process')
@@ -560,7 +544,7 @@
test('text', async () => {
element.diff = {...createEmptyDiff(), content};
element.render(keyLocations);
- await waitForEventOnce(element, 'render-content');
+ await waitForEventOnce(diffTable, 'render-content');
assert.isTrue(processStub.calledOnce);
assert.isFalse(processStub.lastCall.args[1]);
});
@@ -569,7 +553,7 @@
element.diff = {...createEmptyDiff(), content, binary: true};
element.isImageDiff = true;
element.render(keyLocations);
- await waitForEventOnce(element, 'render-content');
+ await waitForEventOnce(diffTable, 'render-content');
assert.isTrue(processStub.calledOnce);
assert.isTrue(processStub.lastCall.args[1]);
});
@@ -577,7 +561,7 @@
test('binary', async () => {
element.diff = {...createEmptyDiff(), content, binary: true};
element.render(keyLocations);
- await waitForEventOnce(element, 'render-content');
+ await waitForEventOnce(diffTable, 'render-content');
assert.isTrue(processStub.calledOnce);
assert.isTrue(processStub.lastCall.args[1]);
});
@@ -605,11 +589,10 @@
],
},
];
- element = basicFixture.instantiate() as GrDiffBuilderElement;
- dispatchStub = sinon.stub(element, 'dispatchEvent');
- outputEl = queryAndAssert(element, '#diffTable');
+ dispatchStub = sinon.stub(diffTable, 'dispatchEvent');
+ outputEl = element.diffElement!;
keyLocations = {left: {}, right: {}};
- sinon.stub(element, '_getDiffBuilder').callsFake(() => {
+ sinon.stub(element, 'getDiffBuilder').callsFake(() => {
builder = new GrDiffBuilderSideBySide(
{...createEmptyDiff(), content},
prefs,
@@ -656,9 +639,13 @@
});
test('render-start and render-content are fired', async () => {
- await new Promise(resolve => afterNextRender(element, resolve));
- const firedEventTypes = dispatchStub.getCalls().map(c => c.args[0].type);
+ await nextRender();
+ let firedEventTypes = dispatchStub.getCalls().map(c => c.args[0].type);
assert.include(firedEventTypes, 'render-start');
+ assert.include(firedEventTypes, 'render-progress');
+
+ await nextRender();
+ firedEventTypes = dispatchStub.getCalls().map(c => c.args[0].type);
assert.include(firedEventTypes, 'render-content');
});
@@ -673,11 +660,7 @@
let dispatchStub: sinon.SinonStub;
setup(async () => {
- element = basicFixture.instantiate() as GrDiffBuilderElement;
- dispatchStub = sinon.stub(element, 'dispatchEvent');
- const afterNextRenderPromise = new Promise(resolve => {
- afterNextRender(element, resolve);
- });
+ dispatchStub = sinon.stub(diffTable, 'dispatchEvent');
element.diff = {
...createEmptyDiff(),
content: [
@@ -695,14 +678,14 @@
};
element.render(keyLocations);
// Make sure all listeners are installed.
- await afterNextRenderPromise;
+ await nextRender();
});
test('hides lines behind two context controls', () => {
- const contextControls = element.querySelectorAll('gr-context-controls');
+ const contextControls = diffTable.querySelectorAll('gr-context-controls');
assert.equal(contextControls.length, 2);
- const diffRows = element.querySelectorAll('.diff-row');
+ const diffRows = diffTable.querySelectorAll('.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');
@@ -712,7 +695,7 @@
});
test('clicking +x common lines expands those lines', () => {
- const contextControls = element.querySelectorAll('gr-context-controls');
+ const contextControls = diffTable.querySelectorAll('gr-context-controls');
const topExpandCommonButton =
contextControls[0].shadowRoot?.querySelectorAll<HTMLElement>(
'.showContext'
@@ -720,7 +703,7 @@
assert.isOk(topExpandCommonButton);
assert.include(topExpandCommonButton!.textContent, '+9 common lines');
topExpandCommonButton!.click();
- const diffRows = element.querySelectorAll('.diff-row');
+ const diffRows = diffTable.querySelectorAll('.diff-row');
// The first two are LOST and FILE line
assert.equal(diffRows.length, 2 + 10 + 1 + 1);
assert.include(diffRows[2].textContent, 'unchanged 1');
@@ -742,7 +725,7 @@
dispatchStub.reset();
element.unhideLine(4, Side.LEFT);
- const diffRows = element.querySelectorAll('.diff-row');
+ const diffRows = diffTable.querySelectorAll('.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
@@ -759,20 +742,19 @@
assert.include(diffRows[8].textContent, 'after');
assert.include(diffRows[9].textContent, 'unchanged 11');
- await new Promise(resolve => afterNextRender(element, resolve));
+ await nextRender();
const firedEventTypes = dispatchStub.getCalls().map(c => c.args[0].type);
assert.include(firedEventTypes, 'render-content');
});
});
suite('mock-diff', () => {
- let element: GrDiffBuilderElement;
let builder: GrDiffBuilderSideBySide;
let diff: DiffInfo;
let keyLocations: KeyLocations;
setup(() => {
- element = mockDiffFixture.instantiate() as GrDiffBuilderElement;
+ element.viewMode = DiffViewMode.SIDE_BY_SIDE;
diff = createDiff();
element.diff = diff;
@@ -785,11 +767,11 @@
tab_size: 4,
};
element.render(keyLocations);
- builder = element._builder as GrDiffBuilderSideBySide;
+ builder = element.builder as GrDiffBuilderSideBySide;
});
test('aria-labels on added line numbers', () => {
- const deltaLineNumberButton = element.diffElement.querySelectorAll(
+ const deltaLineNumberButton = diffTable.querySelectorAll(
'.lineNumButton.right'
)[5];
@@ -798,7 +780,7 @@
});
test('aria-labels on removed line numbers', () => {
- const deltaLineNumberButton = element.diffElement.querySelectorAll(
+ const deltaLineNumberButton = diffTable.querySelectorAll(
'.lineNumButton.left'
)[10];
@@ -826,7 +808,7 @@
});
test('getContentTdByLineEl works both with button and td', () => {
- const diffRow = element.diffElement.querySelectorAll('tr.diff-row')[2];
+ const diffRow = diffTable.querySelectorAll('tr.diff-row')[2];
const lineNumTdLeft = queryAndAssert(diffRow, 'td.lineNum.left');
const lineNumButtonLeft = queryAndAssert(lineNumTdLeft, 'button');
@@ -918,7 +900,7 @@
const contentEl = builder.getContentByLine(
5,
Side.LEFT,
- element.$.diffTable as HTMLTableElement
+ element.diffElement as HTMLTableElement
);
assert.isOk(contentEl);
const lineNumberEl = builder.getLineNumberEl(contentEl!, Side.LEFT);
@@ -931,7 +913,7 @@
const contentEl = builder.getContentByLine(
5,
Side.RIGHT,
- element.$.diffTable as HTMLTableElement
+ element.diffElement as HTMLTableElement
);
assert.isOk(contentEl);
const lineNumberEl = builder.getLineNumberEl(contentEl!, Side.RIGHT);
@@ -944,12 +926,12 @@
// Re-render as unified:
element.viewMode = 'UNIFIED_DIFF';
element.render(keyLocations);
- builder = element._builder as GrDiffBuilderSideBySide;
+ builder = element.builder as GrDiffBuilderSideBySide;
const contentEl = builder.getContentByLine(
5,
Side.LEFT,
- element.$.diffTable as HTMLTableElement
+ element.diffElement as HTMLTableElement
);
assert.isOk(contentEl);
const lineNumberEl = builder.getLineNumberEl(contentEl!, Side.LEFT);
@@ -962,12 +944,12 @@
// Re-render as unified:
element.viewMode = 'UNIFIED_DIFF';
element.render(keyLocations);
- builder = element._builder as GrDiffBuilderSideBySide;
+ builder = element.builder as GrDiffBuilderSideBySide;
const contentEl = builder.getContentByLine(
5,
Side.RIGHT,
- element.$.diffTable as HTMLTableElement
+ element.diffElement as HTMLTableElement
);
assert.isOk(contentEl);
const lineNumberEl = builder.getLineNumberEl(contentEl!, Side.RIGHT);
@@ -980,7 +962,7 @@
const startElem = builder.getContentByLine(
5,
Side.LEFT,
- element.$.diffTable as HTMLTableElement
+ element.diffElement as HTMLTableElement
);
assert.isOk(startElem);
const expectedStartString = diff.content[2].ab?.[0];
@@ -996,7 +978,7 @@
const startElem = builder.getContentByLine(
5,
Side.RIGHT,
- element.$.diffTable as HTMLTableElement
+ element.diffElement as HTMLTableElement
);
const expectedStartString = diff.content[1].b?.[0];
const expectedNextString = diff.content[1].b?.[1];
@@ -1012,12 +994,12 @@
// Re-render as unified:
element.viewMode = 'UNIFIED_DIFF';
element.render(keyLocations);
- builder = element._builder as GrDiffBuilderSideBySide;
+ builder = element.builder as GrDiffBuilderSideBySide;
const startElem = builder.getContentByLine(
5,
Side.LEFT,
- element.$.diffTable as HTMLTableElement
+ element.diffElement as HTMLTableElement
);
const expectedStartString = diff.content[2].ab?.[0];
const expectedNextString = diff.content[2].ab?.[1];
@@ -1033,12 +1015,12 @@
// Re-render as unified:
element.viewMode = 'UNIFIED_DIFF';
element.render(keyLocations);
- builder = element._builder as GrDiffBuilderSideBySide;
+ builder = element.builder as GrDiffBuilderSideBySide;
const startElem = builder.getContentByLine(
5,
Side.RIGHT,
- element.$.diffTable as HTMLTableElement
+ element.diffElement as HTMLTableElement
);
const expectedStartString = diff.content[1].b?.[0];
const expectedNextString = diff.content[1].b?.[1];
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor_test.js b/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor_test.js
index f48d673..9c6fad6 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor_test.js
+++ b/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor_test.js
@@ -19,11 +19,11 @@
import '../gr-diff/gr-diff.js';
import './gr-diff-cursor.js';
import {fixture, html} from '@open-wc/testing-helpers';
-import {listenOnce, mockPromise} from '../../../test/test-utils.js';
+import {mockPromise} from '../../../test/test-utils.js';
import {createDiff} from '../../../test/test-data-generators.js';
import {createDefaultDiffPrefs} from '../../../constants/constants.js';
import {GrDiffCursor} from './gr-diff-cursor.js';
-import {afterNextRender} from '@polymer/polymer/lib/utils/render-status';
+import {waitForEventOnce} from '../../../utils/event-util.js';
suite('gr-diff-cursor tests', () => {
let cursor;
@@ -110,7 +110,8 @@
// 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;
- await flush();
+ await waitForEventOnce(diffElement, 'render');
+
cursor._updateStops();
const chunks = Array.from(diffElement.root.querySelectorAll(
@@ -160,7 +161,7 @@
};
diffElement.diff = diff;
- await new Promise(resolve => afterNextRender(diffElement, resolve));
+ await waitForEventOnce(diffElement, 'render');
cursor._updateStops();
const chunks = Array.from(diffElement.root.querySelectorAll(
@@ -215,8 +216,7 @@
suite('unified diff', () => {
setup(async () => {
diffElement.viewMode = 'UNIFIED_DIFF';
- // We must allow the diff to re-render after setting the viewMode.
- await new Promise(resolve => afterNextRender(diffElement, resolve));
+ await waitForEventOnce(diffElement, 'render');
cursor.reInitCursor();
});
@@ -453,7 +453,7 @@
});
diffElement._diffChanged(createDiff());
- await new Promise(resolve => afterNextRender(diffElement, resolve));
+ await waitForEventOnce(diffElement, 'render');
cursor.reInitCursor();
assert.isFalse(moveToNumStub.called);
assert.isTrue(moveToChunkStub.called);
@@ -472,7 +472,7 @@
cursor.side = 'right';
diffElement._diffChanged(createDiff());
- await new Promise(resolve => afterNextRender(diffElement, resolve));
+ await waitForEventOnce(diffElement, 'render');
cursor.reInitCursor();
assert.isFalse(moveToChunkStub.called);
assert.isTrue(moveToNumStub.called);
@@ -601,7 +601,7 @@
MockInteractions.tap(diffElement.shadowRoot
.querySelector('gr-context-controls').shadowRoot
.querySelector('.showContext'));
- await new Promise(resolve => afterNextRender(diffElement, resolve));
+ await waitForEventOnce(diffElement, 'render');
assert.isTrue(cursor._updateStops.called);
});
@@ -641,13 +641,10 @@
}
test('do not skip loading diffs', async () => {
- const diffRenderedPromises =
- diffElements.map(diffEl => listenOnce(diffEl, 'render'));
-
diffElements[0].diff = createDiff();
diffElements[2].diff = createDiff();
- await Promise.all([diffRenderedPromises[0], diffRenderedPromises[2]]);
- await new Promise(resolve => afterNextRender(diffElements[0], resolve));
+ await waitForEventOnce(diffElements[0], 'render');
+ await waitForEventOnce(diffElements[2], 'render');
const lastLine = diffElements[0].diff.meta_b.lines;
@@ -668,8 +665,7 @@
// Diff 1 finishing to load
diffElements[1].diff = createDiff();
- await diffRenderedPromises[1];
- await new Promise(resolve => afterNextRender(diffElements[0], resolve));
+ await waitForEventOnce(diffElements[1], 'render');
// Now we can go down
cursor.moveDown();
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 e5f9de0..40696fb 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
@@ -100,7 +100,6 @@
export interface GrDiff {
$: {
- diffBuilder: GrDiffBuilderElement;
diffTable: HTMLTableElement;
};
}
@@ -179,7 +178,7 @@
@property({type: Object})
highlightRange?: CommentRange;
- @property({type: Array})
+ @property({type: Array, observer: '_coverageRangesObserver'})
coverageRanges: CoverageRange[] = [];
@property({type: Boolean, observer: '_lineWrappingObserver'})
@@ -248,9 +247,6 @@
@property({type: Object, observer: '_blameChanged'})
blame: BlameInfo[] | null = null;
- @property({type: Number})
- parentIndex?: number;
-
@property({type: Boolean})
showNewlineWarningLeft = false;
@@ -298,6 +294,9 @@
private highlights = new GrDiffHighlight();
+ // visible for testing
+ diffBuilder = new GrDiffBuilderElement();
+
constructor() {
super();
this._setLoading(true);
@@ -321,11 +320,12 @@
this._unobserveNodes();
this.diffSelection.cleanup();
this.highlights.cleanup();
+ this.diffBuilder.cancel();
super.disconnectedCallback();
}
getLineNumEls(side: Side): HTMLElement[] {
- return this.$.diffBuilder.getLineNumEls(side);
+ return this.diffBuilder.getLineNumEls(side);
}
showNoChangeMessage(
@@ -426,19 +426,25 @@
cr.side === removedCommentRange.side &&
rangesEqual(cr.range, removedCommentRange.range)
);
- this.splice('_commentRanges', i, 1);
+ this._commentRanges.splice(i, 1);
}
- if (addedCommentRanges && addedCommentRanges.length) {
- this.push('_commentRanges', ...addedCommentRanges);
+ if (addedCommentRanges?.length) {
+ this._commentRanges.push(...addedCommentRanges);
}
if (this.highlightRange) {
- this.push('_commentRanges', {
+ this._commentRanges.push({
side: Side.RIGHT,
range: this.highlightRange,
rootId: '',
});
}
+
+ this.diffBuilder.updateCommentRanges(this._commentRanges);
+ }
+
+ _coverageRangesObserver() {
+ this.diffBuilder.updateCoverageRanges(this.coverageRanges);
}
/**
@@ -483,7 +489,7 @@
/** Cancel any remaining diff builder rendering work. */
cancel() {
- this.$.diffBuilder.cancel();
+ this.diffBuilder.cancel();
this.renderDiffTableTask?.cancel();
}
@@ -492,7 +498,7 @@
// Get rendered stops.
const stops: Array<HTMLElement | AbortStop> =
- this.$.diffBuilder.getLineNumberRows();
+ this.diffBuilder.getLineNumberRows();
// If we are still loading this diff, abort after the rendered stops to
// avoid skipping over to e.g. the next file.
@@ -512,7 +518,7 @@
_blameChanged(newValue?: BlameInfo[] | null) {
if (newValue === undefined) return;
- this.$.diffBuilder.setBlame(newValue);
+ this.diffBuilder.setBlame(newValue);
if (newValue) {
this.classList.add('showBlame');
} else {
@@ -603,7 +609,7 @@
_createCommentForSelection(side: Side, range: CommentRange) {
const lineNum = range.end_line;
- const lineEl = this.$.diffBuilder.getLineElByNumber(lineNum, side);
+ const lineEl = this.diffBuilder.getLineElByNumber(lineNum, side);
if (lineEl) {
this._createComment(lineEl, lineNum, side, range);
}
@@ -621,7 +627,7 @@
side?: Side,
range?: CommentRange
) {
- const contentEl = this.$.diffBuilder.getContentTdByLineEl(lineEl);
+ const contentEl = this.diffBuilder.getContentTdByLineEl(lineEl);
if (!contentEl) throw new Error('content el not found for line el');
side = side ?? this._getCommentSideByLineAndContent(lineEl, contentEl);
assertIsDefined(this.path, 'path');
@@ -699,7 +705,7 @@
if (!this.lineOfInterest) return;
const lineNum = this.lineOfInterest.lineNum;
if (typeof lineNum !== 'number') return;
- this.$.diffBuilder.unhideLine(lineNum, this.lineOfInterest.side);
+ this.diffBuilder.unhideLine(lineNum, this.lineOfInterest.side);
}
_cleanup() {
@@ -808,7 +814,7 @@
if (this.prefs) {
this._updatePreferenceStyles(this.prefs, renderPrefs);
}
- this.$.diffBuilder.updateRenderPrefs(renderPrefs);
+ this.diffBuilder.updateRenderPrefs(renderPrefs);
}
_diffChanged(newValue?: DiffInfo) {
@@ -820,7 +826,7 @@
}
if (this.diff) {
this.diffSelection.init(this.diff, this.$.diffTable);
- this.highlights.init(this.$.diffTable, this.$.diffBuilder);
+ this.highlights.init(this.$.diffTable, this.diffBuilder);
}
}
@@ -866,9 +872,24 @@
this._showWarning = false;
const keyLocations = this._computeKeyLocations();
- this.$.diffBuilder.prefs = this._getBypassPrefs(this.prefs);
- this.$.diffBuilder.renderPrefs = this.renderPrefs;
- this.$.diffBuilder.render(keyLocations);
+
+ // TODO: Setting tons of public properties like this is obviously a code
+ // smell. We are planning to introduce a diff model for managing all this
+ // data. Then diff builder will only need access to that model.
+ this.diffBuilder.prefs = this._getBypassPrefs(this.prefs);
+ this.diffBuilder.renderPrefs = this.renderPrefs;
+ this.diffBuilder.diff = this.diff;
+ this.diffBuilder.path = this.path;
+ this.diffBuilder.viewMode = this.viewMode;
+ this.diffBuilder.layers = this.layers ?? [];
+ this.diffBuilder.isImageDiff = this.isImageDiff;
+ this.diffBuilder.baseImage = this.baseImage ?? null;
+ this.diffBuilder.revisionImage = this.revisionImage ?? null;
+ this.diffBuilder.useNewImageDiffUi = this.useNewImageDiffUi;
+ this.diffBuilder.diffElement = this.$.diffTable;
+ this.diffBuilder.updateCommentRanges(this._commentRanges);
+ this.diffBuilder.updateCoverageRanges(this.coverageRanges);
+ this.diffBuilder.render(keyLocations);
}
_handleRenderContent() {
@@ -895,10 +916,7 @@
const commentSide = getSide(threadEl);
const range = getRange(threadEl);
if (!commentSide) continue;
- const lineEl = this.$.diffBuilder.getLineElByNumber(
- lineNum,
- commentSide
- );
+ const lineEl = this.diffBuilder.getLineElByNumber(lineNum, commentSide);
// When the line the comment refers to does not exist, log an error
// but don't crash. This can happen e.g. if the API does not fully
// validate e.g. (robot) comments
@@ -911,7 +929,7 @@
);
continue;
}
- const contentEl = this.$.diffBuilder.getContentTdByLineEl(lineEl);
+ const contentEl = this.diffBuilder.getContentTdByLineEl(lineEl);
if (!contentEl) continue;
if (lineNum === 'LOST' && !contentEl.hasChildNodes()) {
contentEl.appendChild(this._portedCommentsWithoutRangeMessage());
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_html.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_html.ts
index 6d36b89..40d4e7f 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_html.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_html.ts
@@ -698,36 +698,22 @@
class$="[[_computeContainerClass(loggedIn, viewMode, displayLine)]]"
on-click="_handleTap"
>
- <gr-diff-builder
- id="diffBuilder"
- comment-ranges="[[_commentRanges]]"
- coverage-ranges="[[coverageRanges]]"
- diff="[[diff]]"
- path="[[path]]"
- view-mode="[[viewMode]]"
- is-image-diff="[[isImageDiff]]"
- base-image="[[baseImage]]"
- layers="[[layers]]"
- revision-image="[[revisionImage]]"
- use-new-image-diff-ui="[[useNewImageDiffUi]]"
- >
- <table
- id="diffTable"
- class$="[[_diffTableClass]]"
- role="presentation"
- contenteditable$="[[isContentEditable]]"
- ></table>
+ <table
+ id="diffTable"
+ class$="[[_diffTableClass]]"
+ role="presentation"
+ contenteditable$="[[isContentEditable]]"
+ ></table>
- <template
- is="dom-if"
- if="[[showNoChangeMessage(_loading, prefs, _diffLength, diff)]]"
- >
- <div class="whitespace-change-only-message">
- This file only contains whitespace changes. Modify the whitespace
- setting to see the changes.
- </div>
- </template>
- </gr-diff-builder>
+ <template
+ is="dom-if"
+ if="[[showNoChangeMessage(_loading, prefs, _diffLength, diff)]]"
+ >
+ <div class="whitespace-change-only-message">
+ This file only contains whitespace changes. Modify the whitespace
+ setting to see the changes.
+ </div>
+ </template>
</div>
<div class$="[[_computeNewlineWarningClass(_newlineWarning, _loading)]]">
[[_newlineWarning]]
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.js b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.js
index c8b643d..130dab8 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.js
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.js
@@ -25,7 +25,6 @@
import {Side} from '../../../api/diff.js';
import {mockPromise, stubRestApi} from '../../../test/test-utils.js';
import {AbortStop} from '../../../api/core.js';
-import {afterNextRender} from '@polymer/polymer/lib/utils/render-status';
import {waitForEventOnce} from '../../../utils/event-util.js';
const basicFixture = fixtureFromElement('gr-diff');
@@ -72,7 +71,7 @@
test('cancel', () => {
element = basicFixture.instantiate();
- const cancelStub = sinon.stub(element.$.diffBuilder, 'cancel');
+ const cancelStub = sinon.stub(element.diffBuilder, 'cancel');
element.cancel();
assert.isTrue(cancelStub.calledOnce);
});
@@ -192,9 +191,6 @@
element.changeNum = 123;
element.patchRange = {basePatchNum: 1, patchNum: 2};
element.path = 'file.txt';
- element.$.diffBuilder.diff = createDiff();
- element.$.diffBuilder.prefs = {...MINIMAL_PREFS};
- element.$.diffBuilder._builder = element.$.diffBuilder._getDiffBuilder();
// No thread groups.
assert.equal(contentEl.querySelectorAll('.thread-group').length, 0);
@@ -263,7 +259,7 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
- element.$.diffBuilder._builder, GrDiffBuilderImage);
+ element.diffBuilder.builder, GrDiffBuilderImage);
// Left image rendered with the parent commit's version of the file.
const leftImage = element.$.diffTable.querySelector('td.left img');
@@ -321,7 +317,7 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
- element.$.diffBuilder._builder, GrDiffBuilderImage);
+ element.diffBuilder.builder, GrDiffBuilderImage);
// Left image rendered with the parent commit's version of the file.
const leftImage = element.$.diffTable.querySelector('td.left img');
@@ -381,7 +377,7 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
- element.$.diffBuilder._builder, GrDiffBuilderImage);
+ element.diffBuilder.builder, GrDiffBuilderImage);
const leftImage = element.$.diffTable.querySelector('td.left img');
const rightImage = element.$.diffTable.querySelector('td.right img');
@@ -417,7 +413,7 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
- element.$.diffBuilder._builder, GrDiffBuilderImage);
+ element.diffBuilder.builder, GrDiffBuilderImage);
const leftImage = element.$.diffTable.querySelector('td.left img');
const rightImage = element.$.diffTable.querySelector('td.right img');
@@ -455,7 +451,7 @@
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
assert.instanceOf(
- element.$.diffBuilder._builder, GrDiffBuilderImage);
+ element.diffBuilder.builder, GrDiffBuilderImage);
const leftImage = element.$.diffTable.querySelector('td.left img');
assert.isNotOk(leftImage);
});
@@ -602,7 +598,7 @@
ab: Array(13).fill('text'),
}];
setupSampleDiff({content});
- await new Promise(resolve => afterNextRender(element, resolve));
+ await waitForEventOnce(element, 'render');
element.appendChild(threadEl);
await flush();
@@ -775,9 +771,9 @@
setup(() => {
element = basicFixture.instantiate();
- renderStub = sinon.stub(element.$.diffBuilder, 'render').callsFake(
+ renderStub = sinon.stub(element.diffBuilder, 'render').callsFake(
() => {
- element.$.diffBuilder.dispatchEvent(
+ element.$.diffTable.dispatchEvent(
new CustomEvent('render', {bubbles: true, composed: true}));
return Promise.resolve({});
});
@@ -838,7 +834,7 @@
assert.equal(element.prefs.context, 3);
assert.equal(element._safetyBypass, -1);
- assert.equal(element.$.diffBuilder.prefs.context, -1);
+ assert.equal(element.diffBuilder.prefs.context, -1);
});
test('toggles collapse context from bypass', async () => {
@@ -851,7 +847,7 @@
assert.equal(element.prefs.context, 3);
assert.isNull(element._safetyBypass);
- assert.equal(element.$.diffBuilder.prefs.context, 3);
+ assert.equal(element.diffBuilder.prefs.context, 3);
});
test('toggles collapse context from pref using default', async () => {
@@ -863,7 +859,7 @@
assert.equal(element.prefs.context, -1);
assert.equal(element._safetyBypass, 10);
- assert.equal(element.$.diffBuilder.prefs.context, 10);
+ assert.equal(element.diffBuilder.prefs.context, 10);
});
});
@@ -874,7 +870,7 @@
test('unsetting', () => {
element.blame = [];
- const setBlameSpy = sinon.spy(element.$.diffBuilder, 'setBlame');
+ const setBlameSpy = sinon.spy(element.diffBuilder, 'setBlame');
element.classList.add('showBlame');
element.blame = null;
assert.isTrue(setBlameSpy.calledWithExactly(null));
@@ -976,7 +972,7 @@
setup(() => {
element = basicFixture.instantiate();
element.prefs = {};
- renderStub = sinon.stub(element.$.diffBuilder, 'render')
+ renderStub = sinon.stub(element.diffBuilder, 'render')
.returns(new Promise(() => {}));
});
diff --git a/polygerrit-ui/app/test/test-utils.ts b/polygerrit-ui/app/test/test-utils.ts
index 985bec1..ea7865e 100644
--- a/polygerrit-ui/app/test/test-utils.ts
+++ b/polygerrit-ui/app/test/test-utils.ts
@@ -27,7 +27,7 @@
import {ShortcutsService} from '../services/shortcuts/shortcuts-service';
import {queryAndAssert, query} from '../utils/common-util';
import {FlagsService} from '../services/flags/flags';
-import {Key, Modifier} from '../utils/dom-util';
+import {afterNextRender, Key, Modifier} from '../utils/dom-util';
import {Observable} from 'rxjs';
import {filter, take, timeout} from 'rxjs/operators';
import {HighlightService} from '../services/highlight/highlight-service';
@@ -224,6 +224,10 @@
return waitUntil(() => stub.called, `${name} was not called`);
}
+export async function nextRender() {
+ return new Promise(resolve => afterNextRender(resolve));
+}
+
/**
* Subscribes to the observable and resolves once it emits a matching value.
* Usage:
diff --git a/polygerrit-ui/app/utils/dom-util.ts b/polygerrit-ui/app/utils/dom-util.ts
index 16e0586..f2e0994 100644
--- a/polygerrit-ui/app/utils/dom-util.ts
+++ b/polygerrit-ui/app/utils/dom-util.ts
@@ -505,3 +505,14 @@
});
obs.observe(el);
}
+
+/**
+ * Mimics a Polymer utility. `requestAnimationFrame` is called before the next
+ * browser paint. An additional `setTimeout` ensures that the paint has
+ * actually happened.
+ */
+export function afterNextRender(callback: (value?: unknown) => void) {
+ requestAnimationFrame(() => {
+ setTimeout(callback);
+ });
+}
diff --git a/polygerrit-ui/app/utils/event-util.ts b/polygerrit-ui/app/utils/event-util.ts
index 418adbd..e624cef 100644
--- a/polygerrit-ui/app/utils/event-util.ts
+++ b/polygerrit-ui/app/utils/event-util.ts
@@ -32,7 +32,7 @@
);
}
-type HTMLElementEventDetailType<K extends keyof HTMLElementEventMap> =
+export type HTMLElementEventDetailType<K extends keyof HTMLElementEventMap> =
HTMLElementEventMap[K] extends CustomEvent<infer DT>
? unknown extends DT
? never