Files
react-native-devtools-frontend/front_end/components/ImagePreview.js
T
Tim van der Lippe 213266c175 Migrate trimMiddle to string-utilities
R=szuend@chromium.org

Bug: 1050549
Change-Id: I4fd1a5051ca31270e28e53038f68ea79d0d03c4f
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2631114
Commit-Queue: Tim van der Lippe <tvanderlippe@chromium.org>
Auto-Submit: Tim van der Lippe <tvanderlippe@chromium.org>
Reviewed-by: Simon Zünd <szuend@chromium.org>
2021-01-19 13:02:57 +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', Platform.StringUtilities.trimMiddle(imageURL, 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});
}
}