blob: e7ae8a492f0f37391799ce418691653a22115db6 [file] [log] [blame]
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import '../../../elements/shared/gr-button/gr-button';
import {html, LitElement} from 'lit';
import {property, state} from 'lit/decorators.js';
import {DiffInfo, DiffViewMode, RenderPreferences} from '../../../api/diff';
import {GrDiffGroup, GrDiffGroupType} from '../gr-diff/gr-diff-group';
import {diffClasses, isNewDiff} from '../gr-diff/gr-diff-utils';
import {getShowConfig} from './gr-context-controls';
import {ifDefined} from 'lit/directives/if-defined.js';
import {when} from 'lit/directives/when.js';
import {subscribe} from '../../../elements/lit/subscription-controller';
import {resolve} from '../../../models/dependency';
import {diffModelToken} from '../gr-diff-model/gr-diff-model';
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;
/** 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;
@state() viewMode: DiffViewMode = DiffViewMode.SIDE_BY_SIDE;
private readonly getDiffModel = resolve(this, diffModelToken);
constructor() {
super();
subscribe(
this,
() => this.getDiffModel().viewMode$,
viewMode => (this.viewMode = viewMode)
);
}
/**
* 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 modeClass = this.isSideBySide() ? 'side-by-side' : 'unified';
const type = this.isSideBySide()
? 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>
${when(
this.isSideBySide(),
() => html`
<td class=${diffClasses('sign')}></td>
<td class=${diffClasses()}></td>
`
)}
<td class=${diffClasses('contextLineNum')}></td>
${when(
this.isSideBySide(),
() => html`<td class=${diffClasses('sign')}></td>`
)}
<td class=${diffClasses()}></td>
</tr>
`;
}
private isSideBySide() {
return this.viewMode !== DiffViewMode.UNIFIED;
}
private createContextControlRow() {
// Note that <td> table cells that have `display: none` don't count!
const colspan = this.renderPrefs?.show_sign_col ? '5' : '3';
const showConfig = getShowConfig(this.showAbove, this.showBelow);
return html`
<tr class=${diffClasses('dividerRow', `show-${showConfig}`)}>
<td class=${diffClasses('blame')} data-line-number="0"></td>
${when(
this.isSideBySide(),
() => html`<td class=${diffClasses()}></td>`
)}
<td class=${diffClasses('dividerCell')} colspan=${colspan}>
<gr-context-controls
class=${diffClasses()}
.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;
}
}
// TODO(newdiff-cleanup): Remove once newdiff migration is completed.
if (isNewDiff()) {
customElements.define(
'gr-context-controls-section',
GrContextControlsSection
);
}
declare global {
interface HTMLElementTagNameMap {
// TODO(newdiff-cleanup): Replace once newdiff migration is completed.
'gr-context-controls-section': LitElement;
}
}