diff options
Diffstat (limited to 'devtools/client/shared/widgets/tooltip/ImageTooltipHelper.js')
-rw-r--r-- | devtools/client/shared/widgets/tooltip/ImageTooltipHelper.js | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/devtools/client/shared/widgets/tooltip/ImageTooltipHelper.js b/devtools/client/shared/widgets/tooltip/ImageTooltipHelper.js new file mode 100644 index 0000000000..aa2cc75eb7 --- /dev/null +++ b/devtools/client/shared/widgets/tooltip/ImageTooltipHelper.js @@ -0,0 +1,145 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +const { LocalizationHelper } = require("resource://devtools/shared/l10n.js"); +const L10N = new LocalizationHelper( + "devtools/client/locales/inspector.properties" +); + +const XHTML_NS = "http://www.w3.org/1999/xhtml"; + +// Default image tooltip max dimension +const MAX_DIMENSION = 200; +const CONTAINER_MIN_WIDTH = 100; +// Should remain synchronized with tooltips.css --image-tooltip-image-padding +const IMAGE_PADDING = 4; +// Should remain synchronized with tooltips.css --image-tooltip-label-height +const LABEL_HEIGHT = 20; + +/** + * Image preview tooltips should be provided with the naturalHeight and + * naturalWidth value for the image to display. This helper loads the provided + * image URL in an image object in order to retrieve the image dimensions after + * the load. + * + * @param {Document} doc the document element to use to create the image object + * @param {String} imageUrl the url of the image to measure + * @return {Promise} returns a promise that will resolve after the iamge load: + * - {Number} naturalWidth natural width of the loaded image + * - {Number} naturalHeight natural height of the loaded image + */ +function getImageDimensions(doc, imageUrl) { + return new Promise(resolve => { + const imgObj = new doc.defaultView.Image(); + imgObj.onload = () => { + imgObj.onload = null; + const { naturalWidth, naturalHeight } = imgObj; + resolve({ naturalWidth, naturalHeight }); + }; + imgObj.src = imageUrl; + }); +} + +/** + * Set the tooltip content of a provided HTMLTooltip instance to display an + * image preview matching the provided imageUrl. + * + * @param {HTMLTooltip} tooltip + * The tooltip instance on which the image preview content should be set + * @param {Document} doc + * A document element to create the HTML elements needed for the tooltip + * @param {String} imageUrl + * Absolute URL of the image to display in the tooltip + * @param {Object} options + * - {Number} naturalWidth mandatory, width of the image to display + * - {Number} naturalHeight mandatory, height of the image to display + * - {Number} maxDim optional, max width/height of the preview + * - {Boolean} hideDimensionLabel optional, pass true to hide the label + * - {Boolean} hideCheckeredBackground optional, pass true to hide + the checkered background + */ +function setImageTooltip(tooltip, doc, imageUrl, options) { + let { + naturalWidth, + naturalHeight, + hideDimensionLabel, + hideCheckeredBackground, + maxDim, + } = options; + maxDim = maxDim || MAX_DIMENSION; + + let imgHeight = naturalHeight; + let imgWidth = naturalWidth; + if (imgHeight > maxDim || imgWidth > maxDim) { + const scale = maxDim / Math.max(imgHeight, imgWidth); + // Only allow integer values to avoid rounding errors. + imgHeight = Math.floor(scale * naturalHeight); + imgWidth = Math.ceil(scale * naturalWidth); + } + + // Create tooltip content + const container = doc.createElementNS(XHTML_NS, "div"); + container.classList.add("devtools-tooltip-image-container"); + + const wrapper = doc.createElementNS(XHTML_NS, "div"); + wrapper.classList.add("devtools-tooltip-image-wrapper"); + container.appendChild(wrapper); + + const img = doc.createElementNS(XHTML_NS, "img"); + img.classList.add("devtools-tooltip-image"); + img.classList.toggle("devtools-tooltip-tiles", !hideCheckeredBackground); + img.style.height = imgHeight; + img.src = encodeURI(imageUrl); + wrapper.appendChild(img); + + if (!hideDimensionLabel) { + const dimensions = doc.createElementNS(XHTML_NS, "div"); + dimensions.classList.add("devtools-tooltip-image-dimensions"); + container.appendChild(dimensions); + + const label = naturalWidth + " \u00D7 " + naturalHeight; + const span = doc.createElementNS(XHTML_NS, "span"); + span.classList.add("theme-comment", "devtools-tooltip-caption"); + span.textContent = label; + dimensions.appendChild(span); + } + + tooltip.panel.innerHTML = ""; + tooltip.panel.appendChild(container); + + // Calculate tooltip dimensions + const width = Math.max(CONTAINER_MIN_WIDTH, imgWidth + 2 * IMAGE_PADDING); + let height = imgHeight + 2 * IMAGE_PADDING; + if (!hideDimensionLabel) { + height += parseFloat(LABEL_HEIGHT); + } + + tooltip.setContentSize({ width, height }); +} + +/* + * Set the tooltip content of a provided HTMLTooltip instance to display a + * fallback error message when an image preview tooltip can not be displayed. + * + * @param {HTMLTooltip} tooltip + * The tooltip instance on which the image preview content should be set + * @param {Document} doc + * A document element to create the HTML elements needed for the tooltip + */ +function setBrokenImageTooltip(tooltip, doc) { + const div = doc.createElementNS(XHTML_NS, "div"); + div.className = "theme-comment devtools-tooltip-image-broken"; + const message = L10N.getStr("previewTooltip.image.brokenImage"); + div.textContent = message; + + tooltip.panel.innerHTML = ""; + tooltip.panel.appendChild(div); + tooltip.setContentSize({ width: "auto", height: "auto" }); +} + +module.exports.getImageDimensions = getImageDimensions; +module.exports.setImageTooltip = setImageTooltip; +module.exports.setBrokenImageTooltip = setBrokenImageTooltip; |