CanvasBlocker/lib/askForPermission.js

215 lines
5.9 KiB
JavaScript
Raw Permalink Normal View History

2015-09-08 11:41:33 +02:00
/* 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/. */
(function(){
"use strict";
2019-11-28 01:26:35 +01:00
let scope;
if ((typeof exports) !== "undefined"){
scope = exports;
}
else {
2019-03-12 22:24:23 +01:00
scope = require.register("./askForPermission", {});
}
2016-02-13 12:28:36 +01:00
const {parseErrorStack} = require("./callingStack");
2015-09-08 11:41:33 +02:00
// Check canvas appearance
function canvasAppearance(window, api, context){
2019-11-28 01:26:35 +01:00
let oldBorder = false;
let canvas = false;
let inDOM = null;
if (api === "canvas" && context){
2019-11-28 01:26:35 +01:00
let nodeName;
try {
2016-08-06 19:17:36 +02:00
nodeName = context.nodeName;
}
2019-11-28 01:26:35 +01:00
catch (error){
2017-10-03 15:35:31 +02:00
nodeName = "";
}
if (nodeName === "CANVAS"){
2015-09-08 11:41:33 +02:00
canvas = context;
}
else if (
context instanceof window.CanvasRenderingContext2D ||
context instanceof window.WebGLRenderingContext
){
canvas = context.canvas;
}
}
if (canvas){
oldBorder = canvas.style.border;
canvas.style.border = "2px solid red";
inDOM = canvas.ownerDocument.contains(canvas);
}
return {
canvas: canvas,
askCategory: canvas? (inDOM? "visible": "invisible"): (api === "canvas"? "nocanvas": api),
2015-09-08 11:41:33 +02:00
get text(){
2019-11-28 01:26:35 +01:00
const text = canvas? (this.visible? "visible": "invisible"): (api === "canvas"? "nocanvas": api);
2015-09-08 11:41:33 +02:00
Object.defineProperty(this, "text", {value: text});
return text;
},
inDom: inDOM,
get visible(){
2019-11-28 01:26:35 +01:00
let visible = inDOM;
2015-09-08 11:41:33 +02:00
if (inDOM){
canvas.scrollIntoView();
2019-11-28 01:26:35 +01:00
const rect = canvas.getBoundingClientRect();
const foundEl = window.document.elementFromPoint(
rect.left + rect.width / 2,
rect.top + rect.height / 2
);
2015-09-08 11:41:33 +02:00
visible = (foundEl === canvas);
}
Object.defineProperty(this, "visible", {value: visible});
return visible;
},
reset: function(){
if (canvas){
canvas.style.border = oldBorder;
}
}
};
}
2019-11-28 01:26:35 +01:00
const modes = new WeakMap();
2016-02-13 12:28:36 +01:00
function getAskMode(window, type, _){
2019-11-28 01:26:35 +01:00
let mode = modes.get(window);
2015-09-08 11:41:33 +02:00
if (mode){
return mode[type];
}
else {
mode = {
context: {
askText: {
visible: _("askForVisiblePermission"),
invisible: _("askForInvisiblePermission"),
nocanvas: _("askForPermission"),
audio: _("askForAudioPermission"),
history: _("askForHistoryPermission"),
2018-09-09 00:16:44 +02:00
window: _("askForWindowPermission"),
domRect: _("askForDOMRectPermission"),
svg: _("askForSVGPermission"),
2015-09-08 11:41:33 +02:00
},
askStatus: {
alreadyAsked: {},
answer: {}
}
},
2017-06-25 21:14:13 +02:00
input: {
askText: {
visible: _("askForVisibleInputPermission"),
invisible: _("askForInvisibleInputPermission"),
nocanvas: _("askForInputPermission"),
audio: _("askForAudioInputPermission"),
history: _("askForHistoryInputPermission"),
2018-09-09 00:16:44 +02:00
window: _("askForWindowInputPermission"),
domRect: _("askForDOMRectInputPermission"),
svg: _("askForSVGInputPermission"),
2017-06-25 21:14:13 +02:00
},
askStatus: {
alreadyAsked: {},
answer: {}
}
},
2015-09-08 11:41:33 +02:00
readout: {
askText: {
visible: _("askForVisibleReadoutPermission"),
invisible: _("askForInvisibleReadoutPermission"),
nocanvas: _("askForReadoutPermission"),
audio: _("askForAudioReadoutPermission"),
history: _("askForHistoryReadoutPermission"),
2018-09-09 00:16:44 +02:00
window: _("askForWindowReadoutPermission"),
domRect: _("askForDOMRectReadoutPermission"),
svg: _("askForSVGReadoutPermission"),
2015-09-08 11:41:33 +02:00
},
askStatus: {
alreadyAsked: {},
answer: {}
}
}
};
modes.set(window, mode);
return mode[type];
}
}
scope.ask = function({window, type, api, canvas, errorStack}, {_, prefs}){
2019-11-28 01:26:35 +01:00
let answer;
const askMode = getAskMode(window, type, _);
const askStatus = askMode.askStatus;
const appearance = canvasAppearance(window, api, canvas);
let category = appearance.askCategory;
if (prefs("askOnlyOnce") !== "no" && askStatus.alreadyAsked[category]){
2015-09-08 11:41:33 +02:00
// already asked
appearance.reset();
return askStatus.answer[category];
2015-09-08 11:41:33 +02:00
}
else {
2018-01-04 13:36:18 +01:00
let imgContainer = null;
if (type === "readout" && prefs("showCanvasWhileAsking") && canvas){
try {
let document = window.top.document;
imgContainer = document.createElement("div");
imgContainer.style.cssText = `
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.7);
color: white;
text-align: center;
z-index: 100000000000000;
padding: 1em;`;
let heading = document.createElement("h1");
heading.textContent = "CanvasBlocker";
imgContainer.appendChild(heading);
let text = document.createElement("div");
text.style.margin = "0.5em auto";
text.textContent = _("showCanvasWhileAsking_message");
2018-01-04 13:36:18 +01:00
imgContainer.appendChild(text);
let img = document.createElement("img");
img.style.backgroundColor = "white";
img.style.border = "2px solid lightgray";
img.src = HTMLCanvasElement.prototype.toDataURL.call(canvas);
imgContainer.appendChild(img);
document.body.appendChild(imgContainer);
}
2019-11-28 01:26:35 +01:00
catch (error){
2018-01-04 13:36:18 +01:00
// unable to read the canvas
}
}
2015-09-08 11:41:33 +02:00
// asking
2019-11-28 01:26:35 +01:00
let msg = askMode.askText[appearance.text];
// visible vs invisible is only calculated here correctly
category = appearance.text;
2016-02-13 12:28:36 +01:00
if (prefs("showCallingFile")){
msg += parseErrorStack(errorStack).toString(_);
2015-09-08 11:41:33 +02:00
}
2018-01-04 13:30:48 +01:00
answer = window.top.confirm(msg)? "allow": prefs("askDenyMode");
2018-01-04 13:36:18 +01:00
if (imgContainer && imgContainer.parentNode){
imgContainer.parentNode.removeChild(imgContainer);
}
if (prefs("askOnlyOnce") === "combined"){
["context", "readout", "input"].forEach(function(type){
2019-11-28 01:26:35 +01:00
const askMode = getAskMode(window, type, _);
const askStatus = askMode.askStatus;
askStatus.alreadyAsked[category] = true;
askStatus.answer[category] = answer;
});
}
else {
askStatus.alreadyAsked[category] = true;
askStatus.answer[category] = answer;
}
2015-09-08 11:41:33 +02:00
appearance.reset();
return answer;
}
};
}());