Files
react-native-devtools-frontend/front_end/components/ImagePreview.js
T
Tim van der Lippe d7cfd14814 Fix no-implicit-coercion errors in front_end/
R=jacktfranklin@chromium.org

No-Presubmit: True
Bug: 1082789
Change-Id: Ic77884bf7e9b5dc74053915b3b10699368841b66
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2595268
Commit-Queue: Tim van der Lippe <tvanderlippe@chromium.org>
Reviewed-by: Jack Franklin <jacktfranklin@chromium.org>
2021-01-07 12:40:16 +00:00

163 lines
5.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Common from '../common/common.js';
import * as i18n from '../i18n/i18n.js';
import * as Platform from '../platform/platform.js';
import * as SDK from '../sdk/sdk.js';
import * as UI from '../ui/ui.js';
export const UIStrings = {
/**
*@description Description in Image Preview
*@example {500} PH1
*@example {300} PH2
*@example {200} PH3
*@example {100} PH4
*/
sSPxIntrinsicSSPx: '{PH1} × {PH2} px (intrinsic: {PH3} × {PH4} px)',
/**
*@description Description in Image Preview
*@example {500} PH1
*@example {500} PH2
*/
sSPx: '{PH1} × {PH2} px',
/**
*@description Alt text description of an image's source
*/
unknownSource: 'unknown source',
/**
*@description Text to indicate the source of an image
*@example {example.com} PH1
*/
imageFromS: 'Image from {PH1}',
};
const str_ = i18n.i18n.registerUIStrings('components/ImagePreview.js', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
/** @typedef {{
* renderedWidth: number,
* renderedHeight: number,
* currentSrc: (string|undefined)
* }}
*/
// @ts-ignore typedef
export let PrecomputedFeatures;
export class ImagePreview {
/**
* @param {!SDK.SDKModel.Target} target
* @param {string} originalImageURL
* @param {boolean} showDimensions
* @param {!{precomputedFeatures: (!PrecomputedFeatures|undefined), imageAltText: (string|undefined)}=} options
* @return {!Promise<?Element>}
*/
static async build(
target, originalImageURL, showDimensions, options = {precomputedFeatures: undefined, imageAltText: undefined}) {
const {precomputedFeatures, imageAltText} = options;
const resourceTreeModel = target.model(SDK.ResourceTreeModel.ResourceTreeModel);
if (!resourceTreeModel) {
return /** @type {?Element} */ (null);
}
let resource = resourceTreeModel.resourceForURL(originalImageURL);
let imageURL = originalImageURL;
if (!isImageResource(resource) && precomputedFeatures && precomputedFeatures.currentSrc) {
imageURL = precomputedFeatures.currentSrc;
resource = resourceTreeModel.resourceForURL(imageURL);
}
if (!resource || !isImageResource(resource)) {
return /** @type {?Element} */ (null);
}
/** @type {function(*):void} */
let fulfill;
const promise = new Promise(x => {
fulfill = x;
});
const imageElement = /** @type{!HTMLImageElement} */ (document.createElement('img'));
imageElement.addEventListener('load', buildContent, false);
imageElement.addEventListener('error', () => fulfill(null), false);
if (imageAltText) {
imageElement.alt = imageAltText;
}
resource.populateImageSource(imageElement);
return promise;
/**
* @param {?SDK.Resource.Resource} resource
* @return {boolean}
*/
function isImageResource(resource) {
return resource !== null && resource.resourceType() === Common.ResourceType.resourceTypes.Image;
}
function buildContent() {
const container = document.createElement('table');
UI.Utils.appendStyle(container, 'components/imagePreview.css', {enableLegacyPatching: false});
container.className = 'image-preview-container';
const intrinsicWidth = imageElement.naturalWidth;
const intrinsicHeight = imageElement.naturalHeight;
const renderedWidth = precomputedFeatures ? precomputedFeatures.renderedWidth : intrinsicWidth;
const renderedHeight = precomputedFeatures ? precomputedFeatures.renderedHeight : intrinsicHeight;
let description;
if (showDimensions) {
if (renderedHeight !== intrinsicHeight || renderedWidth !== intrinsicWidth) {
description = i18nString(
UIStrings.sSPxIntrinsicSSPx,
{PH1: renderedWidth, PH2: renderedHeight, PH3: intrinsicWidth, PH4: intrinsicHeight});
} else {
description = i18nString(UIStrings.sSPx, {PH1: renderedWidth, PH2: renderedHeight});
}
}
container.createChild('tr').createChild('td', 'image-container').appendChild(imageElement);
if (description) {
container.createChild('tr').createChild('td').createChild('span', 'description').textContent = description;
}
if (imageURL !== originalImageURL) {
container.createChild('tr').createChild('td').createChild('span', 'description').textContent =
Platform.StringUtilities.sprintf('currentSrc: %s', imageURL.trimMiddle(100));
}
fulfill(container);
}
}
/**
* @param {!SDK.DOMModel.DOMNode} node
* @return {!Promise<!PrecomputedFeatures|undefined>}
*/
static async loadDimensionsForNode(node) {
if (!node.nodeName() || node.nodeName().toLowerCase() !== 'img') {
return;
}
const object = await node.resolveToObject('');
if (!object) {
return;
}
const featuresObject = object.callFunctionJSON(features, undefined);
object.release();
return featuresObject;
/**
* @return {!PrecomputedFeatures}
* @this {!HTMLImageElement}
*/
function features() {
return {renderedWidth: this.width, renderedHeight: this.height, currentSrc: this.currentSrc};
}
}
/**
* @param {string} url
* @return {string}
*/
static defaultAltTextForImageURL(url) {
const parsedImageURL = new Common.ParsedURL.ParsedURL(url);
const imageSourceText = parsedImageURL.isValid ? parsedImageURL.displayName : i18nString(UIStrings.unknownSource);
return i18nString(UIStrings.imageFromS, {PH1: imageSourceText});
}
}