in polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts [409:646]
override render() {
const src = this.baseSelected ? this.baseUrl : this.revisionUrl;
const sourceImage = html`
<img
id="source-image"
src="${src}"
class="${classMap({checkerboard: this.checkerboardSelected})}"
style="${styleMap({
backgroundColor: this.checkerboardSelected
? ''
: this.backgroundColor,
})}"
@load="${this.updateSizes}"
/>
`;
const sourceImageWithHighlight = html`
<div id="source-plus-highlight-container">
${sourceImage}
<img
id="highlight-image"
style="${styleMap({
opacity: this.showHighlight ? '1' : '0',
// When the highlight layer is not being shown, saving the image or
// opening it in a new tab from the context menu, e.g. for external
// comparison, should give back the source image, not the highlight
// layer.
'pointer-events': this.showHighlight ? 'auto' : 'none',
})}"
src="${ifDefined(this.diffHighlightSrc)}"
/>
</div>
`;
const versionExplanation = html`
<div id="version-explanation">
This file is being ${this.revisionUrl ? 'added' : 'deleted'}.
</div>
`;
// This uses the unelevated and outlined attributes from mwc-button with
// manual styling, for a more seamless transition later.
const leftClasses = {
left: true,
unelevated: this.baseSelected,
outlined: !this.baseSelected,
};
const rightClasses = {
right: true,
unelevated: !this.baseSelected,
outlined: this.baseSelected,
};
const versionToggle = html`
<div id="version-switcher">
<paper-button
class="${classMap(leftClasses)}"
@click="${this.selectBase}"
>
Base
</paper-button>
<paper-fab mini icon="gr-icons:swapHoriz" @click="${this.manualBlink}">
</paper-fab>
<paper-button
class="${classMap(rightClasses)}"
@click="${this.selectRevision}"
>
Revision
</paper-button>
</div>
`;
const versionSwitcher = html`
${this.baseUrl && this.revisionUrl ? versionToggle : versionExplanation}
`;
const highlightSwitcher = this.diffHighlightSrc
? html`
<paper-checkbox
id="highlight-changes"
?checked="${this.showHighlight}"
@change="${this.showHighlightChanged}"
>
Highlight differences
</paper-checkbox>
`
: '';
const overviewImage = html`
<gr-overview-image
.frameRect="${this.overviewFrame}"
@center-updated="${this.onOverviewCenterUpdated}"
>
<img
src="${src}"
class="${classMap({checkerboard: this.checkerboardSelected})}"
style="${styleMap({
backgroundColor: this.checkerboardSelected
? ''
: this.backgroundColor,
})}"
/>
</gr-overview-image>
`;
const zoomControl = html`
<paper-dropdown-menu id="zoom-control" label="Zoom">
<paper-listbox
slot="dropdown-content"
selected="fit"
.attrForSelected="${'value'}"
@selected-changed="${this.zoomControlChanged}"
>
${this.zoomLevels.map(
zoomLevel => html`
<paper-item value="${zoomLevel}">
${zoomLevel === 'fit' ? 'Fit' : `${zoomLevel * 100}%`}
</paper-item>
`
)}
</paper-listbox>
</paper-dropdown-menu>
`;
const followMouse = html`
<paper-checkbox
id="follow-mouse"
?checked="${this.followMouse}"
@change="${this.followMouseChanged}"
>
Magnifier follows mouse
</paper-checkbox>
`;
const backgroundPicker = html`
<div class="color-picker">
<div class="label">Background</div>
<div class="options">
${this.renderCheckerboardButton()}
${this.colorPickerCallbacks.map(({color, callback}) =>
this.renderColorPickerButton(color, callback)
)}
</div>
</div>
`;
/*
* We want the content to fill the available space until it can display
* without being cropped, the maximum of which will be determined by
* (max-)width and (max-)height constraints on the host element; but we
* are also limiting the displayed content to the measured dimensions of
* the host element without overflow, so we need something else to take up
* the requested space unconditionally.
*/
const spacerScale = Math.max(this.scale, 1);
const spacerWidth = this.imageSize.width * spacerScale;
const spacerHeight = this.imageSize.height * spacerScale;
const spacer = html`
<div
id="spacer"
style="${styleMap({
width: `${spacerWidth}px`,
height: `${spacerHeight}px`,
})}"
></div>
`;
const automaticBlink = html`
<paper-fab
id="automatic-blink-button"
class="${classMap({show: this.automaticBlinkShown})}"
title="Automatic blink"
icon="gr-icons:${this.automaticBlink ? 'pause' : 'playArrow'}"
@click="${this.toggleAutomaticBlink}"
>
</paper-fab>
`;
// To pass CSS mixins for @apply to Polymer components, they need to appear
// in <style> inside the template.
/* eslint-disable lit/prefer-static-styles */
const customStyle = html`
<style>
paper-item {
--paper-item-min-height: 48;
--paper-item: {
min-height: 48px;
padding: 0 var(--spacing-xl);
}
--paper-item-focused-before: {
background-color: var(--selection-background-color);
}
--paper-item-focused: {
background-color: var(--selection-background-color);
}
}
</style>
`;
return html`
${customStyle}
<div
class="imageArea"
@mousemove="${this.mousemoveImageArea}"
@mouseleave="${this.mouseleaveImageArea}"
>
<gr-zoomed-image
class="${classMap({
base: this.baseSelected,
revision: !this.baseSelected,
})}"
style="${styleMap({
...this.zoomedImageStyle,
cursor: this.grabbing ? 'grabbing' : 'pointer',
})}"
.scale="${this.scale}"
.frameRect="${this.magnifierFrame}"
@mousedown="${this.mousedownMagnifier}"
@mouseup="${this.mouseupMagnifier}"
@mousemove="${this.mousemoveMagnifier}"
@mouseleave="${this.mouseleaveMagnifier}"
@dragstart="${this.dragstartMagnifier}"
>
${sourceImageWithHighlight}
</gr-zoomed-image>
${this.baseUrl && this.revisionUrl ? automaticBlink : ''} ${spacer}
</div>
<div class="dimensions">
${this.imageSize.width} x ${this.imageSize.height}
</div>
<paper-card class="controls">
${versionSwitcher} ${highlightSwitcher} ${overviewImage} ${zoomControl}
${!this.scaledSelected ? followMouse : ''} ${backgroundPicker}
</paper-card>
`;
}