"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.zoomIn = exports.zoomReset = exports.zoomOut = exports.withFocusedWindow = exports.setProxyRules = exports.sendParamsOnDidFinishLoad = exports.injectCSS = exports.hideWindow = exports.goToURL = exports.goForward = exports.goBack = exports.getDefaultWindowOptions = exports.getCurrentURL = exports.createNewWindow = exports.createNewTab = exports.createAboutBlankWindow = exports.clearCache = exports.clearAppData = exports.showNavigationBlockedMessage = exports.adjustWindowZoom = void 0;
const path_1 = __importDefault(require("path"));
const electron_1 = require("electron");
const helpers_1 = require("./helpers");
const log = __importStar(require("./loggingHelper"));
const crypto_1 = require("crypto");
const ZOOM_INTERVAL = 0.1;
function adjustWindowZoom(adjustment) {
    withFocusedWindow((focusedWindow) => {
        focusedWindow.webContents.zoomFactor =
            focusedWindow.webContents.zoomFactor + adjustment;
    });
}
exports.adjustWindowZoom = adjustWindowZoom;
function showNavigationBlockedMessage(message) {
    return new Promise((resolve, reject) => {
        withFocusedWindow((focusedWindow) => {
            electron_1.dialog
                .showMessageBox(focusedWindow, {
                message,
                type: 'error',
                title: 'Navigation blocked',
            })
                .then((result) => resolve(result))
                .catch((err) => {
                reject(err);
            });
        });
    });
}
exports.showNavigationBlockedMessage = showNavigationBlockedMessage;
async function clearAppData(window) {
    const response = await electron_1.dialog.showMessageBox(window, {
        type: 'warning',
        buttons: ['Yes', 'Cancel'],
        defaultId: 1,
        title: 'Clear cache confirmation',
        message: 'This will clear all data (cookies, local storage etc) from this app. Are you sure you wish to proceed?',
    });
    if (response.response !== 0) {
        return;
    }
    await clearCache(window);
}
exports.clearAppData = clearAppData;
async function clearCache(window) {
    const { session } = window.webContents;
    await session.clearStorageData();
    await session.clearCache();
}
exports.clearCache = clearCache;
function createAboutBlankWindow(options, setupWindow, parent) {
    const window = createNewWindow({ ...options, show: false }, setupWindow, 'about:blank', (0, helpers_1.nativeTabsSupported)() ? undefined : parent);
    window.webContents.once('did-stop-loading', () => {
        if (window.webContents.getURL() === 'about:blank') {
            window.close();
        }
        else {
            window.show();
        }
    });
    return window;
}
exports.createAboutBlankWindow = createAboutBlankWindow;
function createNewTab(options, setupWindow, url, foreground) {
    const focusedWindow = electron_1.BrowserWindow.getFocusedWindow();
    log.debug('createNewTab', {
        url,
        foreground,
        focusedWindow,
    });
    return withFocusedWindow((focusedWindow) => {
        const newTab = createNewWindow(options, setupWindow, url);
        log.debug('createNewTab.withFocusedWindow', { focusedWindow, newTab });
        focusedWindow.addTabbedWindow(newTab);
        if (!foreground) {
            focusedWindow.focus();
        }
        return newTab;
    });
}
exports.createNewTab = createNewTab;
function createNewWindow(options, setupWindow, url, parent) {
    log.debug('createNewWindow', {
        url,
        parent,
    });
    const window = new electron_1.BrowserWindow({
        parent: (0, helpers_1.nativeTabsSupported)() ? undefined : parent,
        ...getDefaultWindowOptions(options),
    });
    setupWindow(options, window);
    window.loadURL(url).catch((err) => log.error('window.loadURL ERROR', err));
    return window;
}
exports.createNewWindow = createNewWindow;
function getCurrentURL() {
    return withFocusedWindow((focusedWindow) => focusedWindow.webContents.getURL());
}
exports.getCurrentURL = getCurrentURL;
function getDefaultWindowOptions(options) {
    var _a, _b, _c;
    const browserwindowOptions = {
        ...options.browserwindowOptions,
    };
    // We're going to remove this and merge it separately into DEFAULT_WINDOW_OPTIONS.webPreferences
    // Otherwise the browserwindowOptions.webPreferences object will completely replace the
    // webPreferences specified in the DEFAULT_WINDOW_OPTIONS with itself
    delete browserwindowOptions.webPreferences;
    const webPreferences = {
        ...((_b = (_a = options.browserwindowOptions) === null || _a === void 0 ? void 0 : _a.webPreferences) !== null && _b !== void 0 ? _b : {}),
    };
    const defaultOptions = {
        autoHideMenuBar: options.autoHideMenuBar,
        fullscreenable: true,
        tabbingIdentifier: (0, helpers_1.nativeTabsSupported)()
            ? (_c = options.tabbingIdentifier) !== null && _c !== void 0 ? _c : (0, crypto_1.randomUUID)()
            : undefined,
        title: options.name,
        webPreferences: {
            javascript: true,
            nodeIntegration: false,
            preload: path_1.default.join(__dirname, 'preload.js'),
            plugins: true,
            sandbox: false,
            webSecurity: !options.insecure,
            zoomFactor: options.zoom,
            // `contextIsolation` was switched to true in Electron 12, which:
            // 1. Breaks access to global variables in `--inject`-ed scripts:
            //    https://github.com/nativefier/nativefier/issues/1269
            // 2. Might break notifications under Windows, although this was refuted:
            //    https://github.com/nativefier/nativefier/issues/1292
            // So, it was flipped to false in https://github.com/nativefier/nativefier/pull/1308
            //
            // If attempting to set it back to `true` (for security),
            // do test exhaustively these two areas, and more.
            contextIsolation: false,
            ...webPreferences,
        },
        ...browserwindowOptions,
    };
    log.debug('getDefaultWindowOptions', {
        options,
        webPreferences,
        defaultOptions,
    });
    return defaultOptions;
}
exports.getDefaultWindowOptions = getDefaultWindowOptions;
function goBack() {
    log.debug('onGoBack');
    withFocusedWindow((focusedWindow) => {
        focusedWindow.webContents.goBack();
    });
}
exports.goBack = goBack;
function goForward() {
    log.debug('onGoForward');
    withFocusedWindow((focusedWindow) => {
        focusedWindow.webContents.goForward();
    });
}
exports.goForward = goForward;
function goToURL(url) {
    return withFocusedWindow((focusedWindow) => focusedWindow.loadURL(url));
}
exports.goToURL = goToURL;
function hideWindow(window, event, fastQuit, tray) {
    if ((0, helpers_1.isOSX)() && !fastQuit) {
        // this is called when exiting from clicking the cross button on the window
        event.preventDefault();
        window.hide();
    }
    else if (!fastQuit && tray !== 'false') {
        event.preventDefault();
        window.hide();
    }
    // will close the window on other platforms
}
exports.hideWindow = hideWindow;
function injectCSS(browserWindow) {
    const cssToInject = (0, helpers_1.getCSSToInject)();
    if (!cssToInject) {
        return;
    }
    browserWindow.webContents.on('did-navigate', () => {
        log.debug('browserWindow.webContents.did-navigate', browserWindow.webContents.getURL());
        browserWindow.webContents
            .insertCSS(cssToInject)
            .catch((err) => log.error('browserWindow.webContents.insertCSS', err));
        // We must inject css early enough; so onResponseStarted is a good place.
        browserWindow.webContents.session.webRequest.onResponseStarted({ urls: [] }, // Pass an empty filter list; null will not match _any_ urls
        (details) => {
            log.debug('onResponseStarted', {
                resourceType: details.resourceType,
                url: details.url,
            });
            injectCSSIntoResponse(details, cssToInject).catch((err) => {
                log.error('injectCSSIntoResponse ERROR', err);
            });
        });
    });
}
exports.injectCSS = injectCSS;
function injectCSSIntoResponse(details, cssToInject) {
    var _a;
    const contentType = details.responseHeaders && 'content-type' in details.responseHeaders
        ? details.responseHeaders['content-type'][0]
        : undefined;
    log.debug('injectCSSIntoResponse', { details, cssToInject, contentType });
    // We go with a denylist rather than a whitelist (e.g. only text/html)
    // to avoid "whoops I didn't think this should have been CSS-injected" cases
    const nonInjectableContentTypes = [
        /application\/.*/,
        /font\/.*/,
        /image\/.*/,
    ];
    const nonInjectableResourceTypes = ['image', 'script', 'stylesheet', 'xhr'];
    if ((contentType &&
        ((_a = nonInjectableContentTypes.filter((x) => {
            const matches = x.exec(contentType);
            return matches && (matches === null || matches === void 0 ? void 0 : matches.length) > 0;
        })) === null || _a === void 0 ? void 0 : _a.length) > 0) ||
        nonInjectableResourceTypes.includes(details.resourceType) ||
        !details.webContents) {
        log.debug(`Skipping CSS injection for:\n${details.url}\nwith resourceType ${details.resourceType} and content-type ${contentType}`);
        return Promise.resolve(undefined);
    }
    log.debug(`Injecting CSS for:\n${details.url}\nwith resourceType ${details.resourceType} and content-type ${contentType}`);
    return details.webContents.insertCSS(cssToInject);
}
function sendParamsOnDidFinishLoad(options, window) {
    window.webContents.on('did-finish-load', () => {
        log.debug('sendParamsOnDidFinishLoad.window.webContents.did-finish-load', window.webContents.getURL());
        // In children windows too: Restore pinch-to-zoom, disabled by default in recent Electron.
        // See https://github.com/nativefier/nativefier/issues/379#issuecomment-598612128
        // and https://github.com/electron/electron/pull/12679
        window.webContents
            .setVisualZoomLevelLimits(1, 3)
            .catch((err) => log.error('webContents.setVisualZoomLevelLimits', err));
        window.webContents.send('params', JSON.stringify(options));
    });
}
exports.sendParamsOnDidFinishLoad = sendParamsOnDidFinishLoad;
function setProxyRules(window, proxyRules) {
    window.webContents.session
        .setProxy({
        proxyRules,
        pacScript: '',
        proxyBypassRules: '',
    })
        .catch((err) => log.error('session.setProxy ERROR', err));
}
exports.setProxyRules = setProxyRules;
function withFocusedWindow(block) {
    const focusedWindow = electron_1.BrowserWindow.getFocusedWindow();
    if (focusedWindow) {
        return block(focusedWindow);
    }
    return undefined;
}
exports.withFocusedWindow = withFocusedWindow;
function zoomOut() {
    log.debug('zoomOut');
    adjustWindowZoom(-ZOOM_INTERVAL);
}
exports.zoomOut = zoomOut;
function zoomReset(options) {
    log.debug('zoomReset');
    withFocusedWindow((focusedWindow) => {
        var _a;
        focusedWindow.webContents.zoomFactor = (_a = options.zoom) !== null && _a !== void 0 ? _a : 1.0;
    });
}
exports.zoomReset = zoomReset;
function zoomIn() {
    log.debug('zoomIn');
    adjustWindowZoom(ZOOM_INTERVAL);
}
exports.zoomIn = zoomIn;
//# sourceMappingURL=windowHelpers.js.map