summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDhruv Srivastava <dhruvsri@google.com>2022-04-12 09:16:30 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2022-04-12 09:16:30 +0000
commitccc66ddf47818c158d2c931d14773faa9f930ada (patch)
tree87035ca54d93573de4f5b4c8ec041b2d2563ef12
parent508d3ebaa3ecea84ae0ca2e435d0fb738c75dbf5 (diff)
parent4badebf5cf94f345c28c63f90cca5c598d7065c8 (diff)
Merge "Revert "Add lit element based gr-diff elements""
-rw-r--r--polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls-section.ts113
-rw-r--r--polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls-section_test.ts63
-rw-r--r--polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts13
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-element.ts26
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-lit.ts185
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder.ts2
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-row.ts368
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-row_test.ts195
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts240
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section_test.ts213
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-text.ts138
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-text_test.ts154
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor.ts1
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff-selection/gr-diff-selection.ts11
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff/gr-diff-line.ts5
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts34
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils_test.ts279
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts7
-rw-r--r--polygerrit-ui/app/embed/diff/gr-diff/gr-diff_html.ts6
19 files changed, 146 insertions, 1907 deletions
diff --git a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls-section.ts b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls-section.ts
deleted file mode 100644
index 77ba8cde25..0000000000
--- a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls-section.ts
+++ /dev/null
@@ -1,113 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../elements/shared/gr-button/gr-button';
-import {html, LitElement} from 'lit';
-import {customElement, property, state} from 'lit/decorators';
-import {DiffInfo, DiffViewMode, RenderPreferences} from '../../../api/diff';
-import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
-import {diffClasses} from '../gr-diff/gr-diff-utils';
-import {getShowConfig} from './gr-context-controls';
-import {ifDefined} from 'lit/directives/if-defined';
-
-@customElement('gr-context-controls-section')
-export class GrContextControlsSection extends LitElement {
- /** Should context controls be rendered for expanding above the section? */
- @property({type: Boolean}) showAbove = false;
-
- /** Should context controls be rendered for expanding below the section? */
- @property({type: Boolean}) showBelow = false;
-
- @property({type: Object}) viewMode = DiffViewMode.SIDE_BY_SIDE;
-
- /** Must be of type GrDiffGroupType.CONTEXT_CONTROL. */
- @property({type: Object})
- group?: GrDiffGroup;
-
- @property({type: Object})
- diff?: DiffInfo;
-
- @property({type: Object})
- renderPrefs?: RenderPreferences;
-
- /**
- * Semantic DOM diff testing does not work with just table fragments, so when
- * running such tests the render() method has to wrap the DOM in a proper
- * <table> element.
- */
- @state()
- addTableWrapperForTesting = false;
-
- /**
- * 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;
- }
-
- private renderPaddingRow(whereClass: 'above' | 'below') {
- if (!this.showAbove && whereClass === 'above') return;
- if (!this.showBelow && whereClass === 'below') return;
- const sideBySide = this.viewMode === DiffViewMode.SIDE_BY_SIDE;
- const modeClass = sideBySide ? 'side-by-side' : 'unified';
- const type = sideBySide ? GrDiffGroupType.CONTEXT_CONTROL : undefined;
- return html`
- <tr
- class=${diffClasses('contextBackground', modeClass, whereClass)}
- left-type=${ifDefined(type)}
- right-type=${ifDefined(type)}
- >
- <td class=${diffClasses('blame')} data-line-number="0"></td>
- <td class=${diffClasses('contextLineNum')}></td>
- ${sideBySide ? html`<td class=${diffClasses()}></td>` : ''}
- <td class=${diffClasses('contextLineNum')}></td>
- <td class=${diffClasses()}></td>
- </tr>
- `;
- }
-
- private createContextControlRow() {
- const sideBySide = this.viewMode === DiffViewMode.SIDE_BY_SIDE;
- const showConfig = getShowConfig(this.showAbove, this.showBelow);
- return html`
- <tr class=${diffClasses('dividerRow', `show-${showConfig}`)}>
- <td class=${diffClasses('blame')} data-line-number="0"></td>
- ${sideBySide ? html`<td class=${diffClasses()}></td>` : ''}
- <td class=${diffClasses('dividerCell')} colspan="3">
- <gr-context-controls
- .diff=${this.diff}
- .renderPreferences=${this.renderPrefs}
- .group=${this.group}
- .showConfig=${showConfig}
- >
- </gr-context-controls>
- </td>
- </tr>
- `;
- }
-
- override render() {
- const rows = html`
- ${this.renderPaddingRow('above')} ${this.createContextControlRow()}
- ${this.renderPaddingRow('below')}
- `;
- if (this.addTableWrapperForTesting) {
- return html`<table>
- ${rows}
- </table>`;
- }
- return rows;
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'gr-context-controls-section': GrContextControlsSection;
- }
-}
diff --git a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls-section_test.ts b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls-section_test.ts
deleted file mode 100644
index 2c1043d355..0000000000
--- a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls-section_test.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup-karma';
-import './gr-context-controls-section';
-import {GrContextControlsSection} from './gr-context-controls-section';
-import {html} from 'lit';
-import {fixture} from '@open-wc/testing-helpers';
-
-suite('gr-context-controls-section test', () => {
- let element: GrContextControlsSection;
-
- setup(async () => {
- element = await fixture<GrContextControlsSection>(
- html`<gr-context-controls-section></gr-context-controls-section>`
- );
- element.addTableWrapperForTesting = true;
- await element.updateComplete;
- });
-
- test('render: normal with showAbove and showBelow', async () => {
- element.showAbove = true;
- element.showBelow = true;
- await element.updateComplete;
- expect(element).lightDom.to.equal(/* HTML */ `
- <table>
- <tbody>
- <tr
- class="above contextBackground gr-diff side-by-side style-scope"
- left-type="contextControl"
- right-type="contextControl"
- >
- <td class="blame gr-diff style-scope" data-line-number="0"></td>
- <td class="contextLineNum gr-diff style-scope"></td>
- <td class="gr-diff style-scope"></td>
- <td class="contextLineNum gr-diff style-scope"></td>
- <td class="gr-diff style-scope"></td>
- </tr>
- <tr class="dividerRow gr-diff show-both style-scope">
- <td class="blame gr-diff style-scope" data-line-number="0"></td>
- <td class="gr-diff style-scope"></td>
- <td class="dividerCell gr-diff style-scope" colspan="3">
- <gr-context-controls showconfig="both"> </gr-context-controls>
- </td>
- </tr>
- <tr
- class="below contextBackground gr-diff side-by-side style-scope"
- left-type="contextControl"
- right-type="contextControl"
- >
- <td class="blame gr-diff style-scope" data-line-number="0"></td>
- <td class="contextLineNum gr-diff style-scope"></td>
- <td class="gr-diff style-scope"></td>
- <td class="contextLineNum gr-diff style-scope"></td>
- <td class="gr-diff style-scope"></td>
- </tr>
- </tbody>
- </table>
- `);
- });
-});
diff --git a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts
index a451700c20..77a5dfba08 100644
--- a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts
+++ b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts
@@ -80,19 +80,6 @@ function findBlockTreePathForLine(
export type GrContextControlsShowConfig = 'above' | 'below' | 'both';
-export function getShowConfig(
- showAbove: boolean,
- showBelow: boolean
-): GrContextControlsShowConfig {
- if (showAbove && !showBelow) return 'above';
- if (!showAbove && showBelow) return 'below';
-
- // Note that !showAbove && !showBelow also intentionally returns 'both'.
- // This means the file is completely collapsed, which is unusual, but at least
- // happens in one test.
- return 'both';
-}
-
@customElement('gr-context-controls')
export class GrContextControls extends LitElement {
@property({type: Object}) renderPreferences?: RenderPreferences;
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 27ebe4ea59..aabdf57d93 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
@@ -25,7 +25,6 @@ import {GrDiffBuilderSideBySide} from './gr-diff-builder-side-by-side';
import {GrDiffBuilderImage} from './gr-diff-builder-image';
import {GrDiffBuilderUnified} from './gr-diff-builder-unified';
import {GrDiffBuilderBinary} from './gr-diff-builder-binary';
-import {GrDiffBuilderLit} from './gr-diff-builder-lit';
import {CancelablePromise, util} from '../../../scripts/util';
import {customElement, property, observe} from '@polymer/decorators';
import {BlameInfo, ImageInfo} from '../../../types/common';
@@ -464,24 +463,13 @@ export class GrDiffBuilderElement extends PolymerElement {
// If the diff is binary, but not an image.
return new GrDiffBuilderBinary(this.diff, localPrefs, this.diffElement);
} else if (this.viewMode === DiffViewMode.SIDE_BY_SIDE) {
- const useLit = this.renderPrefs?.use_lit_components;
- if (useLit) {
- builder = new GrDiffBuilderLit(
- this.diff,
- localPrefs,
- this.diffElement,
- this._layers,
- this.renderPrefs
- );
- } else {
- builder = new GrDiffBuilderSideBySide(
- this.diff,
- localPrefs,
- this.diffElement,
- this._layers,
- this.renderPrefs
- );
- }
+ builder = new GrDiffBuilderSideBySide(
+ this.diff,
+ localPrefs,
+ this.diffElement,
+ this._layers,
+ this.renderPrefs
+ );
} else if (this.viewMode === DiffViewMode.UNIFIED) {
builder = new GrDiffBuilderUnified(
this.diff,
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-lit.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-lit.ts
deleted file mode 100644
index 368774775b..0000000000
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder-lit.ts
+++ /dev/null
@@ -1,185 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {RenderPreferences} from '../../../api/diff';
-import {LineNumber} from '../gr-diff/gr-diff-line';
-import {GrDiffGroup} from '../gr-diff/gr-diff-group';
-import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
-import {Side} from '../../../constants/constants';
-import {DiffLayer, notUndefined} from '../../../types/types';
-import {diffClasses} from '../gr-diff/gr-diff-utils';
-import {GrDiffBuilder} from './gr-diff-builder';
-import {BlameInfo} from '../../../types/common';
-import {html, render} from 'lit';
-import {GrDiffSection} from './gr-diff-section';
-import '../gr-context-controls/gr-context-controls';
-import './gr-diff-section';
-import {GrDiffRow} from './gr-diff-row';
-
-/**
- * Base class for builders that are creating the diff using Lit elements.
- */
-export class GrDiffBuilderLit extends GrDiffBuilder {
- constructor(
- diff: DiffInfo,
- prefs: DiffPreferencesInfo,
- outputEl: HTMLElement,
- layers: DiffLayer[] = [],
- renderPrefs?: RenderPreferences
- ) {
- super(diff, prefs, outputEl, layers, renderPrefs);
- }
-
- override getContentTdByLine(
- lineNumber: LineNumber,
- side?: Side,
- _root: Element = this.outputEl
- ): HTMLTableCellElement | null {
- if (!side) return null;
- const row = this.findRow(lineNumber, side);
- return row?.getContentCell(side) ?? null;
- }
-
- override getLineElByNumber(lineNumber: LineNumber, side: Side) {
- const row = this.findRow(lineNumber, side);
- return row?.getLineNumberCell(side) ?? null;
- }
-
- private findRow(lineNumber?: LineNumber, side?: Side): GrDiffRow | undefined {
- if (!side || !lineNumber) return undefined;
- const group = this.findGroup(side, lineNumber);
- if (!group) return undefined;
- const section = this.findSection(group);
- if (!section) return undefined;
- return section.findRow(side, lineNumber);
- }
-
- private getDiffRows() {
- const sections = [
- ...this.outputEl.querySelectorAll<GrDiffSection>('gr-diff-section'),
- ];
- return sections.map(s => s.getDiffRows()).flat();
- }
-
- override getLineNumberRows(): HTMLTableRowElement[] {
- const rows = this.getDiffRows();
- return rows.map(r => r.getTableRow()).filter(notUndefined);
- }
-
- override getLineNumEls(side: Side): HTMLTableCellElement[] {
- const rows = this.getDiffRows();
- return rows.map(r => r.getLineNumberCell(side)).filter(notUndefined);
- }
-
- override getBlameTdByLine(lineNumber: number): Element | undefined {
- return this.findRow(lineNumber, Side.LEFT)?.getBlameCell();
- }
-
- override getContentByLine(
- lineNumber: LineNumber,
- side?: Side,
- _root?: HTMLElement
- ): HTMLElement | null {
- const cell = this.getContentTdByLine(lineNumber, side);
- return (cell?.firstChild ?? null) as HTMLElement | null;
- }
-
- override renderContentByRange(
- start: LineNumber,
- end: LineNumber,
- side: Side
- ) {
- // TODO: Revisit whether there is maybe a more efficient and reliable
- // approach. renderContentByRange() is only used when layers announce
- // updates. We have to look deeper into the design of layers anyway. So
- // let's defer optimizing this code until a refactor of layers in general.
- const groups = this.getGroupsByLineRange(start, end, side);
- for (const group of groups) {
- const section = this.findSection(group);
- for (const row of section?.getDiffRows() ?? []) {
- row.requestUpdate();
- }
- }
- }
-
- private findSection(group?: GrDiffGroup): GrDiffSection | undefined {
- if (!group) return undefined;
- const leftClass = `left-${group.lineRange.left.start_line}`;
- const rightClass = `right-${group.lineRange.right.start_line}`;
- return (
- this.outputEl.querySelector<GrDiffSection>(
- `gr-diff-section.${leftClass}.${rightClass}`
- ) ?? undefined
- );
- }
-
- override renderBlameByRange(
- blameInfo: BlameInfo,
- start: number,
- end: number
- ) {
- for (let lineNumber = start; lineNumber <= end; lineNumber++) {
- const row = this.findRow(lineNumber, Side.LEFT);
- if (!row) continue;
- row.blameInfo = blameInfo;
- }
- }
-
- // TODO: Refactor this such that adding the move controls becomes part of the
- // lit element.
- protected override getMoveControlsConfig() {
- return {
- numberOfCells: 4, // How many cells does the diff table have?
- movedOutIndex: 1, // Index of left content column in diff table.
- movedInIndex: 3, // Index of right content column in diff table.
- lineNumberCols: [0, 2], // Indices of line number columns in diff table.
- };
- }
-
- protected override buildSectionElement(group: GrDiffGroup) {
- const leftCl = `left-${group.lineRange.left.start_line}`;
- const rightCl = `right-${group.lineRange.right.start_line}`;
- const section = html`
- <gr-diff-section
- class="${leftCl} ${rightCl}"
- .group=${group}
- .diff=${this._diff}
- .layers=${this.layers}
- .diffPrefs=${this._prefs}
- .renderPrefs=${this.renderPrefs}
- ></gr-diff-section>
- `;
- // TODO: Refactor GrDiffBuilder.emitGroup() and buildSectionElement()
- // such that we can render directly into the correct container.
- const tempContainer = document.createElement('div');
- render(section, tempContainer);
- return tempContainer.firstElementChild as GrDiffSection;
- }
-
- override addColumns(outputEl: HTMLElement, lineNumberWidth: number): void {
- render(
- html`
- <colgroup>
- <col class=${diffClasses('blame')}></col>
- <col class=${diffClasses(Side.LEFT)} width=${lineNumberWidth}></col>
- <col class=${diffClasses(Side.LEFT)}></col>
- <col class=${diffClasses(Side.RIGHT)} width=${lineNumberWidth}></col>
- <col class=${diffClasses(Side.RIGHT)}></col>
- </colgroup>
- `,
- outputEl
- );
- }
-
- protected override getNextContentOnSide(
- _content: HTMLElement,
- _side: Side
- ): HTMLElement | null {
- // TODO: getNextContentOnSide() is not required by lit based rendering.
- // So let's refactor it to be moved into gr-diff-builder-legacy.
- console.warn('unimplemented method getNextContentOnSide() called');
- return null;
- }
-}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder.ts
index 4efa238426..add7ffae85 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-builder.ts
@@ -194,7 +194,7 @@ export abstract class GrDiffBuilder implements DiffBuilder {
group.element = element;
}
- protected getGroupsByLineRange(
+ private getGroupsByLineRange(
startLine: LineNumber,
endLine: LineNumber,
side: Side
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-row.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-row.ts
deleted file mode 100644
index ae18e592ac..0000000000
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-row.ts
+++ /dev/null
@@ -1,368 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {html, LitElement, TemplateResult} from 'lit';
-import {customElement, property, state} from 'lit/decorators';
-import {ifDefined} from 'lit/directives/if-defined';
-import {createRef, Ref, ref} from 'lit/directives/ref';
-import {
- DiffResponsiveMode,
- Side,
- LineNumber,
- DiffLayer,
-} from '../../../api/diff';
-import {BlameInfo} from '../../../types/common';
-import {assertIsDefined} from '../../../utils/common-util';
-import {fire} from '../../../utils/event-util';
-import {getBaseUrl} from '../../../utils/url-util';
-import './gr-diff-text';
-import {GrDiffLine, GrDiffLineType} from '../gr-diff/gr-diff-line';
-import {diffClasses, isResponsive} from '../gr-diff/gr-diff-utils';
-
-@customElement('gr-diff-row')
-export class GrDiffRow extends LitElement {
- contentLeftRef: Ref<HTMLDivElement> = createRef();
-
- contentRightRef: Ref<HTMLDivElement> = createRef();
-
- lineNumberLeftRef: Ref<HTMLTableCellElement> = createRef();
-
- lineNumberRightRef: Ref<HTMLTableCellElement> = createRef();
-
- blameCellRef: Ref<HTMLTableCellElement> = createRef();
-
- tableRowRef: Ref<HTMLTableRowElement> = createRef();
-
- @property({type: Object})
- left?: GrDiffLine;
-
- @property({type: Object})
- right?: GrDiffLine;
-
- @property({type: Object})
- blameInfo?: BlameInfo;
-
- @property({type: Object})
- responsiveMode?: DiffResponsiveMode;
-
- @property({type: Number})
- tabSize = 2;
-
- @property({type: Number})
- lineLength = 80;
-
- @property({type: Boolean})
- hideFileCommentButton = false;
-
- @property({type: Object})
- layers: DiffLayer[] = [];
-
- /**
- * While not visible we are trying to optimize rendering performance by
- * rendering a simpler version of the diff. Once this has become true it
- * cannot be set back to false.
- */
- @state()
- isVisible = false;
-
- /**
- * Semantic DOM diff testing does not work with just table fragments, so when
- * running such tests the render() method has to wrap the DOM in a proper
- * <table> element.
- */
- @state()
- addTableWrapperForTesting = false;
-
- /**
- * 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;
- }
-
- override updated() {
- this.updateLayers(Side.LEFT);
- this.updateLayers(Side.RIGHT);
- }
-
- /**
- * TODO: This needs some refinement, because layers do not detect whether they
- * have already applied their information, so at the moment all layers would
- * constantly re-apply their information to the diff in each lit rendering
- * pass.
- */
- private updateLayers(side: Side) {
- if (!this.isVisible) return;
- const line = this.line(side);
- const contentEl = this.contentRef(side).value;
- const lineNumberEl = this.lineNumberRef(side).value;
- if (!line || !contentEl || !lineNumberEl) return;
- for (const layer of this.layers) {
- if (typeof layer.annotate === 'function') {
- layer.annotate(contentEl, lineNumberEl, line, side);
- }
- }
- }
-
- private renderInvisible() {
- return html`
- <tr>
- <td class="style-scope gr-diff blame"></td>
- <td class="style-scope gr-diff left"></td>
- <td class="style-scope gr-diff left content">
- <div>${this.left?.text ?? ''}</div>
- </td>
- <td class="style-scope gr-diff right"></td>
- <td class="style-scope gr-diff right content">
- <div>${this.right?.text ?? ''}</div>
- </td>
- </tr>
- `;
- }
-
- override render() {
- if (!this.left || !this.right) return;
- if (!this.isVisible) return this.renderInvisible();
- const row = html`
- <tr
- ${ref(this.tableRowRef)}
- class=${diffClasses('diff-row', 'side-by-side')}
- left-type=${this.left.type}
- right-type=${this.right.type}
- tabindex="-1"
- >
- ${this.renderBlameCell()} ${this.renderLineNumberCell(Side.LEFT)}
- ${this.renderContentCell(Side.LEFT)}
- ${this.renderLineNumberCell(Side.RIGHT)}
- ${this.renderContentCell(Side.RIGHT)}
- </tr>
- `;
- if (this.addTableWrapperForTesting) {
- return html`<table>
- ${row}
- </table>`;
- }
- return row;
- }
-
- getTableRow(): HTMLTableRowElement | undefined {
- return this.tableRowRef.value;
- }
-
- getLineNumberCell(side: Side): HTMLTableCellElement | undefined {
- return this.lineNumberRef(side).value;
- }
-
- getContentCell(side: Side) {
- const div = this.contentRef(side)?.value;
- if (!div) return undefined;
- return div.parentElement as HTMLTableCellElement;
- }
-
- getBlameCell() {
- return this.blameCellRef.value;
- }
-
- private renderBlameCell() {
- // td.blame has `white-space: pre`, so prettier must not add spaces.
- // prettier-ignore
- return html`
- <td
- ${ref(this.blameCellRef)}
- class=${diffClasses('blame')}
- data-line-number=${this.left?.beforeNumber ?? 0}
- >${this.renderBlameElement()}</td>
- `;
- }
-
- private renderBlameElement() {
- const lineNum = this.left?.beforeNumber;
- const commit = this.blameInfo;
- if (!lineNum || !commit) return;
-
- const isStartOfRange = commit.ranges.some(r => r.start === lineNum);
- const extras: string[] = [];
- if (isStartOfRange) extras.push('startOfRange');
- const date = new Date(commit.time * 1000).toLocaleDateString();
- const shortName = commit.author.split(' ')[0];
- const url = `${getBaseUrl()}/q/${commit.id}`;
-
- // td.blame has `white-space: pre`, so prettier must not add spaces.
- // prettier-ignore
- return html`<span class=${diffClasses(...extras)}
- ><a href=${url} class=${diffClasses('blameDate')}>${date}</a
- ><span class=${diffClasses('blameAuthor')}> ${shortName}</span
- ><gr-hovercard class=${diffClasses()}>
- <span class=${diffClasses('blameHoverCard')}>
- Commit ${commit.id}<br />
- Author: ${commit.author}<br />
- Date: ${date}<br />
- <br />
- ${commit.commit_msg}
- </span>
- </gr-hovercard
- ></span>`;
- }
-
- private renderLineNumberCell(side: Side): TemplateResult {
- const line = this.line(side);
- const lineNumber = this.lineNumber(side);
- if (!line || !lineNumber || line.type === GrDiffLineType.BLANK) {
- return html`<td
- ${ref(this.lineNumberRef(side))}
- class=${diffClasses(side)}
- ></td>`;
- }
-
- return html`<td
- ${ref(this.lineNumberRef(side))}
- class=${diffClasses(side, 'lineNum')}
- data-value=${lineNumber}
- >
- ${this.renderLineNumberButton(line, lineNumber, side)}
- </td>`;
- }
-
- private renderLineNumberButton(
- line: GrDiffLine,
- lineNumber: LineNumber,
- side: Side
- ) {
- if (this.hideFileCommentButton && lineNumber === 'FILE') return;
- if (lineNumber === 'LOST') return;
- // .lineNumButton has `white-space: pre`, so prettier must not add spaces.
- // prettier-ignore
- return html`
- <button
- class=${diffClasses('lineNumButton', side)}
- tabindex="-1"
- data-value=${lineNumber}
- aria-label=${ifDefined(
- this.computeLineNumberAriaLabel(line, lineNumber)
- )}
- @mouseenter=${() =>
- fire(this, 'line-mouse-enter', {lineNum: lineNumber, side})}
- @mouseleave=${() =>
- fire(this, 'line-mouse-leave', {lineNum: lineNumber, side})}
- >${lineNumber === 'FILE' ? 'File' : lineNumber.toString()}</button>
- `;
- }
-
- private computeLineNumberAriaLabel(line: GrDiffLine, lineNumber: LineNumber) {
- if (lineNumber === 'FILE') return 'Add file comment';
-
- // Add aria-labels for valid line numbers.
- // For unified diff, this method will be called with number set to 0 for
- // the empty line number column for added/removed lines. This should not
- // be announced to the screenreader.
- if (lineNumber <= 0) return undefined;
-
- switch (line.type) {
- case GrDiffLineType.REMOVE:
- return `${lineNumber} removed`;
- case GrDiffLineType.ADD:
- return `${lineNumber} added`;
- case GrDiffLineType.BOTH:
- case GrDiffLineType.BLANK:
- return undefined;
- }
- }
-
- private renderContentCell(side: Side): TemplateResult {
- const line = this.line(side);
- const lineNumber = this.lineNumber(side);
- assertIsDefined(line, 'line');
- const extras: string[] = [line.type, side];
- if (line.type !== GrDiffLineType.BLANK) extras.push('content');
- if (!line.hasIntralineInfo) extras.push('no-intraline-info');
- if (line.beforeNumber === 'FILE') extras.push('file');
- if (line.beforeNumber === 'LOST') extras.push('lost');
-
- // .content has `white-space: pre`, so prettier must not add spaces.
- // prettier-ignore
- return html`
- <td
- class=${diffClasses(...extras)}
- @mouseenter=${() => {
- if (lineNumber)
- fire(this, 'line-mouse-enter', {lineNum: lineNumber, side});
- }}
- @mouseleave=${() => {
- if (lineNumber)
- fire(this, 'line-mouse-leave', {lineNum: lineNumber, side});
- }}
- >${this.renderText(side)}${this.renderThreadGroup(side, lineNumber)}</td>
- `;
- }
-
- private renderThreadGroup(side: Side, lineNumber?: LineNumber) {
- if (!lineNumber) return;
- // TODO: For the LOST line number the convention is that a <tr> will always
- // be rendered, but it will not be visible, because of all cells being
- // empty. For this to work with lit-based rendering we may only render a
- // thread-group and a <slot> when there is a thread using that slot. The
- // cleanest solution for that is probably introducing a gr-diff-model, where
- // each diff row can look up or observe comment threads.
- // .content has `white-space: pre`, so prettier must not add spaces.
- // prettier-ignore
- return html`<div class="thread-group" data-side=${side}><slot name="${side}-${lineNumber}"></slot></div>`;
- }
-
- private contentRef(side: Side) {
- return side === Side.LEFT ? this.contentLeftRef : this.contentRightRef;
- }
-
- private lineNumberRef(side: Side) {
- return side === Side.LEFT
- ? this.lineNumberLeftRef
- : this.lineNumberRightRef;
- }
-
- private lineNumber(side: Side) {
- return this.line(side)?.lineNumber(side);
- }
-
- private line(side: Side) {
- return side === Side.LEFT ? this.left : this.right;
- }
-
- /**
- * Returns a 'div' element containing the supplied |text| as its innerText,
- * with '\t' characters expanded to a width determined by |tabSize|, and the
- * text wrapped at column |lineLimit|, which may be Infinity if no wrapping is
- * desired.
- */
- private renderText(side: Side) {
- const line = this.line(side);
- const lineNumber = this.lineNumber(side);
- if (lineNumber === 'FILE' || lineNumber === 'LOST') return;
- // prettier-ignore
- const textElement = line?.text
- ? html`<gr-diff-text
- ${ref(this.contentRef(side))}
- .text=${line?.text}
- .tabSize=${this.tabSize}
- .lineLimit=${this.lineLength}
- .isResponsive=${isResponsive(this.responsiveMode)}
- ></gr-diff-text>` : '';
- // .content has `white-space: pre`, so prettier must not add spaces.
- // prettier-ignore
- return html`<div
- class=${diffClasses('contentText', side)}
- .ariaLabel=${line?.text ?? ''}
- data-side=${ifDefined(side)}
- >${textElement}</div>`;
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'gr-diff-row': GrDiffRow;
- }
-}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-row_test.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-row_test.ts
deleted file mode 100644
index 757d906f61..0000000000
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-row_test.ts
+++ /dev/null
@@ -1,195 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup-karma';
-import './gr-diff-row';
-import {GrDiffRow} from './gr-diff-row';
-import {html} from 'lit';
-import {fixture} from '@open-wc/testing-helpers';
-import {GrDiffLine} from '../gr-diff/gr-diff-line';
-import {GrDiffLineType} from '../../../api/diff';
-
-suite('gr-diff-row test', () => {
- let element: GrDiffRow;
-
- setup(async () => {
- element = await fixture<GrDiffRow>(html`<gr-diff-row></gr-diff-row>`);
- element.isVisible = true;
- element.addTableWrapperForTesting = true;
- await element.updateComplete;
- });
-
- test('both', async () => {
- const line = new GrDiffLine(GrDiffLineType.BOTH, 1, 1);
- line.text = 'lorem ipsum';
- element.left = line;
- element.right = line;
- await element.updateComplete;
- expect(element).lightDom.to.equal(/* HTML */ `
- <table>
- <tbody>
- <tr
- class="diff-row gr-diff side-by-side style-scope"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff style-scope" data-line-number="1"></td>
- <td class="gr-diff left lineNum style-scope" data-value="1">
- <button
- class="gr-diff left lineNumButton style-scope"
- data-value="1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td class="both content gr-diff left no-intraline-info style-scope">
- <div
- aria-label="lorem ipsum"
- class="contentText gr-diff left style-scope"
- data-side="left"
- >
- <gr-diff-text>lorem ipsum</gr-diff-text>
- </div>
- <div class="thread-group" data-side="left">
- <slot name="left-1"> </slot>
- </div>
- </td>
- <td class="gr-diff lineNum right style-scope" data-value="1">
- <button
- class="gr-diff lineNumButton right style-scope"
- data-value="1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td
- class="both content gr-diff no-intraline-info right style-scope"
- >
- <div
- aria-label="lorem ipsum"
- class="contentText gr-diff right style-scope"
- data-side="right"
- >
- <gr-diff-text>lorem ipsum</gr-diff-text>
- </div>
- <div class="thread-group" data-side="right">
- <slot name="right-1"> </slot>
- </div>
- </td>
- </tr>
- </tbody>
- </table>
- `);
- });
-
- test('add', async () => {
- const line = new GrDiffLine(GrDiffLineType.ADD, 0, 1);
- line.text = 'lorem ipsum';
- element.left = new GrDiffLine(GrDiffLineType.BLANK);
- element.right = line;
- await element.updateComplete;
- expect(element).lightDom.to.equal(/* HTML */ `
- <table>
- <tbody>
- <tr
- class="diff-row gr-diff side-by-side style-scope"
- left-type="blank"
- right-type="add"
- tabindex="-1"
- >
- <td class="blame gr-diff style-scope" data-line-number="0"></td>
- <td class="gr-diff left style-scope"></td>
- <td class="blank gr-diff left no-intraline-info style-scope">
- <div
- aria-label=""
- class="contentText gr-diff left style-scope"
- data-side="left"
- ></div>
- </td>
- <td class="gr-diff lineNum right style-scope" data-value="1">
- <button
- aria-label="1 added"
- class="gr-diff lineNumButton right style-scope"
- data-value="1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td class="add content gr-diff no-intraline-info right style-scope">
- <div
- aria-label="lorem ipsum"
- class="contentText gr-diff right style-scope"
- data-side="right"
- >
- <gr-diff-text>lorem ipsum</gr-diff-text>
- </div>
- <div class="thread-group" data-side="right">
- <slot name="right-1"> </slot>
- </div>
- </td>
- </tr>
- </tbody>
- </table>
- `);
- });
-
- test('remove', async () => {
- const line = new GrDiffLine(GrDiffLineType.REMOVE, 1, 0);
- line.text = 'lorem ipsum';
- element.left = line;
- element.right = new GrDiffLine(GrDiffLineType.BLANK);
- await element.updateComplete;
- expect(element).lightDom.to.equal(/* HTML */ `
- <table>
- <tbody>
- <tr
- class="diff-row gr-diff side-by-side style-scope"
- left-type="remove"
- right-type="blank"
- tabindex="-1"
- >
- <td class="blame gr-diff style-scope" data-line-number="1"></td>
- <td class="gr-diff left lineNum style-scope" data-value="1">
- <button
- aria-label="1 removed"
- class="gr-diff left lineNumButton style-scope"
- data-value="1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td
- class="content gr-diff left no-intraline-info remove style-scope"
- >
- <div
- aria-label="lorem ipsum"
- class="contentText gr-diff left style-scope"
- data-side="left"
- >
- <gr-diff-text>lorem ipsum</gr-diff-text>
- </div>
- <div class="thread-group" data-side="left">
- <slot name="left-1"> </slot>
- </div>
- </td>
- <td class="gr-diff right style-scope"></td>
- <td class="blank gr-diff no-intraline-info right style-scope">
- <div
- aria-label=""
- class="contentText gr-diff right style-scope"
- data-side="right"
- ></div>
- </td>
- </tr>
- </tbody>
- </table>
- `);
- });
-});
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
deleted file mode 100644
index b11d767558..0000000000
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section.ts
+++ /dev/null
@@ -1,240 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {html, LitElement} from 'lit';
-import {customElement, property, state} from 'lit/decorators';
-import {
- DiffInfo,
- DiffLayer,
- DiffViewMode,
- MovedLinkClickedEventDetail,
- RenderPreferences,
- Side,
- LineNumber,
- DiffPreferencesInfo,
-} from '../../../api/diff';
-import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
-import {countLines, diffClasses} from '../gr-diff/gr-diff-utils';
-import {GrDiffRow} from './gr-diff-row';
-import '../gr-context-controls/gr-context-controls-section';
-import '../gr-context-controls/gr-context-controls';
-import '../gr-range-header/gr-range-header';
-import './gr-diff-row';
-import {whenVisible} from '../../../utils/dom-util';
-
-@customElement('gr-diff-section')
-export class GrDiffSection extends LitElement {
- @property({type: Object})
- group?: GrDiffGroup;
-
- @property({type: Object})
- diff?: DiffInfo;
-
- @property({type: Object})
- renderPrefs?: RenderPreferences;
-
- @property({type: Object})
- diffPrefs?: DiffPreferencesInfo;
-
- @property({type: Object})
- layers: DiffLayer[] = [];
-
- /**
- * While not visible we are trying to optimize rendering performance by
- * rendering a simpler version of the diff.
- */
- @state()
- isVisible = false;
-
- /**
- * Semantic DOM diff testing does not work with just table fragments, so when
- * running such tests the render() method has to wrap the DOM in a proper
- * <table> element.
- */
- @state()
- addTableWrapperForTesting = false;
-
- /**
- * 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;
- }
-
- override connectedCallback() {
- super.connectedCallback();
- // TODO: Refine this obviously simplistic approach to optimized rendering.
- whenVisible(this.parentElement!, () => (this.isVisible = true), 1000);
- }
-
- override render() {
- if (!this.group) return;
- const extras: string[] = [];
- extras.push('section');
- extras.push(this.group.type);
- if (this.group.isTotal()) extras.push('total');
- if (this.group.dueToRebase) extras.push('dueToRebase');
- if (this.group.moveDetails) extras.push('dueToMove');
- if (this.group.ignoredWhitespaceOnly) extras.push('ignoredWhitespaceOnly');
-
- const isControl = this.group.type === GrDiffGroupType.CONTEXT_CONTROL;
- const pairs = isControl ? [] : this.group.getSideBySidePairs();
- const body = html`
- <tbody class=${diffClasses(...extras)}>
- ${this.renderContextControls()} ${this.renderMoveControls()}
- ${pairs.map(pair => {
- const leftCl = `left-${pair.left.lineNumber(Side.LEFT)}`;
- const rightCl = `right-${pair.right.lineNumber(Side.RIGHT)}`;
- return html`
- <gr-diff-row
- class="${leftCl} ${rightCl}"
- .left=${pair.left}
- .right=${pair.right}
- .layers=${this.layers}
- .lineLength=${this.diffPrefs?.line_length ?? 80}
- .tabSize=${this.diffPrefs?.tab_size ?? 2}
- .isVisible=${this.isVisible}
- >
- </gr-diff-row>
- `;
- })}
- </tbody>
- `;
- if (this.addTableWrapperForTesting) {
- return html`<table>
- ${body}
- </table>`;
- }
- return body;
- }
-
- getDiffRows(): GrDiffRow[] {
- return [...this.querySelectorAll<GrDiffRow>('gr-diff-row')];
- }
-
- private renderContextControls() {
- if (this.group?.type !== GrDiffGroupType.CONTEXT_CONTROL) return;
-
- const leftStart = this.group.lineRange.left.start_line;
- const leftEnd = this.group.lineRange.left.end_line;
- const firstGroupIsSkipped = !!this.group.contextGroups[0].skip;
- const lastGroupIsSkipped =
- !!this.group.contextGroups[this.group.contextGroups.length - 1].skip;
- const lineCountLeft = countLines(this.diff, Side.LEFT);
- const containsWholeFile = lineCountLeft === leftEnd - leftStart + 1;
- const showAbove =
- (leftStart > 1 && !firstGroupIsSkipped) || containsWholeFile;
- const showBelow = leftEnd < lineCountLeft && !lastGroupIsSkipped;
-
- return html`
- <gr-context-controls-section
- .showAbove=${showAbove}
- .showBelow=${showBelow}
- .group=${this.group}
- .diff=${this.diff}
- .renderPrefs=${this.renderPrefs}
- .viewMode=${DiffViewMode.SIDE_BY_SIDE}
- >
- </gr-context-controls-section>
- `;
- }
-
- findRow(side: Side, lineNumber: LineNumber): GrDiffRow | undefined {
- return (
- this.querySelector<GrDiffRow>(`gr-diff-row.${side}-${lineNumber}`) ??
- undefined
- );
- }
-
- private renderMoveControls() {
- if (!this.group?.moveDetails) return;
- const movedIn = this.group.adds.length > 0;
- const plainCell = html`<td class=${diffClasses()}></td>`;
- const lineNumberCell = html`
- <td class=${diffClasses('moveControlsLineNumCol')}></td>
- `;
- const moveCell = html`
- <td class=${diffClasses('moveHeader')}>
- <gr-range-header class=${diffClasses()} icon="gr-icons:move-item">
- ${this.renderMoveDescription(movedIn)}
- </gr-range-header>
- </td>
- `;
- return html`
- <tr
- class=${diffClasses('moveControls', movedIn ? 'movedIn' : 'movedOut')}
- >
- ${lineNumberCell} ${movedIn ? plainCell : moveCell} ${lineNumberCell}
- ${movedIn ? moveCell : plainCell}
- </tr>
- `;
- }
-
- private renderMoveDescription(movedIn: boolean) {
- if (this.group?.moveDetails?.range) {
- const {changed, range} = this.group.moveDetails;
- const otherSide = movedIn ? Side.LEFT : Side.RIGHT;
- const andChangedLabel = changed ? 'and changed ' : '';
- const direction = movedIn ? 'from' : 'to';
- const textLabel = `Moved ${andChangedLabel}${direction} lines `;
- return html`
- <div class=${diffClasses()}>
- <span class=${diffClasses()}>${textLabel}</span>
- ${this.renderMovedLineAnchor(range.start, otherSide)}
- <span class=${diffClasses()}> - </span>
- ${this.renderMovedLineAnchor(range.end, otherSide)}
- </div>
- `;
- }
-
- return html`
- <div class=${diffClasses()}>
- <span class=${diffClasses()}
- >${movedIn ? 'Moved in' : 'Moved out'}</span
- >
- </div>
- `;
- }
-
- private renderMovedLineAnchor(line: number, side: Side) {
- const listener = (e: MouseEvent) => {
- e.preventDefault();
- this.handleMovedLineAnchorClick(e.target, side, line);
- };
- // `href` is not actually used but important for Screen Readers
- return html`
- <a class=${diffClasses()} href=${`#${line}`} @click=${listener}
- >${line}</a
- >
- `;
- }
-
- private handleMovedLineAnchorClick(
- anchor: EventTarget | null,
- side: Side,
- line: number
- ) {
- anchor?.dispatchEvent(
- new CustomEvent<MovedLinkClickedEventDetail>('moved-link-clicked', {
- detail: {
- lineNum: line,
- side,
- },
- composed: true,
- bubbles: true,
- })
- );
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'gr-diff-section': GrDiffSection;
- }
-}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section_test.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section_test.ts
deleted file mode 100644
index 88c0e8386e..0000000000
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-section_test.ts
+++ /dev/null
@@ -1,213 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup-karma';
-import './gr-diff-section';
-import {GrDiffSection} from './gr-diff-section';
-import {html} from 'lit';
-import {fixture} from '@open-wc/testing-helpers';
-import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
-import {GrDiffLine} from '../gr-diff/gr-diff-line';
-import {GrDiffLineType} from '../../../api/diff';
-
-suite('gr-diff-section test', () => {
- let element: GrDiffSection;
-
- setup(async () => {
- element = await fixture<GrDiffSection>(
- html`<gr-diff-section></gr-diff-section>`
- );
- element.addTableWrapperForTesting = true;
- element.isVisible = true;
- await element.updateComplete;
- });
-
- test('3 normal unchanged rows', async () => {
- const lines = [
- new GrDiffLine(GrDiffLineType.BOTH, 1, 1),
- new GrDiffLine(GrDiffLineType.BOTH, 1, 1),
- new GrDiffLine(GrDiffLineType.BOTH, 1, 1),
- ];
- lines[0].text = 'asdf';
- lines[1].text = 'qwer';
- lines[2].text = 'zxcv';
- const group = new GrDiffGroup({type: GrDiffGroupType.BOTH, lines});
- element.group = group;
- await element.updateComplete;
- expect(element).dom.to.equal(/* HTML */ `
- <gr-diff-section>
- <gr-diff-row class="left-1 right-1"> </gr-diff-row>
- <gr-diff-row class="left-1 right-1"> </gr-diff-row>
- <gr-diff-row class="left-1 right-1"> </gr-diff-row>
- <table>
- <tbody class="both gr-diff section style-scope">
- <tr
- class="diff-row gr-diff side-by-side style-scope"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff style-scope" data-line-number="1"></td>
- <td class="gr-diff left lineNum style-scope" data-value="1">
- <button
- class="gr-diff left lineNumButton style-scope"
- data-value="1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td
- class="both content gr-diff left no-intraline-info style-scope"
- >
- <div
- aria-label="asdf"
- class="contentText gr-diff left style-scope"
- data-side="left"
- >
- <gr-diff-text></gr-diff-text>
- </div>
- <div class="thread-group" data-side="left">
- <slot name="left-1"> </slot>
- </div>
- </td>
- <td class="gr-diff lineNum right style-scope" data-value="1">
- <button
- class="gr-diff lineNumButton right style-scope"
- data-value="1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td
- class="both content gr-diff no-intraline-info right style-scope"
- >
- <div
- aria-label="asdf"
- class="contentText gr-diff right style-scope"
- data-side="right"
- >
- <gr-diff-text></gr-diff-text>
- </div>
- <div class="thread-group" data-side="right">
- <slot name="right-1"> </slot>
- </div>
- </td>
- </tr>
- <tr
- class="diff-row gr-diff side-by-side style-scope"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff style-scope" data-line-number="1"></td>
- <td class="gr-diff left lineNum style-scope" data-value="1">
- <button
- class="gr-diff left lineNumButton style-scope"
- data-value="1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td
- class="both content gr-diff left no-intraline-info style-scope"
- >
- <div
- aria-label="qwer"
- class="contentText gr-diff left style-scope"
- data-side="left"
- >
- <gr-diff-text></gr-diff-text>
- </div>
- <div class="thread-group" data-side="left">
- <slot name="left-1"> </slot>
- </div>
- </td>
- <td class="gr-diff lineNum right style-scope" data-value="1">
- <button
- class="gr-diff lineNumButton right style-scope"
- data-value="1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td
- class="both content gr-diff no-intraline-info right style-scope"
- >
- <div
- aria-label="qwer"
- class="contentText gr-diff right style-scope"
- data-side="right"
- >
- <gr-diff-text></gr-diff-text>
- </div>
- <div class="thread-group" data-side="right">
- <slot name="right-1"> </slot>
- </div>
- </td>
- </tr>
- <tr
- class="diff-row gr-diff side-by-side style-scope"
- left-type="both"
- right-type="both"
- tabindex="-1"
- >
- <td class="blame gr-diff style-scope" data-line-number="1"></td>
- <td class="gr-diff left lineNum style-scope" data-value="1">
- <button
- class="gr-diff left lineNumButton style-scope"
- data-value="1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td
- class="both content gr-diff left no-intraline-info style-scope"
- >
- <div
- aria-label="zxcv"
- class="contentText gr-diff left style-scope"
- data-side="left"
- >
- <gr-diff-text></gr-diff-text>
- </div>
- <div class="thread-group" data-side="left">
- <slot name="left-1"> </slot>
- </div>
- </td>
- <td class="gr-diff lineNum right style-scope" data-value="1">
- <button
- class="gr-diff lineNumButton right style-scope"
- data-value="1"
- tabindex="-1"
- >
- 1
- </button>
- </td>
- <td
- class="both content gr-diff no-intraline-info right style-scope"
- >
- <div
- aria-label="zxcv"
- class="contentText gr-diff right style-scope"
- data-side="right"
- >
- <gr-diff-text></gr-diff-text>
- </div>
- <div class="thread-group" data-side="right">
- <slot name="right-1"> </slot>
- </div>
- </td>
- </tr>
- </tbody>
- </table>
- </gr-diff-section>
- `);
- });
-});
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-text.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-text.ts
deleted file mode 100644
index bb37c43f55..0000000000
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-text.ts
+++ /dev/null
@@ -1,138 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import {LitElement, html, TemplateResult} from 'lit';
-import {customElement, property} from 'lit/decorators';
-import {diffClasses} from '../gr-diff/gr-diff-utils';
-
-const SURROGATE_PAIR = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
-
-const TAB = '\t';
-
-@customElement('gr-diff-text')
-export class GrDiffText extends LitElement {
- /**
- * 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;
- }
-
- @property({type: String})
- text = '';
-
- @property({type: Boolean})
- isResponsive = false;
-
- @property({type: Number})
- tabSize = 2;
-
- @property({type: Number})
- lineLimit = 80;
-
- /** Temporary state while rendering. */
- private textOffset = 0;
-
- /** Temporary state while rendering. */
- private columnPos = 0;
-
- /** Temporary state while rendering. */
- private pieces: (string | TemplateResult)[] = [];
-
- /** Split up the string into tabs, surrogate pairs and regular segments. */
- override render() {
- this.textOffset = 0;
- this.columnPos = 0;
- this.pieces = [];
- const splitByTab = this.text.split('\t');
- for (let i = 0; i < splitByTab.length; i++) {
- const splitBySurrogate = splitByTab[i].split(SURROGATE_PAIR);
- for (let j = 0; j < splitBySurrogate.length; j++) {
- this.renderSegment(splitBySurrogate[j]);
- if (j < splitBySurrogate.length - 1) {
- this.renderSurrogatePair();
- }
- }
- if (i < splitByTab.length - 1) {
- this.renderTab();
- }
- }
- if (this.textOffset !== this.text.length) throw new Error('unfinished');
- return this.pieces;
- }
-
- /** Render regular characters, but insert line breaks appropriately. */
- private renderSegment(segment: string) {
- let segmentOffset = 0;
- while (segmentOffset < segment.length) {
- const newOffset = Math.min(
- segment.length,
- segmentOffset + this.lineLimit - this.columnPos
- );
- this.renderString(segment.substring(segmentOffset, newOffset));
- segmentOffset = newOffset;
- if (segmentOffset < segment.length && this.columnPos === this.lineLimit) {
- this.renderLineBreak();
- }
- }
- }
-
- /** Render regular characters. */
- private renderString(s: string) {
- if (s.length === 0) return;
- this.pieces.push(s);
- this.textOffset += s.length;
- this.columnPos += s.length;
- if (this.columnPos > this.lineLimit) throw new Error('over line limit');
- }
-
- /** Render a tab character. */
- private renderTab() {
- let tabSize = this.tabSize - (this.columnPos % this.tabSize);
- if (this.columnPos + tabSize > this.lineLimit) {
- this.renderLineBreak();
- tabSize = this.tabSize;
- }
- const piece = html`<span
- class=${diffClasses('tab')}
- style="tab-size: ${tabSize}; -moz-tab-size: ${tabSize};"
- >${TAB}</span
- >`;
- this.pieces.push(piece);
- this.textOffset += 1;
- this.columnPos += tabSize;
- }
-
- /** Render a surrogate pair: string length is 2, but is just 1 char. */
- private renderSurrogatePair() {
- if (this.columnPos === this.lineLimit) {
- this.renderLineBreak();
- }
- this.pieces.push(this.text.substring(this.textOffset, this.textOffset + 2));
- this.textOffset += 2;
- this.columnPos += 1;
- }
-
- /** Render a line break, don't advance text offset, reset col position. */
- private renderLineBreak() {
- if (this.isResponsive) {
- this.pieces.push(html`<wbr class=${diffClasses()}></wbr>`);
- } else {
- this.pieces.push(html`<span class=${diffClasses('br')}></span>`);
- }
- // this.textOffset += 0;
- this.columnPos = 0;
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'gr-diff-text': GrDiffText;
- }
-}
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-text_test.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-text_test.ts
deleted file mode 100644
index 21c0936cef..0000000000
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/gr-diff-text_test.ts
+++ /dev/null
@@ -1,154 +0,0 @@
-/**
- * @license
- * Copyright 2022 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-import '../../../test/common-test-setup-karma';
-import './gr-diff-text';
-import {GrDiffText} from './gr-diff-text';
-import {html} from 'lit';
-import {fixture} from '@open-wc/testing-helpers';
-
-const LINE_BREAK = '<span class="style-scope gr-diff br"></span>';
-
-const TAB = '<span class="" style=""></span>';
-
-const TAB_IGNORE = ['class', 'style'];
-
-suite('gr-diff-text test', () => {
- let element: GrDiffText;
-
- setup(async () => {
- element = await fixture<GrDiffText>(html`<gr-diff-text></gr-diff-text>`);
- await element.updateComplete;
- });
-
- const check = async (
- text: string,
- html: string,
- ignoreAttributes: string[] = []
- ) => {
- element.text = text;
- element.tabSize = 4;
- element.lineLimit = 10;
- await element.updateComplete;
- expect(element).lightDom.to.equal(html, {ignoreAttributes});
- };
-
- suite('lit rendering', () => {
- test('renderText newlines 1', () => {
- check('abcdef', 'abcdef');
- check('a'.repeat(20), `aaaaaaaaaa${LINE_BREAK}aaaaaaaaaa`);
- });
-
- test('renderText newlines 2', () => {
- check(
- '<span class="thumbsup">👍</span>',
- '&lt;span clas' +
- LINE_BREAK +
- 's="thumbsu' +
- LINE_BREAK +
- 'p"&gt;👍&lt;/span' +
- LINE_BREAK +
- '&gt;'
- );
- });
-
- test('renderText newlines 3', () => {
- check(
- '01234\t56789',
- '01234' + TAB + '56' + LINE_BREAK + '789',
- TAB_IGNORE
- );
- });
-
- test('renderText newlines 4', async () => {
- element.lineLimit = 20;
- await element.updateComplete;
- check(
- '👍'.repeat(58),
- '👍'.repeat(20) +
- LINE_BREAK +
- '👍'.repeat(20) +
- LINE_BREAK +
- '👍'.repeat(18)
- );
- });
-
- test('tab wrapper style', async () => {
- for (const size of [1, 3, 8, 55]) {
- element.tabSize = size;
- await element.updateComplete;
- check(
- '\t',
- /* HTML */ `
- <span
- class="style-scope gr-diff tab"
- style="tab-size: ${size}; -moz-tab-size: ${size};"
- >
- </span>
- `
- );
- }
- });
-
- test('tab wrapper insertion', () => {
- check('abc\tdef', 'abc' + TAB + 'def', TAB_IGNORE);
- });
-
- test('escaping HTML', async () => {
- element.lineLimit = 100;
- await element.updateComplete;
- check(
- '<script>alert("XSS");<' + '/script>',
- '&lt;script&gt;alert("XSS");&lt;/script&gt;'
- );
- check('& < > " \' / `', '&amp; &lt; &gt; " \' / `');
- });
-
- test('text length with tabs and unicode', async () => {
- async function expectTextLength(
- text: string,
- tabSize: number,
- expected: number
- ) {
- element.text = text;
- element.tabSize = tabSize;
- element.lineLimit = expected;
- await element.updateComplete;
- const result = element.innerHTML;
-
- // Must not contain a line break.
- assert.isNotOk(element.querySelector('span.br'));
-
- // Increasing the line limit by 1 should not change anything.
- element.lineLimit = expected + 1;
- await element.updateComplete;
- const resultPlusOne = element.innerHTML;
- assert.equal(resultPlusOne, result);
-
- // Increasing the line limit to infinity should not change anything.
- element.lineLimit = Infinity;
- await element.updateComplete;
- const resultInf = element.innerHTML;
- assert.equal(resultInf, result);
-
- // Decreasing the line limit by 1 should introduce a line break.
- element.lineLimit = expected + 1;
- await element.updateComplete;
- assert.isNotOk(element.querySelector('span.br'));
- }
- expectTextLength('12345', 4, 5);
- expectTextLength('\t\t12', 4, 10);
- expectTextLength('abc💢123', 4, 7);
- expectTextLength('abc\t', 8, 8);
- expectTextLength('abc\t\t', 10, 20);
- expectTextLength('', 10, 0);
- // 17 Thai combining chars.
- expectTextLength('ก้้้้้้้้้้้้้้้้', 4, 17);
- expectTextLength('abc\tde', 10, 12);
- expectTextLength('abc\tde\t', 10, 20);
- expectTextLength('\t\t\t\t\t', 20, 100);
- });
- });
-});
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor.ts b/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor.ts
index 4ecdcb0a78..dfe8a15d69 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-cursor/gr-diff-cursor.ts
@@ -228,7 +228,6 @@ export class GrDiffCursor implements GrDiffCursorApi {
path?: string,
intentionalMove?: boolean
) {
- this._updateStops();
const row = this._findRowByNumberAndFile(number, side, path);
if (row) {
this.side = side;
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-selection/gr-diff-selection.ts b/polygerrit-ui/app/embed/diff/gr-diff-selection/gr-diff-selection.ts
index 22af7e3e45..2665ef0cdd 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-selection/gr-diff-selection.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-selection/gr-diff-selection.ts
@@ -23,11 +23,7 @@ import {
normalize,
NormalizedRange,
} from '../gr-diff-highlight/gr-range-normalizer';
-import {
- descendedFromClass,
- isElementTarget,
- querySelectorAll,
-} from '../../../utils/dom-util';
+import {descendedFromClass, querySelectorAll} from '../../../utils/dom-util';
import {customElement, property, observe} from '@polymer/decorators';
import {DiffInfo} from '../../../types/diff';
import {Side} from '../../../constants/constants';
@@ -113,9 +109,8 @@ export class GrDiffSelection extends PolymerElement {
}
_handleDown(e: Event) {
- const target = e.composedPath()[0];
- if (!isElementTarget(target)) return;
-
+ const target = e.target;
+ if (!(target instanceof Element)) return;
// Handle the down event on comment thread in Polymer 2
const handled = this._handleDownOnRangeComment(target);
if (handled) return;
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-line.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-line.ts
index 8593e1b30d..29271018e6 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-line.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-line.ts
@@ -19,7 +19,6 @@ import {
GrDiffLine as GrDiffLineApi,
GrDiffLineType,
LineNumber,
- Side,
} from '../../../api/diff';
export {GrDiffLineType, LineNumber};
@@ -39,10 +38,6 @@ export class GrDiffLine implements GrDiffLineApi {
text = '';
- lineNumber(side: Side) {
- return side === Side.LEFT ? this.beforeNumber : this.afterNumber;
- }
-
// TODO(TS): remove this properties
static readonly Type = GrDiffLineType;
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts
index a12867f9c7..182d48e490 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils.ts
@@ -45,20 +45,12 @@ import {getBaseUrl} from '../../../utils/url-util';
* Graphemes: http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
* A proposed JS API: https://github.com/tc39/proposal-intl-segmenter
*/
-export const REGEX_TAB_OR_SURROGATE_PAIR = /\t|[\uD800-\uDBFF][\uDC00-\uDFFF]/;
+const REGEX_TAB_OR_SURROGATE_PAIR = /\t|[\uD800-\uDBFF][\uDC00-\uDFFF]/;
// If any line of the diff is more than the character limit, then disable
// syntax highlighting for the entire file.
export const SYNTAX_MAX_LINE_LENGTH = 500;
-export function countLines(diff?: DiffInfo, side?: Side) {
- if (!diff?.content || !side) return 0;
- return diff.content.reduce((sum, chunk) => {
- const sideChunk = side === Side.LEFT ? chunk.a : chunk.b;
- return sum + (sideChunk?.length ?? chunk.ab?.length ?? chunk.skip ?? 0);
- }, 0);
-}
-
export function getResponsiveMode(
prefs: DiffPreferencesInfo,
renderPrefs?: RenderPreferences
@@ -73,7 +65,7 @@ export function getResponsiveMode(
return 'NONE';
}
-export function isResponsive(responsiveMode?: DiffResponsiveMode) {
+export function isResponsive(responsiveMode: DiffResponsiveMode) {
return (
responsiveMode === 'FULL_RESPONSIVE' || responsiveMode === 'SHRINK_ONLY'
);
@@ -124,12 +116,7 @@ export function getLineElByChild(node?: Node): HTMLElement | null {
return null;
}
}
- node =
- (node as Element).assignedSlot ??
- (node as ShadowRoot).host ??
- node.previousSibling ??
- node.parentNode ??
- undefined;
+ node = node.previousSibling ?? node.parentElement ?? undefined;
}
return null;
}
@@ -208,19 +195,6 @@ export function anyLineTooLong(diff?: DiffInfo) {
}
/**
- * Simple helper method for creating element classes in the context of
- * gr-diff.
- *
- * We are adding 'style-scope', 'gr-diff' classes for compatibility with
- * Shady DOM. TODO: Is that still required??
- *
- * Otherwise this is just a super simple convenience function.
- */
-export function diffClasses(...additionalClasses: string[]) {
- return ['style-scope', 'gr-diff', ...additionalClasses].join(' ');
-}
-
-/**
* Simple helper method for creating elements in the context of gr-diff.
*
* We are adding 'style-scope', 'gr-diff' classes for compatibility with
@@ -281,8 +255,6 @@ export function createTabWrapper(tabSize: number): HTMLElement {
}
/**
- * Deprecated: Lit based rendering uses the textToPieces() function above.
- *
* Returns a 'div' element containing the supplied |text| as its innerText,
* with '\t' characters expanded to a width determined by |tabSize|, and the
* text wrapped at column |lineLimit|, which may be Infinity if no wrapping is
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils_test.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils_test.ts
index 793b0efa95..600913e57a 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-utils_test.ts
@@ -4,171 +4,150 @@
* SPDX-License-Identifier: Apache-2.0
*/
import '../../../test/common-test-setup-karma';
-import {
- createElementDiff,
- formatText,
- createTabWrapper,
- diffClasses,
-} from './gr-diff-utils';
+import {createElementDiff, formatText, createTabWrapper} from './gr-diff-utils';
const LINE_BREAK_HTML = '<span class="style-scope gr-diff br"></span>';
suite('gr-diff-utils tests', () => {
- suite('legacy rendering', () => {
- test('createElementDiff classStr applies all classes', () => {
- const node = createElementDiff('div', 'test classes');
- assert.isTrue(node.classList.contains('gr-diff'));
- assert.isTrue(node.classList.contains('test'));
- assert.isTrue(node.classList.contains('classes'));
- });
-
- test('formatText newlines 1', () => {
- let text = 'abcdef';
-
- assert.equal(formatText(text, 'NONE', 4, 10).innerHTML, text);
- text = 'a'.repeat(20);
- assert.equal(
- formatText(text, 'NONE', 4, 10).innerHTML,
- 'a'.repeat(10) + LINE_BREAK_HTML + 'a'.repeat(10)
- );
- });
+ test('createElementDiff classStr applies all classes', () => {
+ const node = createElementDiff('div', 'test classes');
+ assert.isTrue(node.classList.contains('gr-diff'));
+ assert.isTrue(node.classList.contains('test'));
+ assert.isTrue(node.classList.contains('classes'));
+ });
- test('formatText newlines 2', () => {
- const text = '<span class="thumbsup">👍</span>';
- assert.equal(
- formatText(text, 'NONE', 4, 10).innerHTML,
- '&lt;span clas' +
- LINE_BREAK_HTML +
- 's="thumbsu' +
- LINE_BREAK_HTML +
- 'p"&gt;👍&lt;/span' +
- LINE_BREAK_HTML +
- '&gt;'
- );
- });
+ test('formatText newlines 1', () => {
+ let text = 'abcdef';
- test('formatText newlines 3', () => {
- const text = '01234\t56789';
- assert.equal(
- formatText(text, 'NONE', 4, 10).innerHTML,
- '01234' + createTabWrapper(3).outerHTML + '56' + LINE_BREAK_HTML + '789'
- );
- });
+ assert.equal(formatText(text, 'NONE', 4, 10).innerHTML, text);
+ text = 'a'.repeat(20);
+ assert.equal(
+ formatText(text, 'NONE', 4, 10).innerHTML,
+ 'a'.repeat(10) + LINE_BREAK_HTML + 'a'.repeat(10)
+ );
+ });
- test('formatText newlines 4', () => {
- const text = '👍'.repeat(58);
- assert.equal(
- formatText(text, 'NONE', 4, 20).innerHTML,
+ test('formatText newlines 2', () => {
+ const text = '<span class="thumbsup">👍</span>';
+ assert.equal(
+ formatText(text, 'NONE', 4, 10).innerHTML,
+ '&lt;span clas' +
+ LINE_BREAK_HTML +
+ 's="thumbsu' +
+ LINE_BREAK_HTML +
+ 'p"&gt;👍&lt;/span' +
+ LINE_BREAK_HTML +
+ '&gt;'
+ );
+ });
+
+ test('formatText newlines 3', () => {
+ const text = '01234\t56789';
+ assert.equal(
+ formatText(text, 'NONE', 4, 10).innerHTML,
+ '01234' + createTabWrapper(3).outerHTML + '56' + LINE_BREAK_HTML + '789'
+ );
+ });
+
+ test('formatText newlines 4', () => {
+ const text = '👍'.repeat(58);
+ assert.equal(
+ formatText(text, 'NONE', 4, 20).innerHTML,
+ '👍'.repeat(20) +
+ LINE_BREAK_HTML +
'👍'.repeat(20) +
- LINE_BREAK_HTML +
- '👍'.repeat(20) +
- LINE_BREAK_HTML +
- '👍'.repeat(18)
- );
- });
+ LINE_BREAK_HTML +
+ '👍'.repeat(18)
+ );
+ });
- test('tab wrapper style', () => {
- const pattern = new RegExp(
- '^<span class="style-scope gr-diff tab" ' +
- 'style="((?:-moz-)?tab-size: (\\d+);.?)+">\\t<\\/span>$'
+ test('tab wrapper style', () => {
+ const pattern = new RegExp(
+ '^<span class="style-scope gr-diff tab" ' +
+ 'style="((?:-moz-)?tab-size: (\\d+);.?)+">\\t<\\/span>$'
+ );
+
+ for (const size of [1, 3, 8, 55]) {
+ const html = createTabWrapper(size).outerHTML;
+ expect(html).to.match(pattern);
+ assert.equal(html.match(pattern)?.[2], size.toString());
+ }
+ });
+
+ test('tab wrapper insertion', () => {
+ const html = 'abc\tdef';
+ const tabSize = 8;
+ const wrapper = createTabWrapper(tabSize - 3);
+ assert.ok(wrapper);
+ assert.equal(wrapper.innerText, '\t');
+ assert.equal(
+ formatText(html, 'NONE', tabSize, Infinity).innerHTML,
+ 'abc' + wrapper.outerHTML + 'def'
+ );
+ });
+
+ test('escaping HTML', () => {
+ let input = '<script>alert("XSS");<' + '/script>';
+ let expected = '&lt;script&gt;alert("XSS");&lt;/script&gt;';
+
+ let result = formatText(
+ input,
+ 'NONE',
+ 1,
+ Number.POSITIVE_INFINITY
+ ).innerHTML;
+ assert.equal(result, expected);
+
+ input = '& < > " \' / `';
+ expected = '&amp; &lt; &gt; " \' / `';
+ result = formatText(input, 'NONE', 1, Number.POSITIVE_INFINITY).innerHTML;
+ assert.equal(result, expected);
+ });
+
+ test('text length with tabs and unicode', () => {
+ function expectTextLength(text: string, tabSize: number, expected: number) {
+ // Formatting to |expected| columns should not introduce line breaks.
+ const result = formatText(text, 'NONE', tabSize, expected);
+ assert.isNotOk(
+ result.querySelector('.contentText > .br'),
+ ' Expected the result of: \n' +
+ ` _formatText(${text}', 'NONE', ${tabSize}, ${expected})\n` +
+ ' to not contain a br. But the actual result HTML was:\n' +
+ ` '${result.innerHTML}'\nwhereupon`
);
- for (const size of [1, 3, 8, 55]) {
- const html = createTabWrapper(size).outerHTML;
- expect(html).to.match(pattern);
- assert.equal(html.match(pattern)?.[2], size.toString());
- }
- });
-
- test('tab wrapper insertion', () => {
- const html = 'abc\tdef';
- const tabSize = 8;
- const wrapper = createTabWrapper(tabSize - 3);
- assert.ok(wrapper);
- assert.equal(wrapper.innerText, '\t');
+ // Increasing the line limit should produce the same markup.
assert.equal(
- formatText(html, 'NONE', tabSize, Infinity).innerHTML,
- 'abc' + wrapper.outerHTML + 'def'
+ formatText(text, 'NONE', tabSize, Infinity).innerHTML,
+ result.innerHTML
+ );
+ assert.equal(
+ formatText(text, 'NONE', tabSize, expected + 1).innerHTML,
+ result.innerHTML
);
- });
-
- test('escaping HTML', () => {
- let input = '<script>alert("XSS");<' + '/script>';
- let expected = '&lt;script&gt;alert("XSS");&lt;/script&gt;';
-
- let result = formatText(
- input,
- 'NONE',
- 1,
- Number.POSITIVE_INFINITY
- ).innerHTML;
- assert.equal(result, expected);
-
- input = '& < > " \' / `';
- expected = '&amp; &lt; &gt; " \' / `';
- result = formatText(input, 'NONE', 1, Number.POSITIVE_INFINITY).innerHTML;
- assert.equal(result, expected);
- });
-
- test('text length with tabs and unicode', () => {
- function expectTextLength(
- text: string,
- tabSize: number,
- expected: number
- ) {
- // Formatting to |expected| columns should not introduce line breaks.
- const result = formatText(text, 'NONE', tabSize, expected);
- assert.isNotOk(
- result.querySelector('.contentText > .br'),
- ' Expected the result of: \n' +
- ` _formatText(${text}', 'NONE', ${tabSize}, ${expected})\n` +
- ' to not contain a br. But the actual result HTML was:\n' +
- ` '${result.innerHTML}'\nwhereupon`
- );
- // Increasing the line limit should produce the same markup.
- assert.equal(
- formatText(text, 'NONE', tabSize, Infinity).innerHTML,
- result.innerHTML
- );
- assert.equal(
- formatText(text, 'NONE', tabSize, expected + 1).innerHTML,
- result.innerHTML
+ // Decreasing the line limit should introduce line breaks.
+ if (expected > 0) {
+ const tooSmall = formatText(text, 'NONE', tabSize, expected - 1);
+ assert.isOk(
+ tooSmall.querySelector('.contentText > .br'),
+ ' Expected the result of: \n' +
+ ` _formatText(${text}', ${tabSize}, ${expected - 1})\n` +
+ ' to contain a br. But the actual result HTML was:\n' +
+ ` '${tooSmall.innerHTML}'\nwhereupon`
);
-
- // Decreasing the line limit should introduce line breaks.
- if (expected > 0) {
- const tooSmall = formatText(text, 'NONE', tabSize, expected - 1);
- assert.isOk(
- tooSmall.querySelector('.contentText > .br'),
- ' Expected the result of: \n' +
- ` _formatText(${text}', ${tabSize}, ${expected - 1})\n` +
- ' to contain a br. But the actual result HTML was:\n' +
- ` '${tooSmall.innerHTML}'\nwhereupon`
- );
- }
}
- expectTextLength('12345', 4, 5);
- expectTextLength('\t\t12', 4, 10);
- expectTextLength('abc💢123', 4, 7);
- expectTextLength('abc\t', 8, 8);
- expectTextLength('abc\t\t', 10, 20);
- expectTextLength('', 10, 0);
- // 17 Thai combining chars.
- expectTextLength('ก้้้้้้้้้้้้้้้้', 4, 17);
- expectTextLength('abc\tde', 10, 12);
- expectTextLength('abc\tde\t', 10, 20);
- expectTextLength('\t\t\t\t\t', 20, 100);
- });
- });
-
- suite('lit rendering', () => {
- test('diffClasses', () => {
- const c = diffClasses('div', 'test classes').split(' ');
- assert.include(c, 'gr-diff');
- assert.include(c, 'style-scope');
- assert.include(c, 'test');
- assert.include(c, 'classes');
- });
+ }
+ expectTextLength('12345', 4, 5);
+ expectTextLength('\t\t12', 4, 10);
+ expectTextLength('abc💢123', 4, 7);
+ expectTextLength('abc\t', 8, 8);
+ expectTextLength('abc\t\t', 10, 20);
+ expectTextLength('', 10, 0);
+ // 17 Thai combining chars.
+ expectTextLength('ก้้้้้้้้้้้้้้้้', 4, 17);
+ expectTextLength('abc\tde', 10, 12);
+ expectTextLength('abc\tde\t', 10, 20);
+ expectTextLength('\t\t\t\t\t', 20, 100);
});
});
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 f7e40f9ac2..a38ec91854 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
@@ -24,7 +24,7 @@ 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 {PolymerElement} from '@polymer/polymer/polymer-element';
-import {dom} from '@polymer/polymer/lib/legacy/polymer.dom';
+import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
import {htmlTemplate} from './gr-diff_html';
import {LineNumber} from './gr-diff-line';
import {
@@ -77,7 +77,7 @@ import {
GrDiff as GrDiffApi,
DisplayLine,
} from '../../../api/diff';
-import {isElementTarget, isSafari, toggleClass} from '../../../utils/dom-util';
+import {isSafari, toggleClass} from '../../../utils/dom-util';
import {assertIsDefined} from '../../../utils/common-util';
import {debounce, DelayedTask} from '../../../utils/async-util';
@@ -530,8 +530,7 @@ export class GrDiff extends PolymerElement implements GrDiffApi {
}
_handleTap(e: CustomEvent) {
- const el = e.composedPath()[0];
- if (!isElementTarget(el)) return;
+ const el = (dom(e) as EventApi).localTarget as Element;
if (
el.getAttribute('data-value') !== 'LOST' &&
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 c2e5550e38..e05e85aa88 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
@@ -670,12 +670,6 @@ export const htmlTemplate = html`
.token-highlight {
background-color: var(--token-highlighting-color, #fffd54);
}
-
- gr-diff-section,
- gr-context-controls-section,
- gr-diff-row {
- display: contents;
- }
</style>
<style include="gr-syntax-theme">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */