mirror of
https://github.com/zulip/zulip-desktop.git
synced 2025-11-04 14:03:27 +00:00
Merge pull request #180 from geeeeeeeeek/issue/refinements-on-server-side
Refinements on the main process
This commit is contained in:
@@ -7,24 +7,10 @@ function appUpdater() {
|
|||||||
const log = require('electron-log');
|
const log = require('electron-log');
|
||||||
log.transports.file.level = 'info';
|
log.transports.file.level = 'info';
|
||||||
autoUpdater.logger = log;
|
autoUpdater.logger = log;
|
||||||
/*
|
|
||||||
AutoUpdater.on('error', err => log.info(err));
|
|
||||||
autoUpdater.on('checking-for-update', () => log.info('checking-for-update'));
|
|
||||||
autoUpdater.on('update-available', () => log.info('update-available'));
|
|
||||||
autoUpdater.on('update-not-available', () => log.info('update-not-available'));
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Ask the user if update is available
|
// Ask the user if update is available
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
autoUpdater.on('update-downloaded', (event, info) => {
|
autoUpdater.on('update-downloaded', (event, info) => {
|
||||||
// Let message = app.getName() + ' ' + info.releaseName + ' is now available. It will be installed the next time you restart the application.';
|
|
||||||
// if (info.releaseNotes) {
|
|
||||||
// const splitNotes = info.releaseNotes.split(/[^\r]\n/);
|
|
||||||
// message += '\n\nRelease notes:\n';
|
|
||||||
// splitNotes.forEach(notes => {
|
|
||||||
// message += notes + '\n\n';
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// Ask user to update the app
|
// Ask user to update the app
|
||||||
dialog.showMessageBox({
|
dialog.showMessageBox({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
const wurl = require('wurl');
|
|
||||||
|
|
||||||
// Check link if it's internal/external
|
|
||||||
function linkIsInternal(currentUrl, newUrl) {
|
|
||||||
const currentDomain = wurl('hostname', currentUrl);
|
|
||||||
const newDomain = wurl('hostname', newUrl);
|
|
||||||
return currentDomain === newDomain;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll be needing this to open images in default browser
|
|
||||||
const skipImages = '.jpg|.gif|.png|.jpeg|.JPG|.PNG';
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
linkIsInternal,
|
|
||||||
skipImages
|
|
||||||
};
|
|
||||||
@@ -9,8 +9,6 @@ const BrowserWindow = electron.BrowserWindow;
|
|||||||
const shell = electron.shell;
|
const shell = electron.shell;
|
||||||
const appName = app.getName();
|
const appName = app.getName();
|
||||||
|
|
||||||
const {about} = require('./windowmanager');
|
|
||||||
|
|
||||||
function sendAction(action) {
|
function sendAction(action) {
|
||||||
const win = BrowserWindow.getAllWindows()[0];
|
const win = BrowserWindow.getAllWindows()[0];
|
||||||
|
|
||||||
@@ -135,8 +133,10 @@ const darwinTpl = [
|
|||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
label: 'Zulip desktop',
|
label: 'Zulip desktop',
|
||||||
click() {
|
click(item, focusedWindow) {
|
||||||
about();
|
if (focusedWindow) {
|
||||||
|
sendAction('open-about');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -270,8 +270,10 @@ const otherTpl = [
|
|||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
label: 'Zulip desktop',
|
label: 'Zulip desktop',
|
||||||
click() {
|
click(item, focusedWindow) {
|
||||||
about();
|
if (focusedWindow) {
|
||||||
|
sendAction('open-about');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
const path = require('path');
|
|
||||||
const electron = require('electron');
|
|
||||||
const ipc = require('electron').ipcMain;
|
|
||||||
|
|
||||||
const APP_ICON = path.join(__dirname, '../resources', 'Icon');
|
|
||||||
|
|
||||||
const iconPath = () => {
|
|
||||||
return APP_ICON + (process.platform === 'win32' ? '.ico' : '.png');
|
|
||||||
};
|
|
||||||
let domainWindow;
|
|
||||||
let aboutWindow;
|
|
||||||
|
|
||||||
function onClosed() {
|
|
||||||
// Dereference the window
|
|
||||||
domainWindow = null;
|
|
||||||
aboutWindow = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change Zulip server Window
|
|
||||||
function createdomainWindow() {
|
|
||||||
const domainwin = new electron.BrowserWindow({
|
|
||||||
title: 'Switch Server',
|
|
||||||
frame: false,
|
|
||||||
height: 300,
|
|
||||||
resizable: false,
|
|
||||||
width: 400,
|
|
||||||
show: false,
|
|
||||||
icon: iconPath()
|
|
||||||
|
|
||||||
});
|
|
||||||
const domainURL = 'file://' + path.join(__dirname, '../renderer', 'pref.html');
|
|
||||||
domainwin.loadURL(domainURL);
|
|
||||||
domainwin.on('closed', onClosed);
|
|
||||||
|
|
||||||
return domainwin;
|
|
||||||
}
|
|
||||||
// Call this window onClick addDomain in tray
|
|
||||||
function addDomain() {
|
|
||||||
domainWindow = createdomainWindow();
|
|
||||||
domainWindow.once('ready-to-show', () => {
|
|
||||||
domainWindow.show();
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
if (domainWindow !== null) {
|
|
||||||
if (!domainWindow.isDestroyed()) {
|
|
||||||
domainWindow.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 15000);
|
|
||||||
}
|
|
||||||
// About window
|
|
||||||
function createAboutWindow() {
|
|
||||||
const aboutwin = new electron.BrowserWindow({
|
|
||||||
width: 500,
|
|
||||||
height: 500,
|
|
||||||
title: 'About Zulip Desktop',
|
|
||||||
show: false,
|
|
||||||
center: true,
|
|
||||||
fullscreen: false,
|
|
||||||
fullscreenable: false,
|
|
||||||
resizable: false
|
|
||||||
});
|
|
||||||
const aboutURL = 'file://' + path.join(__dirname, '../renderer', 'about.html');
|
|
||||||
aboutwin.loadURL(aboutURL);
|
|
||||||
aboutwin.on('closed', onClosed);
|
|
||||||
|
|
||||||
// Stop page to update it's title
|
|
||||||
aboutwin.on('page-title-updated', e => {
|
|
||||||
e.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
aboutwin.on('closed', onClosed);
|
|
||||||
|
|
||||||
return aboutwin;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call this onClick About in tray
|
|
||||||
function about() {
|
|
||||||
aboutWindow = createAboutWindow();
|
|
||||||
aboutWindow.once('ready-to-show', () => {
|
|
||||||
aboutWindow.show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ipc.on('trayabout', event => {
|
|
||||||
if (event) {
|
|
||||||
about();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
addDomain,
|
|
||||||
about
|
|
||||||
};
|
|
||||||
@@ -116,11 +116,11 @@ html, body {
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab .settings-tab {
|
.tab .functional-tab {
|
||||||
background: #eee;
|
background: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab .settings-tab i {
|
.tab .functional-tab i {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
line-height: 36px;
|
line-height: 36px;
|
||||||
}
|
}
|
||||||
@@ -151,6 +151,17 @@ html, body {
|
|||||||
.tab .server-tab-badge {
|
.tab .server-tab-badge {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tab .server-tab-badge.close-button {
|
||||||
|
width: 16px;
|
||||||
|
padding: 0 0 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab .server-tab-badge.close-button i {
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
/*******************
|
/*******************
|
||||||
* Webview Area *
|
* Webview Area *
|
||||||
*******************/
|
*******************/
|
||||||
|
|||||||
BIN
app/renderer/img/icon.png
Normal file
BIN
app/renderer/img/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
43
app/renderer/js/components/functional-tab.js
Normal file
43
app/renderer/js/components/functional-tab.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Tab = require(__dirname + '/../components/tab.js');
|
||||||
|
|
||||||
|
class FunctionalTab extends Tab {
|
||||||
|
template() {
|
||||||
|
return `<div class="tab">
|
||||||
|
<div class="server-tab-badge close-button">
|
||||||
|
<i class="material-icons">close</i>
|
||||||
|
</div>
|
||||||
|
<div class="server-tab functional-tab">
|
||||||
|
<i class="material-icons">${this.props.materialIcon}</i>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.$el = this.generateNodeFromTemplate(this.template());
|
||||||
|
this.props.$root.appendChild(this.$el);
|
||||||
|
|
||||||
|
this.$closeButton = this.$el.getElementsByClassName('server-tab-badge')[0];
|
||||||
|
this.registerListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
registerListeners() {
|
||||||
|
super.registerListeners();
|
||||||
|
|
||||||
|
this.$el.addEventListener('mouseover', () => {
|
||||||
|
this.$closeButton.classList.add('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$el.addEventListener('mouseout', () => {
|
||||||
|
this.$closeButton.classList.remove('active');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$closeButton.addEventListener('click', e => {
|
||||||
|
this.props.onDestroy();
|
||||||
|
e.stopPropagation();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = FunctionalTab;
|
||||||
31
app/renderer/js/components/server-tab.js
Normal file
31
app/renderer/js/components/server-tab.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Tab = require(__dirname + '/../components/tab.js');
|
||||||
|
|
||||||
|
class ServerTab extends Tab {
|
||||||
|
template() {
|
||||||
|
return `<div class="tab">
|
||||||
|
<div class="server-tab-badge"></div>
|
||||||
|
<div class="server-tab" style="background-image: url(${this.props.icon});"></div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
super.init();
|
||||||
|
|
||||||
|
this.$badge = this.$el.getElementsByClassName('server-tab-badge')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
updateBadge(count) {
|
||||||
|
if (count > 0) {
|
||||||
|
const formattedCount = count > 999 ? '1K+' : count;
|
||||||
|
|
||||||
|
this.$badge.innerHTML = formattedCount;
|
||||||
|
this.$badge.classList.add('active');
|
||||||
|
} else {
|
||||||
|
this.$badge.classList.remove('active');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ServerTab;
|
||||||
@@ -3,65 +3,43 @@
|
|||||||
const BaseComponent = require(__dirname + '/../components/base.js');
|
const BaseComponent = require(__dirname + '/../components/base.js');
|
||||||
|
|
||||||
class Tab extends BaseComponent {
|
class Tab extends BaseComponent {
|
||||||
constructor(params) {
|
constructor(props) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
const {url, icon, name, type, $root, onClick} = params;
|
this.props = props;
|
||||||
this.url = url;
|
this.webview = this.props.webview;
|
||||||
this.name = name;
|
|
||||||
this.icon = icon;
|
|
||||||
this.type = type;
|
|
||||||
this.$root = $root;
|
|
||||||
this.onClick = onClick;
|
|
||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
template() {
|
|
||||||
if (this.type === Tab.SERVER_TAB) {
|
|
||||||
return `<div class="tab" domain="${this.url}">
|
|
||||||
<div class="server-tab-badge"></div>
|
|
||||||
<div class="server-tab" style="background-image: url(${this.icon});"></div>
|
|
||||||
</div>`;
|
|
||||||
} else {
|
|
||||||
return `<div class="tab" domain="${this.url}">
|
|
||||||
<div class="server-tab-badge"></div>
|
|
||||||
<div class="server-tab settings-tab">
|
|
||||||
<i class="material-icons md-48">settings</i>
|
|
||||||
</div>
|
|
||||||
</div>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.$el = this.generateNodeFromTemplate(this.template());
|
this.$el = this.generateNodeFromTemplate(this.template());
|
||||||
this.$badge = this.$el.getElementsByClassName('server-tab-badge')[0];
|
this.props.$root.appendChild(this.$el);
|
||||||
this.$root.appendChild(this.$el);
|
|
||||||
|
|
||||||
this.registerListeners();
|
this.registerListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBadge(count) {
|
registerListeners() {
|
||||||
if (count > 0) {
|
this.$el.addEventListener('click', this.props.onClick);
|
||||||
const formattedCount = count > 999 ? '1K+' : count;
|
|
||||||
|
|
||||||
this.$badge.innerHTML = formattedCount;
|
|
||||||
this.$badge.classList.add('active');
|
|
||||||
} else {
|
|
||||||
this.$badge.classList.remove('active');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerListeners() {
|
isLoading() {
|
||||||
this.$el.addEventListener('click', this.onClick);
|
return this.webview.isLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
activate() {
|
activate() {
|
||||||
this.$el.classList.add('active');
|
this.$el.classList.add('active');
|
||||||
|
this.webview.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
deactivate() {
|
deactivate() {
|
||||||
this.$el.classList.remove('active');
|
this.$el.classList.remove('active');
|
||||||
|
this.webview.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.$el.parentNode.removeChild(this.$el);
|
||||||
|
this.webview.$el.parentNode.removeChild(this.webview.$el);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,38 +2,28 @@
|
|||||||
|
|
||||||
const DomainUtil = require(__dirname + '/../utils/domain-util.js');
|
const DomainUtil = require(__dirname + '/../utils/domain-util.js');
|
||||||
const SystemUtil = require(__dirname + '/../utils/system-util.js');
|
const SystemUtil = require(__dirname + '/../utils/system-util.js');
|
||||||
const {linkIsInternal, skipImages} = require(__dirname + '/../../../main/link-helper');
|
const LinkUtil = require(__dirname + '/../utils/link-util.js');
|
||||||
const {app, dialog, shell} = require('electron').remote;
|
const {app, dialog, shell} = require('electron').remote;
|
||||||
const {ipcRenderer} = require('electron');
|
const {ipcRenderer} = require('electron');
|
||||||
|
|
||||||
const BaseComponent = require(__dirname + '/../components/base.js');
|
const BaseComponent = require(__dirname + '/../components/base.js');
|
||||||
|
|
||||||
class WebView extends BaseComponent {
|
class WebView extends BaseComponent {
|
||||||
constructor(params) {
|
constructor(props) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
const {$root, url, index, name, isActive, onTitleChange, nodeIntegration} = params;
|
this.props = props;
|
||||||
this.$root = $root;
|
|
||||||
this.index = index;
|
|
||||||
this.name = name;
|
|
||||||
this.url = url;
|
|
||||||
this.nodeIntegration = nodeIntegration;
|
|
||||||
|
|
||||||
this.onTitleChange = onTitleChange;
|
|
||||||
this.zoomFactor = 1.0;
|
this.zoomFactor = 1.0;
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.isActive = isActive;
|
|
||||||
this.domainUtil = new DomainUtil();
|
|
||||||
this.systemUtil = new SystemUtil();
|
|
||||||
this.badgeCount = 0;
|
this.badgeCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template() {
|
template() {
|
||||||
return `<webview
|
return `<webview
|
||||||
id="webview-${this.index}"
|
|
||||||
class="disabled"
|
class="disabled"
|
||||||
src="${this.url}"
|
src="${this.props.url}"
|
||||||
${this.nodeIntegration ? 'nodeIntegration' : ''}
|
${this.props.nodeIntegration ? 'nodeIntegration' : ''}
|
||||||
disablewebsecurity
|
disablewebsecurity
|
||||||
preload="js/preload.js"
|
preload="js/preload.js"
|
||||||
webpreferences="allowRunningInsecureContent, javascript=yes">
|
webpreferences="allowRunningInsecureContent, javascript=yes">
|
||||||
@@ -42,7 +32,7 @@ class WebView extends BaseComponent {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.$el = this.generateNodeFromTemplate(this.template());
|
this.$el = this.generateNodeFromTemplate(this.template());
|
||||||
this.$root.appendChild(this.$el);
|
this.props.$root.appendChild(this.$el);
|
||||||
|
|
||||||
this.registerListeners();
|
this.registerListeners();
|
||||||
}
|
}
|
||||||
@@ -50,9 +40,9 @@ class WebView extends BaseComponent {
|
|||||||
registerListeners() {
|
registerListeners() {
|
||||||
this.$el.addEventListener('new-window', event => {
|
this.$el.addEventListener('new-window', event => {
|
||||||
const {url} = event;
|
const {url} = event;
|
||||||
const domainPrefix = this.domainUtil.getDomain(this.index).url;
|
const domainPrefix = DomainUtil.getDomain(this.props.index).url;
|
||||||
|
|
||||||
if (linkIsInternal(domainPrefix, url) && url.match(skipImages) === null) {
|
if (LinkUtil.isInternal(domainPrefix, url)) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.$el.loadURL(url);
|
this.$el.loadURL(url);
|
||||||
} else {
|
} else {
|
||||||
@@ -64,14 +54,14 @@ class WebView extends BaseComponent {
|
|||||||
this.$el.addEventListener('page-title-updated', event => {
|
this.$el.addEventListener('page-title-updated', event => {
|
||||||
const {title} = event;
|
const {title} = event;
|
||||||
this.badgeCount = this.getBadgeCount(title);
|
this.badgeCount = this.getBadgeCount(title);
|
||||||
this.onTitleChange();
|
this.props.onTitleChange();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.$el.addEventListener('dom-ready', this.show.bind(this));
|
this.$el.addEventListener('dom-ready', this.show.bind(this));
|
||||||
|
|
||||||
this.$el.addEventListener('did-fail-load', event => {
|
this.$el.addEventListener('did-fail-load', event => {
|
||||||
const {errorDescription} = event;
|
const {errorDescription} = event;
|
||||||
const hasConnectivityErr = (this.systemUtil.connectivityERR.indexOf(errorDescription) >= 0);
|
const hasConnectivityErr = (SystemUtil.connectivityERR.indexOf(errorDescription) >= 0);
|
||||||
if (hasConnectivityErr) {
|
if (hasConnectivityErr) {
|
||||||
console.error('error', errorDescription);
|
console.error('error', errorDescription);
|
||||||
this.checkConnectivity();
|
this.checkConnectivity();
|
||||||
@@ -79,10 +69,10 @@ class WebView extends BaseComponent {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.$el.addEventListener('did-start-loading', () => {
|
this.$el.addEventListener('did-start-loading', () => {
|
||||||
let userAgent = this.systemUtil.getUserAgent();
|
let userAgent = SystemUtil.getUserAgent();
|
||||||
if (!userAgent) {
|
if (!userAgent) {
|
||||||
this.systemUtil.setUserAgent(this.$el.getUserAgent());
|
SystemUtil.setUserAgent(this.$el.getUserAgent());
|
||||||
userAgent = this.systemUtil.getUserAgent();
|
userAgent = SystemUtil.getUserAgent();
|
||||||
}
|
}
|
||||||
this.$el.setUserAgent(userAgent);
|
this.$el.setUserAgent(userAgent);
|
||||||
});
|
});
|
||||||
@@ -95,14 +85,14 @@ class WebView extends BaseComponent {
|
|||||||
|
|
||||||
show() {
|
show() {
|
||||||
// Do not show WebView if another tab was selected and this tab should be in background.
|
// Do not show WebView if another tab was selected and this tab should be in background.
|
||||||
if (!this.isActive()) {
|
if (!this.props.isActive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$el.classList.remove('disabled');
|
this.$el.classList.remove('disabled');
|
||||||
this.focus();
|
this.focus();
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.onTitleChange(this.$el.getTitle());
|
this.props.onTitleChange(this.$el.getTitle());
|
||||||
}
|
}
|
||||||
|
|
||||||
focus() {
|
focus() {
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ const {ipcRenderer} = require('electron');
|
|||||||
|
|
||||||
const DomainUtil = require(__dirname + '/js/utils/domain-util.js');
|
const DomainUtil = require(__dirname + '/js/utils/domain-util.js');
|
||||||
const WebView = require(__dirname + '/js/components/webview.js');
|
const WebView = require(__dirname + '/js/components/webview.js');
|
||||||
const Tab = require(__dirname + '/js/components/tab.js');
|
const ServerTab = require(__dirname + '/js/components/server-tab.js');
|
||||||
|
const FunctionalTab = require(__dirname + '/js/components/functional-tab.js');
|
||||||
|
|
||||||
class ServerManagerView {
|
class ServerManagerView {
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -17,21 +18,19 @@ class ServerManagerView {
|
|||||||
this.$settingsButton = $actionsContainer.querySelector('#settings-action');
|
this.$settingsButton = $actionsContainer.querySelector('#settings-action');
|
||||||
this.$content = document.getElementById('content');
|
this.$content = document.getElementById('content');
|
||||||
|
|
||||||
this.settingsTabIndex = -1;
|
|
||||||
this.activeTabIndex = -1;
|
this.activeTabIndex = -1;
|
||||||
this.webviews = [];
|
|
||||||
this.tabs = [];
|
this.tabs = [];
|
||||||
|
this.functionalTabs = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.domainUtil = new DomainUtil();
|
|
||||||
this.initTabs();
|
this.initTabs();
|
||||||
this.initActions();
|
this.initActions();
|
||||||
this.registerIpcs();
|
this.registerIpcs();
|
||||||
}
|
}
|
||||||
|
|
||||||
initTabs() {
|
initTabs() {
|
||||||
const servers = this.domainUtil.getDomains();
|
const servers = DomainUtil.getDomains();
|
||||||
if (servers.length > 0) {
|
if (servers.length > 0) {
|
||||||
for (let i = 0; i < servers.length; i++) {
|
for (let i = 0; i < servers.length; i++) {
|
||||||
this.initServer(servers[i], i);
|
this.initServer(servers[i], i);
|
||||||
@@ -43,94 +42,115 @@ class ServerManagerView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initServer(server, index) {
|
initServer(server, index) {
|
||||||
this.tabs.push(new Tab({
|
this.tabs.push(new ServerTab({
|
||||||
url: server.url,
|
|
||||||
name: server.alias,
|
|
||||||
icon: server.icon,
|
icon: server.icon,
|
||||||
type: Tab.SERVER_TAB,
|
|
||||||
$root: this.$tabsContainer,
|
$root: this.$tabsContainer,
|
||||||
onClick: this.activateTab.bind(this, index)
|
onClick: this.activateTab.bind(this, index),
|
||||||
}));
|
webview: new WebView({
|
||||||
this.webviews.push(new WebView({
|
$root: this.$content,
|
||||||
$root: this.$content,
|
index,
|
||||||
index,
|
url: server.url,
|
||||||
url: server.url,
|
name: server.alias,
|
||||||
name: server.alias,
|
isActive: () => {
|
||||||
isActive: () => {
|
return index === this.activeTabIndex;
|
||||||
return index === this.activeTabIndex;
|
},
|
||||||
},
|
onTitleChange: this.updateBadge.bind(this),
|
||||||
onTitleChange: this.updateBadge.bind(this),
|
nodeIntegration: false
|
||||||
nodeIntegration: false
|
})
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
initActions() {
|
initActions() {
|
||||||
this.$reloadButton.addEventListener('click', () => {
|
this.$reloadButton.addEventListener('click', () => {
|
||||||
this.webviews[this.activeTabIndex].reload();
|
this.tabs[this.activeTabIndex].webview.reload();
|
||||||
});
|
});
|
||||||
this.$addServerButton.addEventListener('click', this.openSettings.bind(this));
|
this.$addServerButton.addEventListener('click', this.openSettings.bind(this));
|
||||||
this.$settingsButton.addEventListener('click', this.openSettings.bind(this));
|
this.$settingsButton.addEventListener('click', this.openSettings.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
openSettings() {
|
openFunctionalTab(tabProps) {
|
||||||
if (this.settingsTabIndex !== -1) {
|
if (this.functionalTabs[tabProps.name]) {
|
||||||
this.activateTab(this.settingsTabIndex);
|
this.activateTab(this.functionalTabs[tabProps.name]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const url = 'file://' + __dirname + '/preference.html';
|
|
||||||
|
|
||||||
this.settingsTabIndex = this.webviews.length;
|
this.functionalTabs[tabProps.name] = this.tabs.length;
|
||||||
|
|
||||||
this.tabs.push(new Tab({
|
this.tabs.push(new FunctionalTab({
|
||||||
url,
|
materialIcon: tabProps.materialIcon,
|
||||||
name: 'Settings',
|
|
||||||
type: Tab.SETTINGS_TAB,
|
|
||||||
$root: this.$tabsContainer,
|
$root: this.$tabsContainer,
|
||||||
onClick: this.activateTab.bind(this, this.settingsTabIndex)
|
onClick: this.activateTab.bind(this, this.functionalTabs[tabProps.name]),
|
||||||
|
onDestroy: this.destroyTab.bind(this, tabProps.name, this.functionalTabs[tabProps.name]),
|
||||||
|
webview: new WebView({
|
||||||
|
$root: this.$content,
|
||||||
|
index: this.functionalTabs[tabProps.name],
|
||||||
|
url: tabProps.url,
|
||||||
|
name: tabProps.name,
|
||||||
|
isActive: () => {
|
||||||
|
return this.functionalTabs[tabProps.name] === this.activeTabIndex;
|
||||||
|
},
|
||||||
|
onTitleChange: this.updateBadge.bind(this),
|
||||||
|
nodeIntegration: true
|
||||||
|
})
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.webviews.push(new WebView({
|
this.activateTab(this.functionalTabs[tabProps.name]);
|
||||||
$root: this.$content,
|
|
||||||
index: this.settingsTabIndex,
|
|
||||||
url,
|
|
||||||
name: 'Settings',
|
|
||||||
isActive: () => {
|
|
||||||
return this.settingsTabIndex === this.activeTabIndex;
|
|
||||||
},
|
|
||||||
onTitleChange: this.updateBadge.bind(this),
|
|
||||||
nodeIntegration: true
|
|
||||||
}));
|
|
||||||
|
|
||||||
this.activateTab(this.settingsTabIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
activateTab(index) {
|
openSettings() {
|
||||||
if (this.webviews[index].loading) {
|
this.openFunctionalTab({
|
||||||
|
name: 'Settings',
|
||||||
|
materialIcon: 'settings',
|
||||||
|
url: `file://${__dirname}/preference.html`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openAbout() {
|
||||||
|
this.openFunctionalTab({
|
||||||
|
name: 'About',
|
||||||
|
materialIcon: 'sentiment_very_satisfied',
|
||||||
|
url: `file://${__dirname}/about.html`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
activateTab(index, hideOldTab = true) {
|
||||||
|
if (this.tabs[index].loading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.activeTabIndex !== -1) {
|
if (this.activeTabIndex !== -1) {
|
||||||
if (this.activeTabIndex === index) {
|
if (this.activeTabIndex === index) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else if (hideOldTab) {
|
||||||
this.tabs[this.activeTabIndex].deactivate();
|
this.tabs[this.activeTabIndex].deactivate();
|
||||||
this.webviews[this.activeTabIndex].hide();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tabs[index].activate();
|
|
||||||
|
|
||||||
this.activeTabIndex = index;
|
this.activeTabIndex = index;
|
||||||
this.webviews[index].load();
|
this.tabs[index].activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyTab(name, index) {
|
||||||
|
if (this.tabs[index].loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tabs[index].destroy();
|
||||||
|
|
||||||
|
delete this.tabs[index];
|
||||||
|
delete this.functionalTabs[name];
|
||||||
|
|
||||||
|
this.activateTab(0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBadge() {
|
updateBadge() {
|
||||||
let messageCountAll = 0;
|
let messageCountAll = 0;
|
||||||
for (let i = 0; i < this.webviews.length; i++) {
|
for (let i = 0; i < this.tabs.length; i++) {
|
||||||
const count = this.webviews[i].badgeCount;
|
if (this.tabs[i] && this.tabs[i].updateBadge) {
|
||||||
messageCountAll += count;
|
const count = this.tabs[i].webview.badgeCount;
|
||||||
|
messageCountAll += count;
|
||||||
this.tabs[i].updateBadge(count);
|
this.tabs[i].updateBadge(count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcRenderer.send('update-badge', messageCountAll);
|
ipcRenderer.send('update-badge', messageCountAll);
|
||||||
@@ -152,7 +172,7 @@ class ServerManagerView {
|
|||||||
|
|
||||||
for (const key in webviewListeners) {
|
for (const key in webviewListeners) {
|
||||||
ipcRenderer.on(key, () => {
|
ipcRenderer.on(key, () => {
|
||||||
const activeWebview = this.webviews[this.activeTabIndex];
|
const activeWebview = this.tabs[this.activeTabIndex].webview;
|
||||||
if (activeWebview) {
|
if (activeWebview) {
|
||||||
activeWebview[webviewListeners[key]]();
|
activeWebview[webviewListeners[key]]();
|
||||||
}
|
}
|
||||||
@@ -160,6 +180,7 @@ class ServerManagerView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ipcRenderer.on('open-settings', this.openSettings.bind(this));
|
ipcRenderer.on('open-settings', this.openSettings.bind(this));
|
||||||
|
ipcRenderer.on('open-about', this.openAbout.bind(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,13 +13,12 @@ class PreferenceView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this.domainUtil = new DomainUtil();
|
|
||||||
this.initServers();
|
this.initServers();
|
||||||
this.initActions();
|
this.initActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
initServers() {
|
initServers() {
|
||||||
const servers = this.domainUtil.getDomains();
|
const servers = DomainUtil.getDomains();
|
||||||
this.$serverInfoContainer.innerHTML = servers.length ? '' : 'Add your first server to get started!';
|
this.$serverInfoContainer.innerHTML = servers.length ? '' : 'Add your first server to get started!';
|
||||||
|
|
||||||
this.initNewServerForm();
|
this.initNewServerForm();
|
||||||
@@ -64,7 +63,7 @@ class PreferenceView {
|
|||||||
</div>`;
|
</div>`;
|
||||||
this.$serverInfoContainer.appendChild(this.insertNode(serverInfoTemplate));
|
this.$serverInfoContainer.appendChild(this.insertNode(serverInfoTemplate));
|
||||||
document.getElementById(`delete-server-action-${index}`).addEventListener('click', () => {
|
document.getElementById(`delete-server-action-${index}`).addEventListener('click', () => {
|
||||||
this.domainUtil.removeDomain(index);
|
DomainUtil.removeDomain(index);
|
||||||
this.initServers();
|
this.initServers();
|
||||||
// alert('Success. Reload to apply changes.');
|
// alert('Success. Reload to apply changes.');
|
||||||
ipcRenderer.send('reload-main');
|
ipcRenderer.send('reload-main');
|
||||||
@@ -109,13 +108,13 @@ class PreferenceView {
|
|||||||
this.$newServerButton.classList.add('hidden');
|
this.$newServerButton.classList.add('hidden');
|
||||||
});
|
});
|
||||||
this.$saveServerButton.addEventListener('click', () => {
|
this.$saveServerButton.addEventListener('click', () => {
|
||||||
this.domainUtil.checkDomain(this.$newServerUrl.value).then(domain => {
|
DomainUtil.checkDomain(this.$newServerUrl.value).then(domain => {
|
||||||
const server = {
|
const server = {
|
||||||
alias: this.$newServerAlias.value,
|
alias: this.$newServerAlias.value,
|
||||||
url: domain,
|
url: domain,
|
||||||
icon: this.$newServerIcon.value
|
icon: this.$newServerIcon.value
|
||||||
};
|
};
|
||||||
this.domainUtil.addDomain(server);
|
DomainUtil.addDomain(server);
|
||||||
this.$saveServerButton.classList.add('hidden');
|
this.$saveServerButton.classList.add('hidden');
|
||||||
this.$newServerButton.classList.remove('hidden');
|
this.$newServerButton.classList.remove('hidden');
|
||||||
this.$newServerForm.classList.add('hidden');
|
this.$newServerForm.classList.add('hidden');
|
||||||
@@ -117,7 +117,7 @@ const createTray = function () {
|
|||||||
const contextMenu = Menu.buildFromTemplate([{
|
const contextMenu = Menu.buildFromTemplate([{
|
||||||
label: 'About',
|
label: 'About',
|
||||||
click() {
|
click() {
|
||||||
ipcRenderer.send('trayabout');
|
sendAction('open-about');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,9 +4,17 @@ const {app} = require('electron').remote;
|
|||||||
const JsonDB = require('node-json-db');
|
const JsonDB = require('node-json-db');
|
||||||
const request = require('request');
|
const request = require('request');
|
||||||
|
|
||||||
const defaultIconUrl = 'https://chat.zulip.org/static/images/logo/zulip-icon-128x128.271d0f6a0ca2.png';
|
let instance = null;
|
||||||
|
|
||||||
|
const defaultIconUrl = __dirname + '../../../img/icon.png';
|
||||||
class DomainUtil {
|
class DomainUtil {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
if (instance) {
|
||||||
|
return instance;
|
||||||
|
} else {
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
this.db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
|
this.db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
|
||||||
// Migrate from old schema
|
// Migrate from old schema
|
||||||
if (this.db.getData('/').domain) {
|
if (this.db.getData('/').domain) {
|
||||||
@@ -16,6 +24,8 @@ class DomainUtil {
|
|||||||
});
|
});
|
||||||
this.db.delete('/domain');
|
this.db.delete('/domain');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDomains() {
|
getDomains() {
|
||||||
@@ -69,4 +79,4 @@ class DomainUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = DomainUtil;
|
module.exports = new DomainUtil();
|
||||||
|
|||||||
29
app/renderer/js/utils/link-util.js
Normal file
29
app/renderer/js/utils/link-util.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const wurl = require('wurl');
|
||||||
|
|
||||||
|
let instance = null;
|
||||||
|
|
||||||
|
class LinkUtil {
|
||||||
|
constructor() {
|
||||||
|
if (instance) {
|
||||||
|
return instance;
|
||||||
|
} else {
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
isInternal(currentUrl, newUrl) {
|
||||||
|
const currentDomain = wurl('hostname', currentUrl);
|
||||||
|
const newDomain = wurl('hostname', newUrl);
|
||||||
|
|
||||||
|
const skipImages = '.jpg|.gif|.png|.jpeg|.JPG|.PNG';
|
||||||
|
|
||||||
|
// We'll be needing this to open images in default browser
|
||||||
|
return (currentDomain === newDomain) && !newUrl.match(skipImages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new LinkUtil();
|
||||||
@@ -52,4 +52,4 @@ class SystemUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = SystemUtil;
|
module.exports = new SystemUtil();
|
||||||
|
|||||||
@@ -41,5 +41,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<script src="js/preference.js"></script>
|
<script src="js/pages/preference.js"></script>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user