fune/browser/extensions/screenshots/selector/shooter.js
Emma Malysz 4a35b15f5d Bug 1683194: ignore scroll coordinates when taking screenshots r=sfoster
We will create the image using the selected position, and the canvas
will use the image coordinates, which have not been adjusted
for scrolling

Differential Revision: https://phabricator.services.mozilla.com/D100291
2021-01-05 01:48:43 +00:00

147 lines
4.5 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/. */
/* globals global, documentMetadata, util, uicontrol, ui, catcher */
/* globals buildSettings, domainFromUrl, randomString, shot, blobConverters */
"use strict";
this.shooter = (function() { // eslint-disable-line no-unused-vars
const exports = {};
const { AbstractShot } = shot;
const RANDOM_STRING_LENGTH = 16;
const MAX_CANVAS_DIMENSION = 32767;
let backend;
let shotObject;
const callBackground = global.callBackground;
const clipboard = global.clipboard;
function regexpEscape(str) {
// http://stackoverflow.com/questions/3115150/how-to-escape-regular-expression-special-characters-using-javascript
return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}
function sanitizeError(data) {
const href = new RegExp(regexpEscape(window.location.href), "g");
const origin = new RegExp(`${regexpEscape(window.location.origin)}[^ \t\n\r",>]*`, "g");
const json = JSON.stringify(data)
.replace(href, "REDACTED_HREF")
.replace(origin, "REDACTED_URL");
const result = JSON.parse(json);
return result;
}
catcher.registerHandler((errorObj) => {
callBackground("reportError", sanitizeError(errorObj));
});
function hideUIFrame() {
ui.iframe.hide();
return Promise.resolve(null);
}
function screenshotPage(dataUrl, selectedPos, type, screenshotTaskFn) {
let promise = Promise.resolve(dataUrl);
if (!dataUrl) {
let isFullPage = type === "fullPage" || type == "fullPageTruncated";
promise = callBackground(
"screenshotPage",
selectedPos.toJSON(),
isFullPage,
window.devicePixelRatio);
}
catcher.watchPromise(promise.then((dataUrl) => {
screenshotTaskFn(dataUrl);
}));
}
exports.downloadShot = function(selectedPos, previewDataUrl, type) {
const shotPromise = previewDataUrl ? Promise.resolve(previewDataUrl) : hideUIFrame();
catcher.watchPromise(shotPromise.then(dataUrl => {
screenshotPage(dataUrl, selectedPos, type, url => {
let type = blobConverters.getTypeFromDataUrl(url);
type = type ? type.split("/", 2)[1] : null;
shotObject.delAllClips();
shotObject.addClip({
createdDate: Date.now(),
image: {
url,
type,
location: selectedPos,
},
});
ui.triggerDownload(url, shotObject.filename);
uicontrol.deactivate();
});
}));
};
exports.preview = function(selectedPos, type) {
catcher.watchPromise(hideUIFrame().then(dataUrl => {
screenshotPage(dataUrl, selectedPos, type, url => {
ui.iframe.usePreview();
ui.Preview.display(url);
});
}));
};
let copyInProgress = null;
exports.copyShot = function(selectedPos, previewDataUrl, type) {
// This is pretty slow. We'll ignore additional user triggered copy events
// while it is in progress.
if (copyInProgress) {
return;
}
// A max of five seconds in case some error occurs.
copyInProgress = setTimeout(() => {
copyInProgress = null;
}, 5000);
const unsetCopyInProgress = () => {
if (copyInProgress) {
clearTimeout(copyInProgress);
copyInProgress = null;
}
};
const shotPromise = previewDataUrl ? Promise.resolve(previewDataUrl) : hideUIFrame();
catcher.watchPromise(shotPromise.then(dataUrl => {
screenshotPage(dataUrl, selectedPos, type, url => {
const blob = blobConverters.dataUrlToBlob(url);
catcher.watchPromise(callBackground("copyShotToClipboard", blob).then(() => {
uicontrol.deactivate();
unsetCopyInProgress();
}, unsetCopyInProgress));
});
}));
};
exports.sendEvent = function(...args) {
const maybeOptions = args[args.length - 1];
if (typeof maybeOptions === "object") {
maybeOptions.incognito = browser.extension.inIncognitoContext;
} else {
args.push({incognito: browser.extension.inIncognitoContext});
}
callBackground("sendEvent", ...args);
};
catcher.watchFunction(() => {
shotObject = new AbstractShot(
backend,
randomString(RANDOM_STRING_LENGTH) + "/" + domainFromUrl(location),
{
origin: shot.originFromUrl(location.href),
}
);
shotObject.update(documentMetadata());
})();
return exports;
})();
null;