mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 16:55:40 +00:00
ceaeb93550
Differential Revision: https://phabricator.services.mozilla.com/D8389 --HG-- extra : moz-landing-system : lando
250 lines
7.3 KiB
JavaScript
250 lines
7.3 KiB
JavaScript
/* 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 { Cc, Ci } = require("chrome");
|
|
const { LocalizationHelper } = require("devtools/shared/l10n");
|
|
const Services = require("Services");
|
|
|
|
loader.lazyImporter(this, "Downloads", "resource://gre/modules/Downloads.jsm");
|
|
loader.lazyImporter(this, "OS", "resource://gre/modules/osfile.jsm");
|
|
loader.lazyImporter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm");
|
|
|
|
const STRINGS_URI = "devtools/shared/locales/screenshot.properties";
|
|
const L10N = new LocalizationHelper(STRINGS_URI);
|
|
|
|
const screenshotDescription = L10N.getStr("screenshotDesc");
|
|
const screenshotGroupOptions = L10N.getStr("screenshotGroupOptions");
|
|
const screenshotCommandParams = [
|
|
{
|
|
name: "clipboard",
|
|
type: "boolean",
|
|
description: L10N.getStr("screenshotClipboardDesc"),
|
|
manual: L10N.getStr("screenshotClipboardManual"),
|
|
},
|
|
{
|
|
name: "delay",
|
|
type: "number",
|
|
description: L10N.getStr("screenshotDelayDesc"),
|
|
manual: L10N.getStr("screenshotDelayManual"),
|
|
},
|
|
{
|
|
name: "dpr",
|
|
type: "number",
|
|
description: L10N.getStr("screenshotDPRDesc"),
|
|
manual: L10N.getStr("screenshotDPRManual"),
|
|
},
|
|
{
|
|
name: "fullpage",
|
|
type: "boolean",
|
|
description: L10N.getStr("screenshotFullPageDesc"),
|
|
manual: L10N.getStr("screenshotFullPageManual"),
|
|
},
|
|
{
|
|
name: "selector",
|
|
type: "string",
|
|
description: L10N.getStr("inspectNodeDesc"),
|
|
manual: L10N.getStr("inspectNodeManual"),
|
|
},
|
|
{
|
|
name: "file",
|
|
type: "boolean",
|
|
description: L10N.getStr("screenshotFileDesc"),
|
|
manual: L10N.getStr("screenshotFileManual"),
|
|
},
|
|
{
|
|
name: "filename",
|
|
type: "string",
|
|
description: L10N.getStr("screenshotFilenameDesc"),
|
|
manual: L10N.getStr("screenshotFilenameManual"),
|
|
},
|
|
];
|
|
|
|
/**
|
|
* Creates a string from an object for use when screenshot is passed the `--help` argument
|
|
*
|
|
* @param object param
|
|
* The param object to be formatted.
|
|
* @return string
|
|
* The formatted information from the param object as a string
|
|
*/
|
|
function formatHelpField(param) {
|
|
const padding = " ".repeat(5);
|
|
return Object.entries(param).map(([key, value]) => {
|
|
if (key === "name") {
|
|
const name = `${padding}--${value}`;
|
|
return name;
|
|
}
|
|
return `${padding.repeat(2)}${key}: ${value}`;
|
|
}).join("\n");
|
|
}
|
|
|
|
/**
|
|
* Creates a string response from the screenshot options for use when
|
|
* screenshot is passed the `--help` argument
|
|
*
|
|
* @return string
|
|
* The formatted information from the param object as a string
|
|
*/
|
|
function getFormattedHelpData() {
|
|
const formattedParams = screenshotCommandParams
|
|
.map(formatHelpField)
|
|
.join("\n\n");
|
|
|
|
return `${screenshotDescription}\n${screenshotGroupOptions}\n\n${formattedParams}`;
|
|
}
|
|
|
|
/**
|
|
* Main entry point in this file; Takes the original arguments that `:screenshot` was
|
|
* called with and the image value from the server, and uses the client window to add
|
|
* and audio effect.
|
|
*
|
|
* @param object window
|
|
* The Debugger Client window.
|
|
*
|
|
* @param object args
|
|
* The original args with which the screenshot
|
|
* was called.
|
|
* @param object value
|
|
* an object with a image value and file name
|
|
*
|
|
* @return string[]
|
|
* Response messages from processing the screenshot
|
|
*/
|
|
function saveScreenshot(window, args = {}, value) {
|
|
if (args.help) {
|
|
const message = getFormattedHelpData();
|
|
// Wrap message in an array so that the return value is consistant with save
|
|
return [message];
|
|
}
|
|
simulateCameraShutter(window);
|
|
return save(args, value);
|
|
}
|
|
|
|
/**
|
|
* This function is called to simulate camera effects
|
|
*
|
|
* @param object document
|
|
* The Debugger Client document.
|
|
*/
|
|
function simulateCameraShutter(window) {
|
|
if (Services.prefs.getBoolPref("devtools.screenshot.audio.enabled")) {
|
|
const audioCamera = new window.Audio("resource://devtools/client/themes/audio/shutter.wav");
|
|
audioCamera.play();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save the captured screenshot to one of several destinations.
|
|
*
|
|
* @param object args
|
|
* The original args with which the screenshot was called.
|
|
*
|
|
* @param object image
|
|
* The image object that was sent from the server.
|
|
*
|
|
* @return string[]
|
|
* Response messages from processing the screenshot.
|
|
*/
|
|
async function save(args, image) {
|
|
const fileNeeded = args.filename ||
|
|
!args.clipboard || args.file;
|
|
const results = [];
|
|
|
|
if (args.clipboard) {
|
|
const result = saveToClipboard(image.data);
|
|
results.push(result);
|
|
}
|
|
|
|
if (fileNeeded) {
|
|
const result = await saveToFile(image);
|
|
results.push(result);
|
|
}
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* Save the image data to the clipboard. This returns a promise, so it can
|
|
* be treated exactly like file processing.
|
|
*
|
|
* @param string base64URI
|
|
* The image data encoded in a base64 URI that was sent from the server.
|
|
*
|
|
* @return string
|
|
* Response message from processing the screenshot.
|
|
*/
|
|
function saveToClipboard(base64URI) {
|
|
try {
|
|
const imageTools = Cc["@mozilla.org/image/tools;1"]
|
|
.getService(Ci.imgITools);
|
|
|
|
const base64Data = base64URI.replace("data:image/png;base64,", "");
|
|
|
|
const image = atob(base64Data);
|
|
const img = imageTools.decodeImageFromBuffer(image, image.length, "image/png");
|
|
|
|
const transferable = Cc["@mozilla.org/widget/transferable;1"]
|
|
.createInstance(Ci.nsITransferable);
|
|
transferable.init(null);
|
|
transferable.addDataFlavor("image/png");
|
|
transferable.setTransferData("image/png", img, -1);
|
|
|
|
Services.clipboard.setData(transferable, null, Services.clipboard.kGlobalClipboard);
|
|
return L10N.getStr("screenshotCopied");
|
|
} catch (ex) {
|
|
console.error(ex);
|
|
return L10N.getStr("screenshotErrorCopying");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save the screenshot data to disk, returning a promise which is resolved on
|
|
* completion.
|
|
*
|
|
* @param object image
|
|
* The image object that was sent from the server.
|
|
*
|
|
* @return string
|
|
* Response message from processing the screenshot.
|
|
*/
|
|
async function saveToFile(image) {
|
|
let filename = image.filename;
|
|
|
|
// Check there is a .png extension to filename
|
|
if (!filename.match(/.png$/i)) {
|
|
filename += ".png";
|
|
}
|
|
|
|
const downloadsDir = await Downloads.getPreferredDownloadsDirectory();
|
|
const downloadsDirExists = await OS.File.exists(downloadsDir);
|
|
if (downloadsDirExists) {
|
|
// If filename is absolute, it will override the downloads directory and
|
|
// still be applied as expected.
|
|
filename = OS.Path.join(downloadsDir, filename);
|
|
}
|
|
|
|
const sourceURI = Services.io.newURI(image.data);
|
|
const targetFile = new FileUtils.File(filename);
|
|
|
|
// Create download and track its progress.
|
|
try {
|
|
const download = await Downloads.createDownload({
|
|
source: sourceURI,
|
|
target: targetFile,
|
|
});
|
|
const list = await Downloads.getList(Downloads.ALL);
|
|
// add the download to the download list in the Downloads list in the Browser UI
|
|
list.add(download);
|
|
// Await successful completion of the save via the download manager
|
|
await download.start();
|
|
return L10N.getFormatStr("screenshotSavedToFile", filename);
|
|
} catch (ex) {
|
|
console.error(ex);
|
|
return L10N.getFormatStr("screenshotErrorSavingToFile", filename);
|
|
}
|
|
}
|
|
|
|
module.exports = saveScreenshot;
|