mirror of
https://github.com/zulip/zulip-desktop.git
synced 2025-11-13 02:17:09 +00:00
Addresses the issue of the webview not being in focus after the Back button is clicked. Now, the webview is focused explicitly by calling focus() on click.
261 lines
6.7 KiB
JavaScript
261 lines
6.7 KiB
JavaScript
'use strict';
|
|
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
|
|
const ConfigUtil = require(__dirname + '/../utils/config-util.js');
|
|
const SystemUtil = require(__dirname + '/../utils/system-util.js');
|
|
const { app, dialog } = require('electron').remote;
|
|
|
|
const BaseComponent = require(__dirname + '/../components/base.js');
|
|
const handleExternalLink = require(__dirname + '/../components/handle-external-link.js');
|
|
|
|
const shouldSilentWebview = ConfigUtil.getConfigItem('silent');
|
|
class WebView extends BaseComponent {
|
|
constructor(props) {
|
|
super();
|
|
|
|
this.props = props;
|
|
|
|
this.zoomFactor = 1.0;
|
|
this.loading = true;
|
|
this.badgeCount = 0;
|
|
this.customCSS = ConfigUtil.getConfigItem('customCSS');
|
|
this.$webviewsContainer = document.querySelector('#webviews-container').classList;
|
|
}
|
|
|
|
template() {
|
|
return `<webview
|
|
class="disabled"
|
|
data-tab-id="${this.props.tabIndex}"
|
|
src="${this.props.url}"
|
|
${this.props.nodeIntegration ? 'nodeIntegration' : ''}
|
|
disablewebsecurity
|
|
${this.props.preload ? 'preload="js/preload.js"' : ''}
|
|
partition="persist:webviewsession"
|
|
name="${this.props.name}"
|
|
webpreferences="allowRunningInsecureContent, javascript=yes">
|
|
</webview>`;
|
|
}
|
|
|
|
init() {
|
|
this.$el = this.generateNodeFromTemplate(this.template());
|
|
this.props.$root.appendChild(this.$el);
|
|
|
|
this.registerListeners();
|
|
}
|
|
|
|
registerListeners() {
|
|
this.$el.addEventListener('new-window', event => {
|
|
handleExternalLink.call(this, event);
|
|
});
|
|
|
|
if (shouldSilentWebview) {
|
|
this.$el.addEventListener('dom-ready', () => {
|
|
this.$el.setAudioMuted(true);
|
|
});
|
|
}
|
|
|
|
this.$el.addEventListener('page-title-updated', event => {
|
|
const { title } = event;
|
|
this.badgeCount = this.getBadgeCount(title);
|
|
this.props.onTitleChange();
|
|
});
|
|
|
|
this.$el.addEventListener('did-navigate-in-page', event => {
|
|
const isSettingPage = event.url.includes('renderer/preference.html');
|
|
if (isSettingPage) {
|
|
return;
|
|
}
|
|
this.canGoBackButton();
|
|
});
|
|
|
|
this.$el.addEventListener('did-navigate', () => {
|
|
this.canGoBackButton();
|
|
});
|
|
|
|
this.$el.addEventListener('page-favicon-updated', event => {
|
|
const { favicons } = event;
|
|
|
|
// This returns a string of favicons URL. If there is a PM counts in unread messages then the URL would be like
|
|
// https://chat.zulip.org/static/images/favicon/favicon-pms.png
|
|
if (favicons[0].indexOf('favicon-pms') > 0 && process.platform === 'darwin') {
|
|
// This api is only supported on macOS
|
|
app.dock.setBadge('●');
|
|
// bounce the dock
|
|
if (ConfigUtil.getConfigItem('dockBouncing')) {
|
|
app.dock.bounce();
|
|
}
|
|
}
|
|
});
|
|
|
|
this.$el.addEventListener('dom-ready', () => {
|
|
if (this.props.role === 'server') {
|
|
this.$el.classList.add('onload');
|
|
}
|
|
this.loading = false;
|
|
this.show();
|
|
|
|
// Refocus text boxes after reload
|
|
// Remove when upstream issue https://github.com/electron/electron/issues/14474 is fixed
|
|
this.$el.blur();
|
|
this.$el.focus();
|
|
});
|
|
|
|
this.$el.addEventListener('did-fail-load', event => {
|
|
const { errorDescription } = event;
|
|
const hasConnectivityErr = (SystemUtil.connectivityERR.indexOf(errorDescription) >= 0);
|
|
if (hasConnectivityErr) {
|
|
console.error('error', errorDescription);
|
|
this.props.onNetworkError();
|
|
}
|
|
});
|
|
|
|
this.$el.addEventListener('did-start-loading', () => {
|
|
let userAgent = SystemUtil.getUserAgent();
|
|
if (!userAgent) {
|
|
SystemUtil.setUserAgent(this.$el.getUserAgent());
|
|
userAgent = SystemUtil.getUserAgent();
|
|
}
|
|
this.$el.setUserAgent(userAgent);
|
|
});
|
|
}
|
|
|
|
getBadgeCount(title) {
|
|
const messageCountInTitle = (/\(([0-9]+)\)/).exec(title);
|
|
return messageCountInTitle ? Number(messageCountInTitle[1]) : 0;
|
|
}
|
|
|
|
show() {
|
|
// Do not show WebView if another tab was selected and this tab should be in background.
|
|
if (!this.props.isActive()) {
|
|
return;
|
|
}
|
|
|
|
// To show or hide the loading indicator in the the active tab
|
|
if (this.loading) {
|
|
this.$webviewsContainer.remove('loaded');
|
|
} else {
|
|
this.$webviewsContainer.add('loaded');
|
|
}
|
|
|
|
this.$el.classList.remove('disabled');
|
|
this.$el.classList.add('active');
|
|
setTimeout(() => {
|
|
if (this.props.role === 'server') {
|
|
this.$el.classList.remove('onload');
|
|
}
|
|
}, 1000);
|
|
this.focus();
|
|
this.props.onTitleChange();
|
|
// Injecting preload css in webview to override some css rules
|
|
this.$el.insertCSS(fs.readFileSync(path.join(__dirname, '/../../css/preload.css'), 'utf8'));
|
|
|
|
// get customCSS again from config util to avoid warning user again
|
|
this.customCSS = ConfigUtil.getConfigItem('customCSS');
|
|
if (this.customCSS) {
|
|
if (!fs.existsSync(this.customCSS)) {
|
|
this.customCSS = null;
|
|
ConfigUtil.setConfigItem('customCSS', null);
|
|
|
|
const errMsg = 'The custom css previously set is deleted!';
|
|
dialog.showErrorBox('custom css file deleted!', errMsg);
|
|
return;
|
|
}
|
|
|
|
this.$el.insertCSS(fs.readFileSync(path.resolve(__dirname, this.customCSS), 'utf8'));
|
|
}
|
|
}
|
|
|
|
focus() {
|
|
// focus Webview and it's contents when Window regain focus.
|
|
const webContents = this.$el.getWebContents();
|
|
// HACK: webContents.isFocused() seems to be true even without the element
|
|
// being in focus. So, we check against `document.activeElement`.
|
|
if (webContents && this.$el !== document.activeElement) {
|
|
// HACK: Looks like blur needs to be called on the previously focused
|
|
// element to transfer focus correctly, in Electron v3.0.10
|
|
// See https://github.com/electron/electron/issues/15718
|
|
document.activeElement.blur();
|
|
this.$el.focus();
|
|
webContents.focus();
|
|
}
|
|
}
|
|
|
|
hide() {
|
|
this.$el.classList.add('disabled');
|
|
this.$el.classList.remove('active');
|
|
}
|
|
|
|
load() {
|
|
if (this.$el) {
|
|
this.show();
|
|
} else {
|
|
this.init();
|
|
}
|
|
}
|
|
|
|
zoomIn() {
|
|
this.zoomFactor += 0.1;
|
|
this.$el.setZoomFactor(this.zoomFactor);
|
|
}
|
|
|
|
zoomOut() {
|
|
this.zoomFactor -= 0.1;
|
|
this.$el.setZoomFactor(this.zoomFactor);
|
|
}
|
|
|
|
zoomActualSize() {
|
|
this.zoomFactor = 1.0;
|
|
this.$el.setZoomFactor(this.zoomFactor);
|
|
}
|
|
|
|
logOut() {
|
|
this.$el.executeJavaScript('logout()');
|
|
}
|
|
|
|
showShortcut() {
|
|
this.$el.executeJavaScript('shortcut()');
|
|
}
|
|
|
|
openDevTools() {
|
|
this.$el.openDevTools();
|
|
}
|
|
|
|
back() {
|
|
if (this.$el.canGoBack()) {
|
|
this.$el.goBack();
|
|
this.focus();
|
|
}
|
|
}
|
|
|
|
canGoBackButton() {
|
|
const $backButton = document.querySelector('#actions-container #back-action');
|
|
if (this.$el.canGoBack()) {
|
|
$backButton.classList.remove('disable');
|
|
} else {
|
|
$backButton.classList.add('disable');
|
|
}
|
|
}
|
|
|
|
forward() {
|
|
if (this.$el.canGoForward()) {
|
|
this.$el.goForward();
|
|
}
|
|
}
|
|
|
|
reload() {
|
|
this.hide();
|
|
// Shows the loading indicator till the webview is reloaded
|
|
this.$webviewsContainer.remove('loaded');
|
|
this.loading = true;
|
|
this.$el.reload();
|
|
}
|
|
|
|
send(...param) {
|
|
this.$el.send(...param);
|
|
}
|
|
}
|
|
|
|
module.exports = WebView;
|