OpenAsar/core/src/app/popoutWindows.js

153 lines
4.3 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.closePopouts = closePopouts;
exports.getWindow = getWindow;
exports.hasInit = void 0;
exports.init = init;
exports.openOrFocusWindow = openOrFocusWindow;
exports.setupPopout = setupPopout;
var _electron = require("electron");
var _securityUtils = require("../common/securityUtils");
var _appFeatures = require("./appFeatures");
const ALLOWED_FEATURES = ['width', 'height', 'left', 'top', 'resizable', 'movable', 'alwaysOnTop', 'frame', 'transparent', 'hasShadow', 'closable', 'skipTaskbar', 'backgroundColor', 'menubar', 'toolbar', 'location', 'directories', 'titleBarStyle'];
const MIN_POPOUT_WIDTH = 320;
const MIN_POPOUT_HEIGHT = 180;
const DEFAULT_POPOUT_OPTIONS = {
title: 'Discord Popout',
backgroundColor: '#2f3136',
minWidth: MIN_POPOUT_WIDTH,
minHeight: MIN_POPOUT_HEIGHT,
transparent: false,
frame: process.platform === 'linux',
resizable: true,
show: true,
titleBarStyle: process.platform === 'darwin' ? 'hidden' : undefined,
trafficLightPosition: process.platform === 'darwin' ? {
x: 10,
y: 3
} : undefined,
webPreferences: {
nodeIntegration: false,
nativeWindowOpen: true,
enableRemoteModule: false,
contextIsolation: true
}
};
const features = (0, _appFeatures.getFeatures)();
let hasInit = false;
exports.hasInit = hasInit;
let popoutWindows = {};
function init() {
if (hasInit) {
console.warn('popoutWindows: Has already init! Cancelling init.');
return;
}
exports.hasInit = hasInit = true;
features.declareSupported('popout_windows');
}
function focusWindow(window) {
if (window == null) return;
// The focus call is not always respected.
// This uses a hack defined in https://github.com/electron/electron/issues/2867
window.setAlwaysOnTop(true);
window.focus();
window.setAlwaysOnTop(false);
}
function getWindow(key) {
return popoutWindows[key];
}
function parseFeatureValue(feature) {
if (feature === 'yes') {
return true;
} else if (feature === 'no') {
return false;
}
const parsedNumber = Number.parseInt(feature);
if (!Number.isNaN(parsedNumber)) {
return parsedNumber;
}
return feature;
}
function filterWindowFeatures(hasKey, getKey) {
return ALLOWED_FEATURES.reduce((acc, curr) => {
if (hasKey(curr)) {
return {
...acc,
[curr]: getKey(curr)
};
}
return acc;
}, {});
}
function parseWindowFeatures(features) {
const keyValuesParsed = features.split(',');
const parsedFeatures = keyValuesParsed.reduce((acc, curr) => {
const [key, value] = curr.split('=');
return {
...acc,
[key]: parseFeatureValue(value)
};
}, {});
return filterWindowFeatures(key => parsedFeatures.hasOwnProperty(key), key => parsedFeatures[key]);
}
function openOrFocusWindow(windowURL, key, features) {
const existingWindow = popoutWindows[key];
if (existingWindow != null) {
focusWindow(existingWindow);
return {
action: 'deny'
};
}
return {
action: 'allow',
overrideBrowserWindowOptions: {
...DEFAULT_POPOUT_OPTIONS,
...parseWindowFeatures(features)
}
};
}
function setupPopout(popoutWindow, key, options, webappEndpoint) {
popoutWindow.windowKey = key;
popoutWindows[popoutWindow.windowKey] = popoutWindow;
/**
* Do not allow navigation to arbitrary domains.
*/
popoutWindow.webContents.on('will-navigate', (evt, url) => {
if (!(0, _securityUtils.checkUrlOriginMatches)(url, webappEndpoint)) {
evt.preventDefault();
}
});
/**
* Any window.open or links within the popout window should just open externally.
*/
popoutWindow.webContents.setWindowOpenHandler(({
url
}) => {
(0, _securityUtils.saferShellOpenExternal)(url);
// Even if this opens the url, we still want to deny since we want to open in the user's browser,
// not the electron app
return {
action: 'deny'
};
});
/**
* Handle events for our new window
*
* NOTE: Wanted to handle 'always-on-top-changed' and send to client but currently
* the event seems to not fire.
* */
popoutWindow.once('closed', () => {
popoutWindow.removeAllListeners();
delete popoutWindows[popoutWindow.windowKey];
});
}
function closePopouts() {
Object.values(popoutWindows).forEach(popoutWindow => popoutWindow.close());
popoutWindows = {};
}