524 lines
18 KiB
JavaScript
524 lines
18 KiB
JavaScript
|
/*
|
||
|
* Copyright (c) 2024 lax1dude. All Rights Reserved.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
const platfWebViewName = "platformWebView";
|
||
|
|
||
|
function initializePlatfWebView(webViewImports) {
|
||
|
|
||
|
const BEGIN_SHOWING_DIRECT = 0;
|
||
|
const BEGIN_SHOWING_ENABLE_JAVASCRIPT = 1;
|
||
|
const BEGIN_SHOWING_CONTENT_BLOCKED = 2;
|
||
|
|
||
|
const EVENT_WEBVIEW_CHANNEL = 0;
|
||
|
const EVENT_WEBVIEW_MESSAGE = 1;
|
||
|
const EVENT_WEBVIEW_PERMISSION_ALLOW = 2;
|
||
|
const EVENT_WEBVIEW_PERMISSION_BLOCK = 3;
|
||
|
const EVENT_WEBVIEW_PERMISSION_CLEAR = 4;
|
||
|
|
||
|
const EVENT_CHANNEL_OPEN = 0;
|
||
|
const EVENT_CHANNEL_CLOSE = 1;
|
||
|
|
||
|
const EVENT_MESSAGE_STRING = 0;
|
||
|
const EVENT_MESSAGE_BINARY = 1;
|
||
|
|
||
|
const utf8Decoder = new TextDecoder("utf-8");
|
||
|
|
||
|
var supported = false;
|
||
|
var cspSupport = false;
|
||
|
var supportForce = runtimeOpts.forceWebViewSupport;
|
||
|
var enableCSP = runtimeOpts.enableWebViewCSP;
|
||
|
if(supportForce) {
|
||
|
supported = true;
|
||
|
cspSupport = true;
|
||
|
}else {
|
||
|
supported = false;
|
||
|
cspSupport = false;
|
||
|
try {
|
||
|
var tmp = /** @type {HTMLIFrameElement} */ (document.createElement("iframe"));
|
||
|
supported = tmp != null && (typeof tmp.allow === "string") && (typeof tmp.sandbox === "object");
|
||
|
cspSupport = enableCSP && supported && (typeof tmp.csp === "string");
|
||
|
}catch(ex) {
|
||
|
eagError("Error checking iframe support");
|
||
|
eagError(ex);
|
||
|
}
|
||
|
}
|
||
|
if(!supported) {
|
||
|
eagError("This browser does not meet the safety requirements for webview support, this feature will be disabled");
|
||
|
}else if(!cspSupport && enableCSP) {
|
||
|
eagWarn("This browser does not support CSP attribute on iframes! (try Chrome)");
|
||
|
}
|
||
|
|
||
|
const requireSSL = location.protocol && "https:" === location.protocol.toLowerCase();
|
||
|
|
||
|
var webviewResetSerial = 0;
|
||
|
|
||
|
/** @type {HTMLElement} */
|
||
|
var currentIFrameContainer = null;
|
||
|
|
||
|
/** @type {HTMLElement} */
|
||
|
var currentAllowJavaScript = null;
|
||
|
|
||
|
/** @type {HTMLIFrameElement} */
|
||
|
var currentIFrame = null;
|
||
|
|
||
|
/** @type {function(MessageEvent)|null} */
|
||
|
var currentMessageHandler = null;
|
||
|
|
||
|
window.addEventListener("message", /** @type {function(Event)} */ (function(/** MessageEvent */ evt) {
|
||
|
if(currentMessageHandler && evt.source !== window) {
|
||
|
currentMessageHandler(evt);
|
||
|
}
|
||
|
}));
|
||
|
|
||
|
/**
|
||
|
* @return {boolean}
|
||
|
*/
|
||
|
webViewImports["checkSupported"] = function() {
|
||
|
return supported;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @return {boolean}
|
||
|
*/
|
||
|
webViewImports["checkCSPSupported"] = function() {
|
||
|
return cspSupport;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param {string} ch
|
||
|
* @param {string} str
|
||
|
*/
|
||
|
webViewImports["sendStringMessage"] = function(ch, str) {
|
||
|
try {
|
||
|
var w;
|
||
|
if(currentIFrame != null && (w = currentIFrame.contentWindow) != null) {
|
||
|
w.postMessage({
|
||
|
"ver": 1,
|
||
|
"channel": ch,
|
||
|
"type": "string",
|
||
|
"data": str
|
||
|
}, "*");
|
||
|
}else {
|
||
|
eagError("Server tried to send the WebView a message, but the message channel is not open!");
|
||
|
}
|
||
|
}catch(/** Error */ ex) {
|
||
|
eagStackTrace(ERROR, "Failed to send string message to WebView!", ex);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param {string} ch
|
||
|
* @param {Uint8Array} bin
|
||
|
*/
|
||
|
webViewImports["sendBinaryMessage"] = function(ch, bin) {
|
||
|
try {
|
||
|
var w;
|
||
|
if(currentIFrame != null && (w = currentIFrame.contentWindow) != null) {
|
||
|
const copiedArray = new Uint8Array(bin.length);
|
||
|
copiedArray.set(bin, 0);
|
||
|
w.postMessage({
|
||
|
"ver": 1,
|
||
|
"channel": ch,
|
||
|
"type": "binary",
|
||
|
"data": copiedArray.buffer
|
||
|
}, "*");
|
||
|
}else {
|
||
|
eagError("Server tried to send the WebView a message, but the message channel is not open!");
|
||
|
}
|
||
|
}catch(/** Error */ ex) {
|
||
|
eagStackTrace(ERROR, "Failed to send string message to WebView!", ex);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param {number} state
|
||
|
* @param {Object} options
|
||
|
* @param {number} x
|
||
|
* @param {number} y
|
||
|
* @param {number} w
|
||
|
* @param {number} h
|
||
|
*/
|
||
|
webViewImports["beginShowing"] = function(state, options, x, y, w, h) {
|
||
|
if(!supported) {
|
||
|
return;
|
||
|
}
|
||
|
try {
|
||
|
setupShowing(x, y, w, h);
|
||
|
switch(state) {
|
||
|
case BEGIN_SHOWING_DIRECT:
|
||
|
beginShowingDirect(options);
|
||
|
break;
|
||
|
case BEGIN_SHOWING_ENABLE_JAVASCRIPT:
|
||
|
if(options["contentMode"] === 1) {
|
||
|
const copiedBlob = new Uint8Array(options["blob"].length);
|
||
|
copiedBlob.set(options["blob"], 0);
|
||
|
options["blob"] = copiedBlob;
|
||
|
}
|
||
|
beginShowingEnableJavaScript(options);
|
||
|
break;
|
||
|
case BEGIN_SHOWING_CONTENT_BLOCKED:
|
||
|
if(options["contentMode"] === 1) {
|
||
|
const copiedBlob = new Uint8Array(options["blob"].length);
|
||
|
copiedBlob.set(options["blob"], 0);
|
||
|
options["blob"] = copiedBlob;
|
||
|
}
|
||
|
beginShowingContentBlocked(options);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}catch(/** Error */ ex) {
|
||
|
eagStackTrace(ERROR, "Failed to begin showing WebView!", ex);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* @param {number} x
|
||
|
* @param {number} y
|
||
|
* @param {number} w
|
||
|
* @param {number} h
|
||
|
*/
|
||
|
function setupShowing(x, y, w, h) {
|
||
|
if(currentIFrameContainer !== null) {
|
||
|
endShowingImpl();
|
||
|
}
|
||
|
currentIFrameContainer = /** @type {HTMLElement} */ (document.createElement("div"));
|
||
|
currentIFrameContainer.classList.add("_eaglercraftX_webview_container_element");
|
||
|
currentIFrameContainer.style.border = "5px solid #333333";
|
||
|
currentIFrameContainer.style.zIndex = "11";
|
||
|
currentIFrameContainer.style.position = "absolute";
|
||
|
currentIFrameContainer.style.backgroundColor = "#DDDDDD";
|
||
|
currentIFrameContainer.style.fontFamily = "sans-serif";
|
||
|
resizeImpl(x, y, w, h);
|
||
|
parentElement.appendChild(currentIFrameContainer);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {HTMLIFrameElement} iframeElement
|
||
|
* @param {string} str
|
||
|
*/
|
||
|
function setAllowSafe(iframeElement, str) {
|
||
|
iframeElement.allow = str;
|
||
|
return iframeElement.allow === str;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {HTMLIFrameElement} iframeElement
|
||
|
* @param {Array<string>} args
|
||
|
*/
|
||
|
function setSandboxSafe(iframeElement, args) {
|
||
|
const theSandbox = iframeElement.sandbox;
|
||
|
for(var i = 0; i < args.length; ++i) {
|
||
|
theSandbox.add(args[i]);
|
||
|
}
|
||
|
for(var i = 0; i < args.length; ++i) {
|
||
|
if(!theSandbox.contains(args[i])) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
for(var i = 0; i < theSandbox.length; ++i) {
|
||
|
if(!args.find(itm => itm === theSandbox[i])) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function beginShowingDirect(options) {
|
||
|
if(!supportForce) {
|
||
|
currentIFrame = /** @type {HTMLIFrameElement} */ (document.createElement("iframe"));
|
||
|
currentIFrame.referrerPolicy = "strict-origin";
|
||
|
const sandboxArgs = [ "allow-downloads" ];
|
||
|
if(options["scriptEnabled"]) {
|
||
|
sandboxArgs.push("allow-scripts");
|
||
|
sandboxArgs.push("allow-pointer-lock");
|
||
|
}
|
||
|
if(!setAllowSafe(currentIFrame, "") || !setSandboxSafe(currentIFrame, sandboxArgs)) {
|
||
|
eagError("Caught safety exception while opening webview!");
|
||
|
if(currentIFrame !== null) {
|
||
|
currentIFrame.remove();
|
||
|
currentIFrame = null;
|
||
|
}
|
||
|
eagError("Things you can try:");
|
||
|
eagError("1. Set window.eaglercraftXOpts.forceWebViewSupport to true");
|
||
|
eagError("2. Set window.eaglercraftXOpts.enableWebViewCSP to false");
|
||
|
eagError("(these settings may compromise security)");
|
||
|
beginShowingSafetyError();
|
||
|
return;
|
||
|
}
|
||
|
}else {
|
||
|
currentIFrame = /** @type {HTMLIFrameElement} */ (document.createElement("iframe"));
|
||
|
currentIFrame.allow = "";
|
||
|
currentIFrame.referrerPolicy = "strict-origin";
|
||
|
currentIFrame.sandbox.add("allow-downloads");
|
||
|
if(options["scriptEnabled"]) {
|
||
|
currentIFrame.sandbox.add("allow-scripts");
|
||
|
currentIFrame.sandbox.add("allow-pointer-lock");
|
||
|
}
|
||
|
}
|
||
|
currentIFrame.credentialless = true;
|
||
|
currentIFrame.loading = "lazy";
|
||
|
var cspWarn = false;
|
||
|
if(options["contentMode"] === 1) {
|
||
|
if(enableCSP && cspSupport) {
|
||
|
if(typeof currentIFrame.csp === "string") {
|
||
|
var csp = "default-src 'none';";
|
||
|
var protos = options["strictCSPEnable"] ? "" : (requireSSL ? " https:" : " http: https:");
|
||
|
if(options["scriptEnabled"]) {
|
||
|
csp += (" script-src 'unsafe-eval' 'unsafe-inline' data: blob:" + protos + ";");
|
||
|
csp += (" style-src 'unsafe-eval' 'unsafe-inline' data: blob:" + protos + ";");
|
||
|
csp += (" img-src data: blob:" + protos + ";");
|
||
|
csp += (" font-src data: blob:" + protos + ";");
|
||
|
csp += (" child-src data: blob:" + protos + ";");
|
||
|
csp += (" frame-src data: blob:;");
|
||
|
csp += (" media-src data: mediastream: blob:" + protos + ";");
|
||
|
csp += (" connect-src data: blob:" + protos + ";");
|
||
|
csp += (" worker-src data: blob:" + protos + ";");
|
||
|
}else {
|
||
|
csp += (" style-src data: 'unsafe-inline'" + protos + ";");
|
||
|
csp += (" img-src data:" + protos + ";");
|
||
|
csp += (" font-src data:" + protos + ";");
|
||
|
csp += (" media-src data:" + protos + ";");
|
||
|
}
|
||
|
currentIFrame.csp = csp;
|
||
|
}else {
|
||
|
eagWarn("This browser does not support CSP attribute on iframes! (try Chrome)");
|
||
|
cspWarn = true;
|
||
|
}
|
||
|
}else {
|
||
|
cspWarn = true;
|
||
|
}
|
||
|
if(cspWarn && options["strictCSPEnable"]) {
|
||
|
eagWarn("Strict CSP was requested for this webview, but that feature is not available!");
|
||
|
}
|
||
|
}else {
|
||
|
cspWarn = true;
|
||
|
}
|
||
|
currentIFrame.style.border = "none";
|
||
|
currentIFrame.style.backgroundColor = "white";
|
||
|
currentIFrame.style.width = "100%";
|
||
|
currentIFrame.style.height = "100%";
|
||
|
currentIFrame.classList.add("_eaglercraftX_webview_iframe_element");
|
||
|
currentIFrameContainer.appendChild(currentIFrame);
|
||
|
if(options["contentMode"] === 1) {
|
||
|
const decodedText = utf8Decoder.decode(options["blob"]);
|
||
|
options["blob"] = null;
|
||
|
currentIFrame.srcdoc = decodedText;
|
||
|
}else {
|
||
|
currentIFrame.src = options["uri"];
|
||
|
}
|
||
|
const resetSer = webviewResetSerial;
|
||
|
const curIFrame = currentIFrame;
|
||
|
let focusTracker = false;
|
||
|
currentIFrame.addEventListener("mouseover", function(/** Event */ evt) {
|
||
|
if(resetSer === webviewResetSerial && curIFrame === currentIFrame) {
|
||
|
if(!focusTracker) {
|
||
|
focusTracker = true;
|
||
|
currentIFrame.contentWindow.focus();
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
currentIFrame.addEventListener("mouseout", function(/** Event */ evt) {
|
||
|
if(resetSer === webviewResetSerial && curIFrame === currentIFrame) {
|
||
|
if(focusTracker) {
|
||
|
focusTracker = false;
|
||
|
window.focus();
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
if(options["scriptEnabled"] && options["serverMessageAPIEnabled"]) {
|
||
|
currentMessageHandler = function(/** MessageEvent */ evt) {
|
||
|
if(resetSer === webviewResetSerial && curIFrame === currentIFrame && evt.source === curIFrame.contentWindow) {
|
||
|
/** @type {Object} */
|
||
|
const obj = evt.data;
|
||
|
if((typeof obj === "object") && (obj["ver"] === 1) && ((typeof obj["channel"] === "string") && obj["channel"]["length"] > 0)) {
|
||
|
if(typeof obj["open"] === "boolean") {
|
||
|
pushEvent(EVENT_TYPE_WEBVIEW, EVENT_WEBVIEW_CHANNEL, {
|
||
|
"eventType": (obj["open"] ? EVENT_CHANNEL_OPEN : EVENT_CHANNEL_CLOSE),
|
||
|
"channelName": obj["channel"]
|
||
|
});
|
||
|
return;
|
||
|
}else if(typeof obj["data"] === "string") {
|
||
|
pushEvent(EVENT_TYPE_WEBVIEW, EVENT_WEBVIEW_MESSAGE, {
|
||
|
"eventType": EVENT_MESSAGE_STRING,
|
||
|
"channelName": obj["channel"],
|
||
|
"eventData": obj["data"]
|
||
|
});
|
||
|
return;
|
||
|
}else if(obj["data"] instanceof ArrayBuffer) {
|
||
|
pushEvent(EVENT_TYPE_WEBVIEW, EVENT_WEBVIEW_MESSAGE, {
|
||
|
"eventType": EVENT_MESSAGE_BINARY,
|
||
|
"channelName": obj["channel"],
|
||
|
"eventData": obj["data"]
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
eagWarn("WebView sent an invalid message!");
|
||
|
}else {
|
||
|
eagWarn("Recieved message from on dead IFrame handler: (#{}) {}", resetSer, curIFrame.src);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
eagInfo("WebView is loading: \"{}\"", options["contentMode"] === 1 ? "about:srcdoc" : currentIFrame.src);
|
||
|
eagInfo("JavaScript: {}, Strict CSP: {}, Message API: {}", options["scriptEnabled"],
|
||
|
options["strictCSPEnable"] && !cspWarn, options["serverMessageAPIEnabled"]);
|
||
|
}
|
||
|
|
||
|
function beginShowingEnableJSSetup() {
|
||
|
if(currentAllowJavaScript !== null) {
|
||
|
++webviewResetSerial;
|
||
|
currentAllowJavaScript.remove();
|
||
|
currentAllowJavaScript = null;
|
||
|
}
|
||
|
currentAllowJavaScript = /** @type {HTMLElement} */ (document.createElement("div"));
|
||
|
currentAllowJavaScript.style.backgroundColor = "white";
|
||
|
currentAllowJavaScript.style.width = "100%";
|
||
|
currentAllowJavaScript.style.height = "100%";
|
||
|
currentAllowJavaScript.classList.add("_eaglercraftX_webview_permission_screen");
|
||
|
currentIFrameContainer.appendChild(currentAllowJavaScript);
|
||
|
}
|
||
|
|
||
|
function beginShowingEnableJavaScript(options) {
|
||
|
beginShowingEnableJSSetup();
|
||
|
var strictCSPMarkup;
|
||
|
if(options["contentMode"] !== 1) {
|
||
|
strictCSPMarkup = "<span style=\"color:red;\">Impossible</span>";
|
||
|
}else if(!cspSupport || !enableCSP) {
|
||
|
strictCSPMarkup = "<span style=\"color:red;\">Unsupported</span>";
|
||
|
}else if(options["strictCSPEnable"]) {
|
||
|
strictCSPMarkup = "<span style=\"color:green;\">Enabled</span>";
|
||
|
}else {
|
||
|
strictCSPMarkup = "<span style=\"color:red;\">Disabled</span>";
|
||
|
}
|
||
|
var messageAPIMarkup;
|
||
|
if(options["serverMessageAPIEnabled"]) {
|
||
|
messageAPIMarkup = "<span style=\"color:red;\">Enabled</span>";
|
||
|
}else {
|
||
|
messageAPIMarkup = "<span style=\"color:green;\">Disabled</span>";
|
||
|
}
|
||
|
currentAllowJavaScript.innerHTML =
|
||
|
"<div style=\"padding-top:13vh;\"><div style=\"margin:auto;max-width:450px;border:6px double black;text-align:center;padding:20px;\">"
|
||
|
+ "<h2><img width=\"32\" height=\"32\" style=\"vertical-align:middle;\" src=\"" + faviconURL + "\"> Allow JavaScript</h2>"
|
||
|
+ "<p style=\"font-family:monospace;text-decoration:underline;word-wrap:break-word;\" class=\"_eaglercraftX_permission_target_url\"></p>"
|
||
|
+ "<h4 style=\"line-height:1.4em;\">Strict CSP: " + strictCSPMarkup + " | "
|
||
|
+ "Message API: " + messageAPIMarkup + "</h4>"
|
||
|
+ "<p><input class=\"_eaglercraftX_remember_javascript\" type=\"checkbox\" checked> Remember my choice</p>"
|
||
|
+ "<p><button style=\"font-size:1.5em;\" class=\"_eaglercraftX_allow_javascript\">Allow</button> "
|
||
|
+ "<button style=\"font-size:1.5em;\" class=\"_eaglercraftX_block_javascript\">Block</button></p></div></div>";
|
||
|
const serial = webviewResetSerial;
|
||
|
if(options["contentMode"] !== 1) {
|
||
|
const urlStr = options["url"];
|
||
|
currentAllowJavaScript.querySelector("._eaglercraftX_permission_target_url").innerText = urlStr.length() > 255 ? (urlStr.substring(0, 253) + "...") : urlStr;
|
||
|
}
|
||
|
currentAllowJavaScript.querySelector("._eaglercraftX_allow_javascript").addEventListener("click", function(/** Event */ evt) {
|
||
|
if(webviewResetSerial === serial && currentAllowJavaScript !== null) {
|
||
|
const chkbox = currentAllowJavaScript.querySelector("._eaglercraftX_remember_javascript");
|
||
|
if(chkbox !== null && chkbox.checked) {
|
||
|
pushEvent(EVENT_TYPE_WEBVIEW, EVENT_WEBVIEW_PERMISSION_ALLOW, null);
|
||
|
}
|
||
|
currentAllowJavaScript.remove();
|
||
|
currentAllowJavaScript = null;
|
||
|
++webviewResetSerial;
|
||
|
beginShowingDirect(options);
|
||
|
}
|
||
|
});
|
||
|
currentAllowJavaScript.querySelector("._eaglercraftX_block_javascript").addEventListener("click", function(/** Event */ evt) {
|
||
|
if(webviewResetSerial === serial && currentAllowJavaScript !== null) {
|
||
|
const chkbox = currentAllowJavaScript.querySelector("._eaglercraftX_remember_javascript");
|
||
|
if(chkbox !== null && chkbox.checked) {
|
||
|
pushEvent(EVENT_TYPE_WEBVIEW, EVENT_WEBVIEW_PERMISSION_BLOCK, null);
|
||
|
}
|
||
|
beginShowingContentBlocked(options);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function beginShowingContentBlocked(options) {
|
||
|
beginShowingEnableJSSetup();
|
||
|
currentAllowJavaScript.innerHTML =
|
||
|
"<div style=\"padding-top:13vh;\"><h1 style=\"text-align:center;\">"
|
||
|
+ "<img width=\"48\" height=\"48\" style=\"vertical-align:middle;\" src=\"" + faviconURL + "\"> Content Blocked</h1>"
|
||
|
+ "<h4 style=\"text-align:center;\">You chose to block JavaScript execution for this embed</h4>"
|
||
|
+ "<p style=\"text-align:center;\"><button style=\"font-size:1.0em;\" class=\"_eaglercraftX_re_evaluate_javascript\">Re-evaluate</button></p></div>";
|
||
|
const serial = webviewResetSerial;
|
||
|
currentAllowJavaScript.querySelector("._eaglercraftX_re_evaluate_javascript").addEventListener("click", function(/** Event */ evt) {
|
||
|
if(webviewResetSerial === serial && currentAllowJavaScript !== null) {
|
||
|
pushEvent(EVENT_TYPE_WEBVIEW, EVENT_WEBVIEW_PERMISSION_CLEAR, null);
|
||
|
beginShowingEnableJavaScript(options);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function beginShowingSafetyError() {
|
||
|
beginShowingEnableJSSetup();
|
||
|
currentAllowJavaScript.innerHTML =
|
||
|
"<div style=\"padding-top:13vh;\"><h1 style=\"text-align:center;\">"
|
||
|
+ "<img width=\"48\" height=\"48\" style=\"vertical-align:middle;\" src=\"" + faviconURL + "\"> IFrame Safety Error</h1>"
|
||
|
+ "<h4 style=\"text-align:center;\">The content cannot be displayed safely!</h4>"
|
||
|
+ "<h4 style=\"text-align:center;\">Check console for more details</h4></div>";
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {number} x
|
||
|
* @param {number} y
|
||
|
* @param {number} w
|
||
|
* @param {number} h
|
||
|
*/
|
||
|
function resizeImpl(x, y, w, h) {
|
||
|
if(currentIFrameContainer) {
|
||
|
const s = window.devicePixelRatio;
|
||
|
currentIFrameContainer.style.top = "" + (y / s) + "px";
|
||
|
currentIFrameContainer.style.left = "" + (x / s) + "px";
|
||
|
currentIFrameContainer.style.width = "" + ((w / s) - 10) + "px";
|
||
|
currentIFrameContainer.style.height = "" + ((h / s) - 10) + "px";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function endShowingImpl() {
|
||
|
++webviewResetSerial;
|
||
|
if(currentIFrame) {
|
||
|
currentIFrame.remove();
|
||
|
currentIFrame = null;
|
||
|
}
|
||
|
currentMessageHandler = null;
|
||
|
if(currentAllowJavaScript) {
|
||
|
currentAllowJavaScript.remove();
|
||
|
currentAllowJavaScript = null;
|
||
|
}
|
||
|
if(currentIFrameContainer) {
|
||
|
currentIFrameContainer.remove();
|
||
|
currentIFrameContainer = null;
|
||
|
}
|
||
|
window.focus();
|
||
|
}
|
||
|
|
||
|
webViewImports["resize"] = resizeImpl;
|
||
|
|
||
|
webViewImports["endShowing"] = endShowingImpl;
|
||
|
|
||
|
}
|
||
|
|
||
|
function initializeNoPlatfWebView(webViewImports) {
|
||
|
setUnsupportedFunc(webViewImports, platfWebViewName, "checkSupported");
|
||
|
setUnsupportedFunc(webViewImports, platfWebViewName, "checkCSPSupported");
|
||
|
setUnsupportedFunc(webViewImports, platfWebViewName, "sendStringMessage");
|
||
|
setUnsupportedFunc(webViewImports, platfWebViewName, "sendBinaryMessage");
|
||
|
setUnsupportedFunc(webViewImports, platfWebViewName, "beginShowing");
|
||
|
setUnsupportedFunc(webViewImports, platfWebViewName, "resize");
|
||
|
setUnsupportedFunc(webViewImports, platfWebViewName, "endShowing");
|
||
|
}
|