fune/browser/components/screenshots/content/screenshots.js

232 lines
7.1 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/. */
/* eslint-env mozilla/browser-window */
"use strict";
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
Downloads: "resource://gre/modules/Downloads.jsm",
FileUtils: "resource://gre/modules/FileUtils.jsm",
});
class ScreenshotsUI extends HTMLElement {
constructor() {
super();
}
async connectedCallback() {
this.initialize();
}
initialize() {
if (this._initialized) {
return;
}
this._initialized = true;
let template = this.ownerDocument.getElementById(
"screenshots-dialog-template"
);
let templateContent = template.content;
this.appendChild(templateContent.cloneNode(true));
this._retryButton = this.querySelector(".highlight-button-retry");
this._retryButton.addEventListener("click", this);
this._cancelButton = this.querySelector(".highlight-button-cancel");
this._cancelButton.addEventListener("click", this);
this._copyButton = this.querySelector(".highlight-button-copy");
this._copyButton.addEventListener("click", this);
this._downloadButton = this.querySelector(".highlight-button-download");
this._downloadButton.addEventListener("click", this);
}
close() {
URL.revokeObjectURL(document.getElementById("placeholder-image").src);
window.close();
}
async handleEvent(event) {
if (event.type == "click" && event.currentTarget == this._cancelButton) {
this.close();
} else if (
event.type == "click" &&
event.currentTarget == this._copyButton
) {
this.saveToClipboard(
this.ownerDocument.getElementById("placeholder-image").src
);
} else if (
event.type == "click" &&
event.currentTarget == this._downloadButton
) {
await this.saveToFile(
this.ownerDocument.getElementById("placeholder-image").src
);
} else if (
event.type == "click" &&
event.currentTarget == this._retryButton
) {
Services.obs.notifyObservers(
window.parent.ownerGlobal,
"menuitem-screenshot",
"retry"
);
}
}
//Adapted from devtools/client/shared/screenshot.js
async saveToFile(src) {
let filename = this.getFilename();
// Guard against missing image data.
if (!src) {
return;
}
// Check there is a .png extension to filename
if (!filename.match(/.png$/i)) {
filename += ".png";
}
const downloadsDir = await Downloads.getPreferredDownloadsDirectory();
const downloadsDirExists = await IOUtils.exists(downloadsDir);
if (downloadsDirExists) {
// If filename is absolute, it will override the downloads directory and
// still be applied as expected.
filename = PathUtils.join(downloadsDir, filename);
}
const sourceURI = Services.io.newURI(src);
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();
// need to close after download because blob url is revoked on close
this.close();
} catch (ex) {}
}
//Adapted from devtools/client/shared/screenshot.js
saveToClipboard(src) {
try {
const imageTools = Cc["@mozilla.org/image/tools;1"].getService(
Ci.imgITools
);
var img = new Image();
img.crossOrigin = "Anonymous";
var self = this;
img.onload = function() {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
var dataURL;
canvas.height = this.naturalHeight;
canvas.width = this.naturalWidth;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL("image/png");
const base64Data = dataURL.replace("data:image/png;base64,", "");
const image = atob(base64Data);
const imgDecoded = 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", imgDecoded);
Services.clipboard.setData(
transferable,
null,
Services.clipboard.kGlobalClipboard
);
self.close();
};
img.src = src;
} catch (ex) {}
}
getFilename() {
let filenameTitle = "Dummy Page"; /* TODO: retrieve title froom image */
const date = new Date(Date.now());
// eslint-disable-next-line no-control-regex
filenameTitle = filenameTitle.replace(/[:\\<>/!@&?"*.|\x00-\x1F]/g, " ");
filenameTitle = filenameTitle.replace(/\s{1,4000}/g, " ");
const currentDateTime = new Date(
date.getTime() - date.getTimezoneOffset() * 60 * 1000
).toISOString();
const filenameDate = currentDateTime.substring(0, 10);
const filenameTime = currentDateTime.substring(11, 19).replace(/:/g, "-");
let clipFilename = `Screenshot ${filenameDate} at ${filenameTime} ${filenameTitle}`;
const clipFilenameBytesSize = clipFilename.length * 2; // JS STrings are UTF-16
if (clipFilenameBytesSize > 251) {
// 255 bytes (Usual filesystems max) - 4 for the ".png" file extension string
const excedingchars = (clipFilenameBytesSize - 246) / 2; // 251 - 5 for ellipsis "[...]"
clipFilename = clipFilename.substring(
0,
clipFilename.length - excedingchars
);
clipFilename = clipFilename + "[...]";
}
let extension = ".png";
return clipFilename + extension;
}
async takeVisibleScreenshot() {
let params = new URLSearchParams(location.search);
let browsingContextId = parseInt(params.get("browsingContextId"), 10);
let browsingContext = BrowsingContext.get(browsingContextId);
let snapshot = await browsingContext.currentWindowGlobal.drawSnapshot(
null,
1,
"rgb(255,255,255)"
);
let canvas = this.ownerDocument.createElementNS(
"http://www.w3.org/1999/xhtml",
"html:canvas"
);
let context = canvas.getContext("2d");
canvas.width = snapshot.width;
canvas.height = snapshot.height;
context.drawImage(snapshot, 0, 0);
canvas.toBlob(function(blob) {
let newImg = document.createElement("img");
let url = URL.createObjectURL(blob);
newImg.setAttribute("id", "placeholder-image");
newImg.src = url;
document.getElementById("preview-image-div").appendChild(newImg);
});
snapshot.close();
}
}
customElements.define("screenshots-ui", ScreenshotsUI);