mirror of
https://github.com/zulip/zulip-desktop.git
synced 2025-11-04 22:13:13 +00:00
Compare commits
178 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3dade768a7 | ||
|
|
7b3c7ba5fa | ||
|
|
616bc0f73b | ||
|
|
8ecdf1f18a | ||
|
|
d2daa65059 | ||
|
|
487ee538e3 | ||
|
|
6382c6d2b3 | ||
|
|
cbcff67d28 | ||
|
|
61a429365b | ||
|
|
e55f38a962 | ||
|
|
81798583ae | ||
|
|
9cab61cebc | ||
|
|
f290732cb6 | ||
|
|
2dd44852fa | ||
|
|
bd2f17deec | ||
|
|
06faf46bcc | ||
|
|
468e9d539b | ||
|
|
449f407236 | ||
|
|
7efe90e709 | ||
|
|
184e1a5bc4 | ||
|
|
85e7b337a7 | ||
|
|
83759bde1c | ||
|
|
d9b1d45e0e | ||
|
|
df91c20f36 | ||
|
|
c1f6159d69 | ||
|
|
5a0461211a | ||
|
|
1394f790c3 | ||
|
|
4d374ff40c | ||
|
|
0d15435408 | ||
|
|
d4448ba086 | ||
|
|
4bd6fde5b6 | ||
|
|
e5097ace06 | ||
|
|
ca078cbbfd | ||
|
|
6d45105b69 | ||
|
|
40f81af2dd | ||
|
|
d5e6184e75 | ||
|
|
0ec38ba41d | ||
|
|
460a64710a | ||
|
|
9ec62a748f | ||
|
|
a7a80cef99 | ||
|
|
bcaf54b349 | ||
|
|
1f6d0762bb | ||
|
|
1aa1655676 | ||
|
|
0ad66399d0 | ||
|
|
3a6bb14224 | ||
|
|
53eb8051ad | ||
|
|
ed9174f57c | ||
|
|
260d6a1906 | ||
|
|
dc53319c8e | ||
|
|
77369536b3 | ||
|
|
531afcb1e5 | ||
|
|
d6c4eeccf8 | ||
|
|
496b906fd0 | ||
|
|
1be29faea6 | ||
|
|
bc9a7c9890 | ||
|
|
5745276dbb | ||
|
|
acf0282aa0 | ||
|
|
54d942178a | ||
|
|
d84ada373e | ||
|
|
d4d36d0582 | ||
|
|
63e6c634b9 | ||
|
|
4bc558cdbc | ||
|
|
34293fd66b | ||
|
|
5eba4b8200 | ||
|
|
a949307820 | ||
|
|
a714977b5a | ||
|
|
bfcaa51c46 | ||
|
|
d7d3017bc1 | ||
|
|
c7ce8fb7c8 | ||
|
|
65a80de01d | ||
|
|
f6bf210451 | ||
|
|
8c23ec3417 | ||
|
|
97bbd809f7 | ||
|
|
76381cac08 | ||
|
|
13c4ceedc2 | ||
|
|
f0889edf9c | ||
|
|
ab8367c946 | ||
|
|
c5887c8f71 | ||
|
|
7b7ab03d0b | ||
|
|
394caa7934 | ||
|
|
db2860b53e | ||
|
|
6d20df3557 | ||
|
|
2942cd1244 | ||
|
|
174049f489 | ||
|
|
21eae28999 | ||
|
|
f256cbcd5d | ||
|
|
ff8c20f0b4 | ||
|
|
9e0c17a793 | ||
|
|
b4fb00aa52 | ||
|
|
13d0b5e51c | ||
|
|
dc15e4578c | ||
|
|
673da66ee9 | ||
|
|
e397e9bfb4 | ||
|
|
4eca2e9254 | ||
|
|
a1407826b6 | ||
|
|
6d8f83798b | ||
|
|
bfc03c7e95 | ||
|
|
06737ce629 | ||
|
|
6b09840347 | ||
|
|
19b5eecdcd | ||
|
|
f443918433 | ||
|
|
bb74e58d63 | ||
|
|
612e670bb5 | ||
|
|
34bb55cb9f | ||
|
|
1457e82649 | ||
|
|
0bdeaaba18 | ||
|
|
e2286b6110 | ||
|
|
27ba3f3068 | ||
|
|
9859315fea | ||
|
|
73d18dde9e | ||
|
|
0372befc5a | ||
|
|
063799a053 | ||
|
|
297b307726 | ||
|
|
deed66973f | ||
|
|
03486e438d | ||
|
|
e113f59aad | ||
|
|
29ece4824a | ||
|
|
66c62c55e2 | ||
|
|
40852942d2 | ||
|
|
15c8591691 | ||
|
|
e21902a5e3 | ||
|
|
a5d42e8ccd | ||
|
|
0923df7250 | ||
|
|
37f5258210 | ||
|
|
19819f7d48 | ||
|
|
40f74cdac2 | ||
|
|
e4ba3b9721 | ||
|
|
9a221585b9 | ||
|
|
069a0ff306 | ||
|
|
3153fb91da | ||
|
|
92d4d27fa8 | ||
|
|
209fc4a65c | ||
|
|
5e9ecedecd | ||
|
|
613df32bf1 | ||
|
|
7606f37695 | ||
|
|
a2f758a46b | ||
|
|
2a477abe5f | ||
|
|
5f027820f4 | ||
|
|
9e75861546 | ||
|
|
4060596474 | ||
|
|
2e5888c8af | ||
|
|
03d1188e14 | ||
|
|
c91b0c209a | ||
|
|
531973194c | ||
|
|
4d1face275 | ||
|
|
ca7503f1f0 | ||
|
|
9c163b4166 | ||
|
|
742afb1c09 | ||
|
|
f9f70f001b | ||
|
|
edf34efd86 | ||
|
|
72ebed95da | ||
|
|
975a6ab8bf | ||
|
|
3352301b67 | ||
|
|
358260f766 | ||
|
|
b58052ce34 | ||
|
|
de9ad8082b | ||
|
|
d6bf84c821 | ||
|
|
d5cba4096d | ||
|
|
afa12cc266 | ||
|
|
42ede5e54b | ||
|
|
1549db5ce0 | ||
|
|
a0de440c2e | ||
|
|
7e54eb89c2 | ||
|
|
f8e77dfa72 | ||
|
|
db6d1f300a | ||
|
|
eac2b92cb6 | ||
|
|
a349e0e4e0 | ||
|
|
58f35569c8 | ||
|
|
4a9f51aa1b | ||
|
|
5bb05906b5 | ||
|
|
f80095d953 | ||
|
|
181803755a | ||
|
|
ef30cd9624 | ||
|
|
7c82f41e87 | ||
|
|
61dfcfc3b1 | ||
|
|
e3deb93730 | ||
|
|
d6a3e5fe1b | ||
|
|
dc15edf0cd |
22
.travis.yml
22
.travis.yml
@@ -1,12 +1,21 @@
|
|||||||
language: node_js
|
sudo: required
|
||||||
|
dist: trusty
|
||||||
|
|
||||||
os:
|
os:
|
||||||
- osx
|
- osx
|
||||||
- linux
|
- linux
|
||||||
sudo: required
|
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- build-essential
|
||||||
|
- libxext-dev
|
||||||
|
- libxtst-dev
|
||||||
|
- libxkbfile-dev
|
||||||
|
|
||||||
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- 'node'
|
- '6'
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- npm install -g gulp
|
- npm install -g gulp
|
||||||
@@ -15,6 +24,13 @@ before_install:
|
|||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- node_modules
|
- node_modules
|
||||||
|
- app/node_modules
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- npm run travis
|
- npm run travis
|
||||||
|
notifications:
|
||||||
|
webhooks:
|
||||||
|
urls:
|
||||||
|
- https://zulip.org/zulipbot/travis
|
||||||
|
on_success: always
|
||||||
|
on_failure: always
|
||||||
@@ -1,16 +1,24 @@
|
|||||||
#Contributing Guidelines
|
# Contributing Guidelines
|
||||||
|
|
||||||
Thanks for taking the time to contribute!
|
Thanks for taking the time to contribute!
|
||||||
|
|
||||||
The following is a set of guidelines for contributing to zulip-electron. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request.
|
The following is a set of guidelines for contributing to zulip-electron. These are just guidelines, not rules, use your best judgement and feel free to propose changes to this document in a pull request.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
Zulip-Desktop app is built on top of [Electron](http://electron.atom.io/). If you are new to Electron please head over to [this](http://jlord.us/essential-electron/) great article.
|
Zulip-Desktop app is built on top of [Electron](http://electron.atom.io/). If you are new to Electron please head over to [this](http://jlord.us/essential-electron/) great article.
|
||||||
|
|
||||||
|
## Community
|
||||||
|
|
||||||
|
* The whole zulip documentation such as development environment, setting up with zulip project, testing, code of conduct can be read [here](https://zulip.readthedocs.io).
|
||||||
|
|
||||||
|
* If you have any questions regarding zulip-electron, open an [issue](https://github.com/zulip/zulip-electron/issues/new/) or ask it [here](https://chat.zulip.org/#narrow/stream/electron).
|
||||||
|
|
||||||
## Issue
|
## Issue
|
||||||
Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/zulip/zulip-electron/issues). If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/zulip/zulip-electron/issues/new). Please pay attention to following points while opening an issue.
|
Ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/zulip/zulip-electron/issues). If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/zulip/zulip-electron/issues/new). Please pay attention to following points while opening an issue.
|
||||||
|
|
||||||
|
The [Zulipbot](https://github.com/zulip/zulipbot) helps to claim the issue by commenting the following in the comment section: "**@zulipbot** claim". **@zulipbot** will assign you to the issue and label the issue as **in progress**. For more details, check out [**@zulipbot**](https://github.com/zulip/zulipbot).
|
||||||
|
|
||||||
### Does it happen on web browsers? (especially Chrome)
|
### Does it happen on web browsers? (especially Chrome)
|
||||||
Zulip-Desktop is based on Electron, which integrates the Chrome engine within a standalone application.
|
Zulip-Desktop is based on Electron, which integrates the Chrome engine within a standalone application.
|
||||||
If the problem you encounter can be reproduced on web browsers, it may be an issue with Zulip web app.
|
If the problem you encounter can be reproduced on web browsers, it may be an issue with Zulip web app.
|
||||||
|
|||||||
15
README.md
15
README.md
@@ -13,11 +13,13 @@ multi-account, auto-updates etc.
|
|||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
* node >= v6.3.1
|
* node >= v6.3.1
|
||||||
* npm >= 3.10.3
|
> Use [nvm](https://github.com/creationix/nvm) to install the current stable version of node
|
||||||
* If you're on Debian or Ubuntu, you'll also need to install
|
|
||||||
`nodejs-legacy`:
|
|
||||||
|
* python (v2.7.x recommended)
|
||||||
|
* If you're on Debian or Ubuntu, you'll need to install following packages:
|
||||||
```sh
|
```sh
|
||||||
$ sudo apt-get install nodejs-legacy
|
$ sudo apt-get install build-essential libxext-dev libxtst-dev libxkbfile-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
@@ -60,6 +62,8 @@ You can create Windows installer only when running on Windows, the same is true
|
|||||||
|
|
||||||
- [x] Native Notifications
|
- [x] Native Notifications
|
||||||
- [x] SpellChecker
|
- [x] SpellChecker
|
||||||
|
- [x] OSX/Win/Linux installer
|
||||||
|
- [x] Automatic Updates (macOS/Windows)
|
||||||
- [x] Keyboard shortcuts
|
- [x] Keyboard shortcuts
|
||||||
|
|
||||||
Description | Keys
|
Description | Keys
|
||||||
@@ -69,9 +73,6 @@ Change Zulip Server | <kbd>Cmd/Ctrl</kbd> <kbd>,</kbd>
|
|||||||
Back | <kbd>Cmd/Ctrl</kbd> <kbd>[</kbd>
|
Back | <kbd>Cmd/Ctrl</kbd> <kbd>[</kbd>
|
||||||
Forward | <kbd>Cmd/Ctrl</kbd> <kbd>]</kbd>
|
Forward | <kbd>Cmd/Ctrl</kbd> <kbd>]</kbd>
|
||||||
|
|
||||||
- [x] OSX/Win/Linux installer
|
|
||||||
- [ ] Launch on OS startup
|
|
||||||
- [ ] Automatic Updates
|
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +1,47 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const {app, autoUpdater, dialog} = require('electron');
|
const {app, dialog} = require('electron');
|
||||||
const version = app.getVersion();
|
const {autoUpdater} = require('electron-updater');
|
||||||
const os = require('os');
|
|
||||||
const platform = os.platform() + '_' + os.arch(); // usually returns darwin_64
|
|
||||||
|
|
||||||
const updaterFeedURL = 'http://zulipdesktop.herokuapp.com/update/'+ platform + '/' + version;
|
|
||||||
|
|
||||||
function appUpdater() {
|
function appUpdater() {
|
||||||
|
|
||||||
autoUpdater.setFeedURL(updaterFeedURL);
|
|
||||||
|
|
||||||
// Log whats happening
|
// Log whats happening
|
||||||
autoUpdater.on('error', err => console.log(err))
|
const log = require('electron-log');
|
||||||
autoUpdater.on('checking-for-update', () => console.log('checking-for-update'))
|
log.transports.file.level = 'info';
|
||||||
autoUpdater.on('update-available', () => console.log('update-available'))
|
autoUpdater.logger = log;
|
||||||
autoUpdater.on('update-not-available', () => console.log('update-not-available'))
|
/*
|
||||||
|
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
|
||||||
autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName, releaseDate) => {
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
autoUpdater.on('update-downloaded', (event, info) => {
|
||||||
let message = app.getName() + ' ' + releaseName + ' is now available. It will be installed the next time you restart the application.';
|
// Let message = app.getName() + ' ' + info.releaseName + ' is now available. It will be installed the next time you restart the application.';
|
||||||
if (releaseNotes) {
|
// if (info.releaseNotes) {
|
||||||
let splitNotes = releaseNotes.split(/[^\r]\n/);
|
// const splitNotes = info.releaseNotes.split(/[^\r]\n/);
|
||||||
message += '\n\nRelease notes:\n';
|
// message += '\n\nRelease notes:\n';
|
||||||
splitNotes.forEach(function (notes) {
|
// splitNotes.forEach(notes => {
|
||||||
message += notes + '\n\n';
|
// message += notes + '\n\n';
|
||||||
})
|
// });
|
||||||
};
|
// }
|
||||||
// Ask user to update the app
|
// Ask user to update the app
|
||||||
dialog.showMessageBox({
|
dialog.showMessageBox({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
buttons: ['Install and Relaunch' ,'Cancel'],
|
buttons: ['Install and Relaunch', 'Later'],
|
||||||
defaultId: 0,
|
defaultId: 0,
|
||||||
message: 'A new version of ' + app.getName() + ' has been downloaded',
|
message: 'A new version of ' + app.getName() + ' has been downloaded',
|
||||||
detail: message
|
detail: 'It will be installed the next time you restart the application'
|
||||||
}, response => {
|
}, response => {
|
||||||
if (response === 0) {
|
if (response === 0) {
|
||||||
setTimeout(() => autoUpdater.quitAndInstall(), 1);
|
setTimeout(() => autoUpdater.quitAndInstall(), 1);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
// init for updates
|
// Init for updates
|
||||||
autoUpdater.checkForUpdates()
|
autoUpdater.checkForUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
exports = module.exports = {
|
module.exports = {
|
||||||
appUpdater
|
appUpdater
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
const JsonDB = require('node-json-db');
|
|
||||||
const {app} = require('electron').remote;
|
|
||||||
const request = require('request');
|
|
||||||
const ipcRenderer = require('electron').ipcRenderer;
|
|
||||||
|
|
||||||
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
|
|
||||||
const data = db.getData('/');
|
|
||||||
|
|
||||||
console.log(data.domain);
|
|
||||||
|
|
||||||
// if (data.domain && window.location.href.indexOf(data.domain) === -1) {
|
|
||||||
// window.location.href = data.domain
|
|
||||||
// }
|
|
||||||
// require('electron-connect').client.create();
|
|
||||||
|
|
||||||
window.addDomain = function () {
|
|
||||||
document.getElementById('main').innerHTML = 'checking...';
|
|
||||||
|
|
||||||
let newDomain = document.getElementById('url').value;
|
|
||||||
newDomain = newDomain.replace(/^https?:\/\//, '');
|
|
||||||
|
|
||||||
const domain = 'https://' + newDomain;
|
|
||||||
const checkDomain = domain + '/static/audio/zulip.ogg';
|
|
||||||
|
|
||||||
request(checkDomain, (error, response) => {
|
|
||||||
if (!error && response.statusCode !== 404) {
|
|
||||||
document.getElementById('main').innerHTML = 'Connect';
|
|
||||||
db.push('/domain', domain);
|
|
||||||
ipcRenderer.send('new-domain', domain);
|
|
||||||
} else {
|
|
||||||
document.getElementById('main').innerHTML = 'Connect';
|
|
||||||
document.getElementById('server-status').innerHTML = 'Not a vaild Zulip Server.';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -1,27 +1,49 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
const electron = require('electron');
|
const electron = require('electron');
|
||||||
const {app} = require('electron');
|
const {app} = require('electron');
|
||||||
const electronLocalshortcut = require('electron-localshortcut');
|
|
||||||
const ipc = require('electron').ipcMain;
|
const ipc = require('electron').ipcMain;
|
||||||
const Configstore = require('configstore');
|
const {dialog} = require('electron');
|
||||||
|
const https = require('https');
|
||||||
|
const http = require('http');
|
||||||
|
const electronLocalshortcut = require('electron-localshortcut');
|
||||||
|
const Configstore = require('electron-config');
|
||||||
const JsonDB = require('node-json-db');
|
const JsonDB = require('node-json-db');
|
||||||
const isDev = require('electron-is-dev');
|
const isDev = require('electron-is-dev');
|
||||||
const tray = require('./tray');
|
|
||||||
const appMenu = require('./menu');
|
const appMenu = require('./menu');
|
||||||
const {linkIsInternal, skipImages} = require('./link-helper');
|
const {linkIsInternal, skipImages} = require('./link-helper');
|
||||||
const { appUpdater } = require('./autoupdater')
|
const {appUpdater} = require('./autoupdater');
|
||||||
|
|
||||||
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
|
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
|
||||||
const data = db.getData('/');
|
const data = db.getData('/');
|
||||||
|
|
||||||
// adds debug features like hotkeys for triggering dev tools and reload
|
// Adds debug features like hotkeys for triggering dev tools and reload
|
||||||
require('electron-debug')();
|
require('electron-debug')();
|
||||||
|
|
||||||
const conf = new Configstore('Zulip-Desktop');
|
const conf = new Configstore();
|
||||||
|
|
||||||
// prevent window being garbage collected
|
function userOS() {
|
||||||
|
if (os.platform() === 'darwin') {
|
||||||
|
return 'Mac';
|
||||||
|
}
|
||||||
|
if (os.platform() === 'linux') {
|
||||||
|
return 'Linux';
|
||||||
|
}
|
||||||
|
if (os.platform() === 'win32' || os.platform() === 'win64') {
|
||||||
|
if (parseFloat(os.release()) < 6.2) {
|
||||||
|
return 'Windows 7';
|
||||||
|
} else {
|
||||||
|
return 'Windows 10';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting userAgent so that server-side code can identify the desktop app
|
||||||
|
const isUserAgent = 'ZulipElectron/' + app.getVersion() + ' ' + userOS();
|
||||||
|
|
||||||
|
// Prevent window being garbage collected
|
||||||
let mainWindow;
|
let mainWindow;
|
||||||
let targetLink;
|
let targetLink;
|
||||||
|
|
||||||
@@ -31,11 +53,77 @@ const staticURL = 'file://' + path.join(__dirname, '../renderer', 'index.html');
|
|||||||
const targetURL = function () {
|
const targetURL = function () {
|
||||||
if (data.domain === undefined) {
|
if (data.domain === undefined) {
|
||||||
return staticURL;
|
return staticURL;
|
||||||
} else {
|
|
||||||
return data.domain;
|
|
||||||
}
|
}
|
||||||
|
return data.domain;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function serverError(targetURL) {
|
||||||
|
if (targetURL.indexOf('localhost:') < 0 && data.domain) {
|
||||||
|
const req = https.request(targetURL + '/static/audio/zulip.ogg', res => {
|
||||||
|
console.log('Server StatusCode:', res.statusCode);
|
||||||
|
console.log('You are connected to:', res.req._headers.host);
|
||||||
|
if (res.statusCode >= 500 && res.statusCode <= 599) {
|
||||||
|
return dialog.showErrorBox('SERVER IS DOWN!', 'We are getting a ' + res.statusCode + ' error status from the server ' + res.req._headers.host + '. Please try again after some time or you may switch server.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
req.on('error', e => {
|
||||||
|
if (e.toString().indexOf('Error: self signed certificate') >= 0) {
|
||||||
|
const url = targetURL.replace(/^https?:\/\//, '');
|
||||||
|
console.log('Server StatusCode:', 200);
|
||||||
|
console.log('You are connected to:', url);
|
||||||
|
} else {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
req.end();
|
||||||
|
} else if (data.domain) {
|
||||||
|
const req = http.request(targetURL + '/static/audio/zulip.ogg', res => {
|
||||||
|
console.log('Server StatusCode:', res.statusCode);
|
||||||
|
console.log('You are connected to:', res.req._headers.host);
|
||||||
|
});
|
||||||
|
req.on('error', e => {
|
||||||
|
console.error(e);
|
||||||
|
});
|
||||||
|
req.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkConnectivity() {
|
||||||
|
return dialog.showMessageBox({
|
||||||
|
title: 'Internet connection problem',
|
||||||
|
message: 'No internet available! Try again?',
|
||||||
|
type: 'warning',
|
||||||
|
buttons: ['Try again', 'Close'],
|
||||||
|
defaultId: 0
|
||||||
|
}, index => {
|
||||||
|
if (index === 0) {
|
||||||
|
mainWindow.webContents.reload();
|
||||||
|
mainWindow.webContents.send('destroytray');
|
||||||
|
}
|
||||||
|
if (index === 1) {
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const connectivityERR = [
|
||||||
|
'ERR_INTERNET_DISCONNECTED',
|
||||||
|
'ERR_PROXY_CONNECTION_FAILED',
|
||||||
|
'ERR_CONNECTION_RESET',
|
||||||
|
'ERR_NOT_CONNECTED',
|
||||||
|
'ERR_NAME_NOT_RESOLVED'
|
||||||
|
];
|
||||||
|
|
||||||
|
function checkConnection() {
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
mainWindow.webContents.on('did-fail-load', (event, errorCode, errorDescription, validatedURL) => {
|
||||||
|
const hasConnectivityErr = (connectivityERR.indexOf(errorDescription) >= 0);
|
||||||
|
if (hasConnectivityErr) {
|
||||||
|
console.error('error', errorDescription);
|
||||||
|
checkConnectivity();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const isAlreadyRunning = app.makeSingleInstance(() => {
|
const isAlreadyRunning = app.makeSingleInstance(() => {
|
||||||
if (mainWindow) {
|
if (mainWindow) {
|
||||||
if (mainWindow.isMinimized()) {
|
if (mainWindow.isMinimized()) {
|
||||||
@@ -57,6 +145,10 @@ function checkWindowURL() {
|
|||||||
return targetLink;
|
return targetLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isWindowsOrmacOS() {
|
||||||
|
return process.platform === 'darwin' || process.platform === 'win32';
|
||||||
|
}
|
||||||
|
|
||||||
const APP_ICON = path.join(__dirname, '../resources', 'Icon');
|
const APP_ICON = path.join(__dirname, '../resources', 'Icon');
|
||||||
|
|
||||||
const iconPath = () => {
|
const iconPath = () => {
|
||||||
@@ -64,8 +156,8 @@ const iconPath = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function onClosed() {
|
function onClosed() {
|
||||||
// dereference the window
|
// Dereference the window
|
||||||
// for multiple windows store them in an array
|
// For multiple windows, store them in an array
|
||||||
mainWindow = null;
|
mainWindow = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,6 +172,7 @@ function updateDockBadge(title) {
|
|||||||
if (process.platform === 'darwin') {
|
if (process.platform === 'darwin') {
|
||||||
app.setBadgeCount(messageCount);
|
app.setBadgeCount(messageCount);
|
||||||
}
|
}
|
||||||
|
mainWindow.webContents.send('tray', messageCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMainWindow() {
|
function createMainWindow() {
|
||||||
@@ -92,14 +185,24 @@ function createMainWindow() {
|
|||||||
minWidth: 600,
|
minWidth: 600,
|
||||||
minHeight: 400,
|
minHeight: 400,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: path.join(__dirname, 'preload.js'),
|
preload: path.join(__dirname, '../renderer/js/preload.js'),
|
||||||
plugins: true,
|
plugins: true,
|
||||||
allowDisplayingInsecureContent: true,
|
allowDisplayingInsecureContent: true,
|
||||||
nodeIntegration: false
|
nodeIntegration: false
|
||||||
}
|
},
|
||||||
|
show: false
|
||||||
|
});
|
||||||
|
|
||||||
|
win.once('ready-to-show', () => {
|
||||||
|
win.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
serverError(targetURL());
|
||||||
|
|
||||||
|
win.loadURL(targetURL(), {
|
||||||
|
userAgent: isUserAgent + ' ' + win.webContents.getUserAgent()
|
||||||
});
|
});
|
||||||
|
|
||||||
win.loadURL(targetURL());
|
|
||||||
win.on('closed', onClosed);
|
win.on('closed', onClosed);
|
||||||
win.setTitle('Zulip');
|
win.setTitle('Zulip');
|
||||||
|
|
||||||
@@ -129,7 +232,7 @@ function createMainWindow() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// on osx it's 'moved'
|
// On osx it's 'moved'
|
||||||
win.on('move', function () {
|
win.on('move', function () {
|
||||||
const pos = this.getPosition();
|
const pos = this.getPosition();
|
||||||
conf.set({
|
conf.set({
|
||||||
@@ -138,19 +241,55 @@ function createMainWindow() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// stop page to update it's title
|
// Stop page to update it's title
|
||||||
win.on('page-title-updated', (e, title) => {
|
win.on('page-title-updated', (e, title) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
updateDockBadge(title);
|
updateDockBadge(title);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// To destroy tray icon when navigate to a new URL
|
||||||
|
win.webContents.on('will-navigate', e => {
|
||||||
|
if (e) {
|
||||||
|
win.webContents.send('destroytray');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return win;
|
return win;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - fix certificate errors
|
// TODO - fix certificate errors
|
||||||
app.commandLine.appendSwitch('ignore-certificate-errors', 'true');
|
|
||||||
|
// app.commandLine.appendSwitch('ignore-certificate-errors', 'true');
|
||||||
|
|
||||||
|
// For self-signed certificate
|
||||||
|
ipc.on('certificate-err', (e, domain) => {
|
||||||
|
const detail = `URL: ${domain} \n Error: Self-Signed Certificate`;
|
||||||
|
dialog.showMessageBox(mainWindow, {
|
||||||
|
title: 'Certificate error',
|
||||||
|
message: `Do you trust certificate from ${domain}?`,
|
||||||
|
// eslint-disable-next-line object-shorthand
|
||||||
|
detail: detail,
|
||||||
|
type: 'warning',
|
||||||
|
buttons: ['Yes', 'No'],
|
||||||
|
cancelId: 1
|
||||||
|
// eslint-disable-next-line object-shorthand
|
||||||
|
}, response => {
|
||||||
|
if (response === 0) {
|
||||||
|
// eslint-disable-next-line object-shorthand
|
||||||
|
db.push('/domain', domain);
|
||||||
|
mainWindow.loadURL(domain);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line max-params
|
||||||
|
app.on('certificate-error', (event, webContents, url, error, certificate, callback) => {
|
||||||
|
event.preventDefault();
|
||||||
|
callback(true);
|
||||||
|
});
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
|
// Unregister all the shortcuts so that they don't interfare with other apps
|
||||||
|
electronLocalshortcut.unregisterAll(mainWindow);
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
@@ -165,13 +304,14 @@ app.on('activate', () => {
|
|||||||
app.on('ready', () => {
|
app.on('ready', () => {
|
||||||
electron.Menu.setApplicationMenu(appMenu);
|
electron.Menu.setApplicationMenu(appMenu);
|
||||||
mainWindow = createMainWindow();
|
mainWindow = createMainWindow();
|
||||||
tray.create(mainWindow);
|
// Not using for now // tray.create();
|
||||||
|
|
||||||
const page = mainWindow.webContents;
|
const page = mainWindow.webContents;
|
||||||
|
|
||||||
// TODO - use global shortcut instead
|
// TODO - use global shortcut instead
|
||||||
electronLocalshortcut.register(mainWindow, 'CommandOrControl+R', () => {
|
electronLocalshortcut.register(mainWindow, 'CommandOrControl+R', () => {
|
||||||
mainWindow.reload();
|
mainWindow.reload();
|
||||||
|
mainWindow.webContents.send('destroytray');
|
||||||
});
|
});
|
||||||
|
|
||||||
electronLocalshortcut.register(mainWindow, 'CommandOrControl+[', () => {
|
electronLocalshortcut.register(mainWindow, 'CommandOrControl+[', () => {
|
||||||
@@ -187,7 +327,7 @@ app.on('ready', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
page.on('dom-ready', () => {
|
page.on('dom-ready', () => {
|
||||||
page.insertCSS(fs.readFileSync(path.join(__dirname, 'preload.css'), 'utf8'));
|
page.insertCSS(fs.readFileSync(path.join(__dirname, '../renderer/css/preload.css'), 'utf8'));
|
||||||
mainWindow.show();
|
mainWindow.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -200,26 +340,35 @@ app.on('ready', () => {
|
|||||||
electron.shell.openExternal(url);
|
electron.shell.openExternal(url);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
page.once('did-frame-finish-load', () => {
|
||||||
page.once("did-frame-finish-load", () => {
|
const checkOS = isWindowsOrmacOS();
|
||||||
if (process.platform === 'darwin' && !isDev) {
|
if (checkOS && !isDev) {
|
||||||
// Initate auto-updates
|
// Initate auto-updates on MacOS and Windows
|
||||||
appUpdater()
|
appUpdater();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
checkConnection();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('will-quit', () => {
|
||||||
|
// Unregister all the shortcuts so that they don't interfare with other apps
|
||||||
|
electronLocalshortcut.unregisterAll(mainWindow);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipc.on('new-domain', (e, domain) => {
|
ipc.on('new-domain', (e, domain) => {
|
||||||
// mainWindow.loadURL(domain);
|
// MainWindow.loadURL(domain);
|
||||||
if (!mainWindow) {
|
if (!mainWindow) {
|
||||||
mainWindow = createMainWindow();
|
mainWindow = createMainWindow();
|
||||||
mainWindow.loadURL(domain);
|
mainWindow.loadURL(domain);
|
||||||
|
mainWindow.webContents.send('destroytray');
|
||||||
} else if (mainWindow.isMinimized()) {
|
} else if (mainWindow.isMinimized()) {
|
||||||
|
mainWindow.webContents.send('destroytray');
|
||||||
mainWindow.loadURL(domain);
|
mainWindow.loadURL(domain);
|
||||||
mainWindow.show();
|
mainWindow.show();
|
||||||
} else {
|
} else {
|
||||||
|
mainWindow.webContents.send('destroytray');
|
||||||
mainWindow.loadURL(domain);
|
mainWindow.loadURL(domain);
|
||||||
|
serverError(domain);
|
||||||
}
|
}
|
||||||
targetLink = domain;
|
targetLink = domain;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ function linkIsInternal(currentUrl, newUrl) {
|
|||||||
// We'll be needing this to open images in default browser
|
// We'll be needing this to open images in default browser
|
||||||
const skipImages = '.jpg|.gif|.png|.jpeg|.JPG|.PNG';
|
const skipImages = '.jpg|.gif|.png|.jpeg|.JPG|.PNG';
|
||||||
|
|
||||||
exports = module.exports = {
|
module.exports = {
|
||||||
linkIsInternal, skipImages
|
linkIsInternal,
|
||||||
|
skipImages
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,10 +2,13 @@
|
|||||||
const os = require('os');
|
const os = require('os');
|
||||||
const electron = require('electron');
|
const electron = require('electron');
|
||||||
|
|
||||||
|
const {dialog} = require('electron');
|
||||||
|
|
||||||
const app = electron.app;
|
const app = electron.app;
|
||||||
const BrowserWindow = electron.BrowserWindow;
|
const BrowserWindow = electron.BrowserWindow;
|
||||||
const shell = electron.shell;
|
const shell = electron.shell;
|
||||||
const appName = app.getName();
|
const appName = app.getName();
|
||||||
|
// Const tray = require('./tray');
|
||||||
|
|
||||||
const {addDomain, about} = require('./windowmanager');
|
const {addDomain, about} = require('./windowmanager');
|
||||||
|
|
||||||
@@ -19,13 +22,21 @@ function sendAction(action) {
|
|||||||
win.webContents.send(action);
|
win.webContents.send(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clearCache() {
|
||||||
|
const win = BrowserWindow.getAllWindows()[0];
|
||||||
|
const ses = win.webContents.session;
|
||||||
|
ses.clearCache(() => {
|
||||||
|
dialog.showMessageBox({type: 'info', buttons: [], message: 'Cache cleared!'});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const viewSubmenu = [
|
const viewSubmenu = [
|
||||||
{
|
{
|
||||||
label: 'Reload',
|
label: 'Reload',
|
||||||
accelerator: 'CmdOrCtrl+R',
|
|
||||||
click(item, focusedWindow) {
|
click(item, focusedWindow) {
|
||||||
if (focusedWindow) {
|
if (focusedWindow) {
|
||||||
focusedWindow.reload();
|
focusedWindow.reload();
|
||||||
|
focusedWindow.webContents.send('destroytray');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -65,6 +76,14 @@ const viewSubmenu = [
|
|||||||
{
|
{
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Toggle Tray Icon',
|
||||||
|
click(item, focusedWindow) {
|
||||||
|
if (focusedWindow) {
|
||||||
|
focusedWindow.webContents.send('toggletray');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Toggle Developer Tools',
|
label: 'Toggle Developer Tools',
|
||||||
accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
||||||
@@ -135,8 +154,15 @@ const darwinTpl = [
|
|||||||
{
|
{
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Clear Cache',
|
||||||
|
click() {
|
||||||
|
clearCache();
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Log Out',
|
label: 'Log Out',
|
||||||
|
accelerator: 'Cmd+L',
|
||||||
click(item, focusedWindow) {
|
click(item, focusedWindow) {
|
||||||
if (focusedWindow) {
|
if (focusedWindow) {
|
||||||
sendAction('log-out');
|
sendAction('log-out');
|
||||||
@@ -264,8 +290,15 @@ const otherTpl = [
|
|||||||
{
|
{
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Clear Cache',
|
||||||
|
click() {
|
||||||
|
clearCache();
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Log Out',
|
label: 'Log Out',
|
||||||
|
accelerator: 'Ctrl+L',
|
||||||
click(item, focusedWindow) {
|
click(item, focusedWindow) {
|
||||||
if (focusedWindow) {
|
if (focusedWindow) {
|
||||||
sendAction('log-out');
|
sendAction('log-out');
|
||||||
@@ -313,7 +346,6 @@ const otherTpl = [
|
|||||||
{
|
{
|
||||||
role: 'selectall'
|
role: 'selectall'
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
const ipcRenderer = require('electron').ipcRenderer;
|
|
||||||
|
|
||||||
// Handle zooming functionality
|
|
||||||
|
|
||||||
const zoomIn = () => {
|
|
||||||
webFrame.setZoomFactor(webFrame.getZoomFactor() + 0.1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const zoomOut = () => {
|
|
||||||
webFrame.setZoomFactor(webFrame.getZoomFactor() - 0.1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const zoomActualSize = () => {
|
|
||||||
webFrame.setZoomFactor(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get zooming actions from main process
|
|
||||||
ipcRenderer.on('zoomIn', () => {
|
|
||||||
zoomIn();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcRenderer.on('zoomOut', () => {
|
|
||||||
zoomOut();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcRenderer.on('zoomActualSize', () => {
|
|
||||||
zoomActualSize();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcRenderer.on('log-out', () => {
|
|
||||||
// create the menu for the below
|
|
||||||
document.querySelector('.dropdown-toggle').click();
|
|
||||||
|
|
||||||
const nodes = document.querySelectorAll('.dropdown-menu li:last-child a');
|
|
||||||
nodes[nodes.length - 1].click();
|
|
||||||
});
|
|
||||||
|
|
||||||
ipcRenderer.on('shortcut', () => {
|
|
||||||
// create the menu for the below
|
|
||||||
document.querySelector('.dropdown-toggle').click();
|
|
||||||
|
|
||||||
const nodes = document.querySelectorAll('.dropdown-menu li:nth-child(4) a');
|
|
||||||
nodes[nodes.length - 1].click();
|
|
||||||
});
|
|
||||||
|
|
||||||
require('./domain');
|
|
||||||
|
|
||||||
// To prevent failing this script on linux we need to load it after the document loaded
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
require('./spellchecker');
|
|
||||||
});
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
const {SpellCheckHandler, ContextMenuListener, ContextMenuBuilder} = require('electron-spellchecker');
|
|
||||||
|
|
||||||
// Implement spellcheck using electron api
|
|
||||||
|
|
||||||
window.spellCheckHandler = new SpellCheckHandler();
|
|
||||||
window.spellCheckHandler.attachToInput();
|
|
||||||
|
|
||||||
// Start off as US English
|
|
||||||
window.spellCheckHandler.switchLanguage('en-US');
|
|
||||||
|
|
||||||
let contextMenuBuilder = new ContextMenuBuilder(window.spellCheckHandler);
|
|
||||||
let contextMenuListener = new ContextMenuListener((info) => {
|
|
||||||
contextMenuBuilder.showPopupMenu(info);
|
|
||||||
});
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
const path = require('path');
|
|
||||||
const electron = require('electron');
|
|
||||||
const app = require('electron').app;
|
|
||||||
const {addDomain, about} = require('./windowmanager');
|
|
||||||
|
|
||||||
let tray = null;
|
|
||||||
|
|
||||||
const APP_ICON = path.join(__dirname, '../resources/tray', 'tray');
|
|
||||||
|
|
||||||
const iconPath = () => {
|
|
||||||
if (process.platform === 'linux') {
|
|
||||||
return APP_ICON + 'linux.png'
|
|
||||||
}
|
|
||||||
return APP_ICON + (process.platform === 'win32' ? 'win.ico' : 'osx.png');
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.create = () => {
|
|
||||||
const contextMenu = electron.Menu.buildFromTemplate([
|
|
||||||
{
|
|
||||||
label: 'About',
|
|
||||||
click() {
|
|
||||||
about();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Change Zulip server',
|
|
||||||
click() {
|
|
||||||
addDomain();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Reload',
|
|
||||||
click(item, focusedWindow) {
|
|
||||||
if (focusedWindow) {
|
|
||||||
focusedWindow.reload();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'separator'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Quit',
|
|
||||||
click() {
|
|
||||||
app.quit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
tray = new electron.Tray(iconPath());
|
|
||||||
tray.setToolTip(`${app.getName()}`);
|
|
||||||
tray.setContextMenu(contextMenu);
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const electron = require('electron');
|
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 domainWindow;
|
||||||
let aboutWindow;
|
let aboutWindow;
|
||||||
|
|
||||||
function onClosed() {
|
function onClosed() {
|
||||||
// dereference the window
|
// Dereference the window
|
||||||
domainWindow = null;
|
domainWindow = null;
|
||||||
aboutWindow = null;
|
aboutWindow = null;
|
||||||
}
|
}
|
||||||
@@ -14,10 +20,14 @@ function onClosed() {
|
|||||||
// Change Zulip server Window
|
// Change Zulip server Window
|
||||||
function createdomainWindow() {
|
function createdomainWindow() {
|
||||||
const domainwin = new electron.BrowserWindow({
|
const domainwin = new electron.BrowserWindow({
|
||||||
|
title: 'Switch Server',
|
||||||
frame: false,
|
frame: false,
|
||||||
height: 300,
|
height: 300,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
width: 400
|
width: 400,
|
||||||
|
show: false,
|
||||||
|
icon: iconPath()
|
||||||
|
|
||||||
});
|
});
|
||||||
const domainURL = 'file://' + path.join(__dirname, '../renderer', 'pref.html');
|
const domainURL = 'file://' + path.join(__dirname, '../renderer', 'pref.html');
|
||||||
domainwin.loadURL(domainURL);
|
domainwin.loadURL(domainURL);
|
||||||
@@ -25,13 +35,20 @@ function createdomainWindow() {
|
|||||||
|
|
||||||
return domainwin;
|
return domainwin;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call this window onClick addDomain in tray
|
// Call this window onClick addDomain in tray
|
||||||
function addDomain() {
|
function addDomain() {
|
||||||
domainWindow = createdomainWindow();
|
domainWindow = createdomainWindow();
|
||||||
|
domainWindow.once('ready-to-show', () => {
|
||||||
domainWindow.show();
|
domainWindow.show();
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
if (domainWindow !== null) {
|
||||||
|
if (!domainWindow.isDestroyed()) {
|
||||||
|
domainWindow.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 15000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// About window
|
// About window
|
||||||
function createAboutWindow() {
|
function createAboutWindow() {
|
||||||
const aboutwin = new electron.BrowserWindow({
|
const aboutwin = new electron.BrowserWindow({
|
||||||
@@ -48,7 +65,7 @@ function createAboutWindow() {
|
|||||||
aboutwin.loadURL(aboutURL);
|
aboutwin.loadURL(aboutURL);
|
||||||
aboutwin.on('closed', onClosed);
|
aboutwin.on('closed', onClosed);
|
||||||
|
|
||||||
// stop page to update it's title
|
// Stop page to update it's title
|
||||||
aboutwin.on('page-title-updated', e => {
|
aboutwin.on('page-title-updated', e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
@@ -61,9 +78,23 @@ function createAboutWindow() {
|
|||||||
// Call this onClick About in tray
|
// Call this onClick About in tray
|
||||||
function about() {
|
function about() {
|
||||||
aboutWindow = createAboutWindow();
|
aboutWindow = createAboutWindow();
|
||||||
|
aboutWindow.once('ready-to-show', () => {
|
||||||
aboutWindow.show();
|
aboutWindow.show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports = module.exports = {
|
ipc.on('trayabout', event => {
|
||||||
addDomain, about
|
if (event) {
|
||||||
|
about();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipc.on('traychangeserver', event => {
|
||||||
|
if (event) {
|
||||||
|
addDomain();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
module.exports = {
|
||||||
|
addDomain,
|
||||||
|
about
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "zulip",
|
"name": "zulip",
|
||||||
"productName": "Zulip",
|
"productName": "Zulip",
|
||||||
"version": "0.5.2",
|
"version": "0.5.10",
|
||||||
"description": "Zulip Desktop App",
|
"description": "Zulip Desktop App",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"email":"<svnitakash@gmail.com>",
|
"email": "<svnitakash@gmail.com>",
|
||||||
"copyright": "©2016 Kandra Labs, Inc.",
|
"copyright": "©2017 Kandra Labs, Inc.",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Akash Nimare",
|
"name": "Akash Nimare",
|
||||||
"email": "svnitakash@gmail.com"
|
"email": "svnitakash@gmail.com"
|
||||||
@@ -27,16 +27,16 @@
|
|||||||
"InstantMessaging"
|
"InstantMessaging"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"electron-is-dev": "*",
|
"electron-config":"0.2.1",
|
||||||
"configstore": "^2.0.0",
|
"electron-debug": "1.1.0",
|
||||||
"dialogs": "1.1.14",
|
"electron-is-dev": "0.1.2",
|
||||||
"electron-context-menu": "0.4.0",
|
"electron-localshortcut": "1.0.0",
|
||||||
"electron-debug": "^1.0.0",
|
"electron-log": "1.3.0",
|
||||||
"electron-dl": "^0.2.0",
|
"electron-spellchecker": "1.0.5",
|
||||||
"electron-localshortcut": "^0.6.1",
|
"electron-updater": "1.11.2",
|
||||||
"node-json-db": "^0.7.2",
|
"https": "^1.0.0",
|
||||||
"request": "^2.74.0",
|
"node-json-db": "0.7.3",
|
||||||
"electron-spellchecker": "^0.5.12",
|
"request": "2.79.0",
|
||||||
"wurl": "^2.1.0"
|
"wurl": "2.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,17 +6,19 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="about">
|
<div class="about">
|
||||||
<center><img src="../resources/zulip.png"></center>
|
<img class="logo" src="../resources/zulip.png" />
|
||||||
<center><p class="detail" id="version"> Version : ?.?.? </p>
|
<p class="detail" id="version">version ?.?.?</p>
|
||||||
<center><p class="detail"> License : Apache </p>
|
<div class="maintenance-info">
|
||||||
<center><p class="detail"> Maintainer : Zulip </p>
|
<p class="detail maintainer">Maintained by Zulip</p>
|
||||||
<p class="left"><a class="bug" onclick="linkInBrowser()" href="#">Found bug?</a></p>
|
<p class="detail license">Available under the Apache License</p>
|
||||||
|
<a class="bug" onclick="linkInBrowser()" href="#">Found bug?</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
const app = require('electron').remote.app;
|
const app = require('electron').remote.app;
|
||||||
const version_tag = document.getElementById('version');
|
const version_tag = document.getElementById('version');
|
||||||
version_tag.innerHTML = ' Version : ' + app.getVersion() + ' ';
|
version_tag.innerHTML = 'version ' + app.getVersion();
|
||||||
|
|
||||||
function linkInBrowser(event) {
|
function linkInBrowser(event) {
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
body {
|
body {
|
||||||
background: #6BB6C7;
|
background: #fafafa;
|
||||||
|
font-family: menu, "Helvetica Neue", sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#version {
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.about {
|
.about {
|
||||||
margin-top: 50px;
|
margin-top: 50px;
|
||||||
}
|
text-align: center;
|
||||||
|
|
||||||
.left {
|
|
||||||
position: absolute;
|
|
||||||
top:89%;
|
|
||||||
left:76%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.about p {
|
.about p {
|
||||||
@@ -18,10 +25,49 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.about img {
|
.about img {
|
||||||
width:160px;
|
width: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail {
|
.detail {
|
||||||
text-align: left;
|
text-align: center;
|
||||||
margin-left: 35%;
|
}
|
||||||
|
|
||||||
|
.detail.maintainer {
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail.license {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maintenance-info {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
bottom: 20px;
|
||||||
|
left: 0px;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maintenance-info p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1em;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maintenance-info .bug {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 8px 15px;
|
||||||
|
margin-top: 30px;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: #52c2af;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.maintenance-info .bug:hover {
|
||||||
|
background-color: #32a692;
|
||||||
}
|
}
|
||||||
@@ -1,375 +1,143 @@
|
|||||||
@charset "UTF-8";
|
* {
|
||||||
header,
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||||
section {
|
Helvetica, Arial, sans-serif, "Apple Color Emoji",
|
||||||
display: block
|
"Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
color: #444;
|
||||||
|
|
||||||
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
html {
|
|
||||||
font-size: 100%;
|
|
||||||
overflow-y: scroll;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
}
|
|
||||||
html,
|
|
||||||
button,
|
|
||||||
input {
|
|
||||||
font-family: "Helvetica Neue", Arial, sans-serif
|
|
||||||
}
|
|
||||||
html,
|
|
||||||
body {
|
body {
|
||||||
height: 100%;
|
|
||||||
margin: 0
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
border: 0;
|
|
||||||
-ms-interpolation-mode: bicubic
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
vertical-align: middle
|
|
||||||
}
|
|
||||||
form {
|
|
||||||
margin: 0
|
|
||||||
}
|
|
||||||
fieldset {
|
|
||||||
border: 0;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0
|
background-image: url(../img/topography.png);
|
||||||
}
|
|
||||||
button,
|
|
||||||
input {
|
|
||||||
font-size: 100%;
|
|
||||||
margin: 0;
|
|
||||||
vertical-align: baseline;
|
|
||||||
box-sizing: content-box;
|
|
||||||
-webkit-box-sizing: content-box
|
|
||||||
}
|
|
||||||
button,
|
|
||||||
input {
|
|
||||||
line-height: normal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
button {
|
button {
|
||||||
cursor: pointer;
|
font-size: 1em;
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
button::-moz-focus-inner,
|
|
||||||
input::-moz-focus-inner {
|
|
||||||
border: 0;
|
|
||||||
padding: 0
|
|
||||||
}
|
|
||||||
hr {
|
|
||||||
display: none
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
max-width: 100%
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
color: #111;
|
|
||||||
line-height: 1em;
|
|
||||||
font-weight: 400;
|
|
||||||
font-family: "Helvetica Neue", Arial, sans-serif;
|
|
||||||
text-rendering: optimizelegibility;
|
|
||||||
-webkit-text-stroke: none
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
margin: 0 0 35px
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body.container-layout header #logo {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top
|
|
||||||
}
|
|
||||||
body.container-layout header #logo {
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
background-position: -790px 0
|
|
||||||
}
|
|
||||||
button[type=submit] {
|
|
||||||
text-decoration: none;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-border-radius: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
position: relative;
|
|
||||||
font-family: "Helvetica Neue", Arial, sans-serif;
|
|
||||||
font-size-adjust: auto;
|
|
||||||
vertical-align: bottom;
|
|
||||||
background-color: #e6eaef;
|
|
||||||
border: 2px solid #e6eaef;
|
|
||||||
color: #96a0ac;
|
|
||||||
font-size: 20px;
|
|
||||||
line-height: 26px;
|
|
||||||
padding: 6px 17px
|
|
||||||
}
|
|
||||||
.desktop button[type=submit] {
|
|
||||||
-webkit-transition: all .2s ease-in-out;
|
|
||||||
transition: all .2s ease-in-out
|
|
||||||
}
|
|
||||||
.desktop button[type=submit]:hover {
|
|
||||||
background-color: #eff2f5;
|
|
||||||
border: 2px solid #eff2f5;
|
|
||||||
color: #96a0ac
|
|
||||||
}
|
|
||||||
button[type=submit]:focus {
|
|
||||||
outline: 0
|
|
||||||
}
|
|
||||||
button[type=submit].btn-primary {
|
|
||||||
background-color: #20b36c;
|
|
||||||
border: 2px solid #20b36c;
|
|
||||||
color: #fff
|
|
||||||
}
|
|
||||||
.desktop button[type=submit].btn-primary:hover {
|
|
||||||
background-color: #39ca83;
|
|
||||||
border: 2px solid #39ca83;
|
|
||||||
color: #fff
|
|
||||||
}
|
|
||||||
button[type=submit].btn-primary:focus {
|
|
||||||
outline: 0
|
|
||||||
}
|
|
||||||
button[type=submit].btn-large {
|
|
||||||
font-family: "Helvetica Neue", Arial, sans-serif;
|
|
||||||
font-size: 20px;
|
|
||||||
line-height: 26px;
|
|
||||||
padding: 12px 30px
|
|
||||||
}
|
|
||||||
input[type=text] {
|
|
||||||
font-family: "Helvetica Neue", Arial, sans-serif;
|
|
||||||
font-weight: 200;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
-webkit-border-radius: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background-color: #fff;
|
|
||||||
border: 1px solid #cad0d7;
|
|
||||||
color: #000;
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 26px;
|
|
||||||
height: 42px;
|
|
||||||
padding: 10px 10px
|
|
||||||
}
|
|
||||||
.desktop input[type=text]:hover {
|
|
||||||
background-color: #fff;
|
|
||||||
border-color: #bbc3cc;
|
|
||||||
color: #111
|
|
||||||
}
|
|
||||||
input[type=text]:focus {
|
|
||||||
background-color: #fff;
|
|
||||||
border-color: #20b36c!important;
|
|
||||||
color: #000;
|
|
||||||
outline: 0
|
|
||||||
}
|
|
||||||
input[type=text]::-webkit-input-placeholder {
|
|
||||||
color: #8e959e
|
|
||||||
}
|
|
||||||
input[type=text]::-moz-placeholder {
|
|
||||||
color: #8e959e
|
|
||||||
}
|
|
||||||
input[type=text]:-ms-input-placeholder {
|
|
||||||
color: #8e959e
|
|
||||||
}
|
|
||||||
.form-large input[type=text] {
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 26px;
|
|
||||||
height: 54px;
|
|
||||||
padding: 12px 15px
|
|
||||||
}
|
|
||||||
.control-group {
|
|
||||||
margin-top: 40px
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
white-space: normal;
|
|
||||||
word-break: break-all;
|
|
||||||
word-break: break-word;
|
|
||||||
-webkit-hyphens: auto;
|
|
||||||
-moz-hyphens: auto;
|
|
||||||
hyphens: auto
|
|
||||||
}
|
|
||||||
.section-main {
|
|
||||||
position: relative
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
color: #111;
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 24px;
|
|
||||||
font-family: "Helvetica Neue", Arial, sans-serif;
|
|
||||||
background: #edf1f3;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
box-sizing: border-box
|
|
||||||
}
|
|
||||||
.desktop body {
|
|
||||||
padding-top: 116px
|
|
||||||
}
|
|
||||||
body.container-layout {
|
|
||||||
padding: 0!important;
|
|
||||||
background-color: #E6EAEF
|
|
||||||
}
|
|
||||||
header {
|
header {
|
||||||
z-index: 800;
|
text-align: center;
|
||||||
border-bottom: 1px solid #dae0e7;
|
margin: 0px 0px 30px 0px;
|
||||||
background: rgba(255, 255, 255, .97);
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: relative;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%
|
|
||||||
}
|
|
||||||
header .container {
|
|
||||||
position: relative
|
|
||||||
}
|
|
||||||
.desktop header {
|
|
||||||
position: fixed
|
|
||||||
}
|
|
||||||
header .container {
|
|
||||||
position: relative;
|
|
||||||
height: 75px
|
|
||||||
}
|
|
||||||
.container-layout header {
|
|
||||||
position: relative;
|
|
||||||
border: 0;
|
|
||||||
background: 0 0;
|
|
||||||
padding: 30px 0
|
|
||||||
}
|
|
||||||
.container-layout header .container {
|
|
||||||
height: auto
|
|
||||||
}
|
|
||||||
header #logo {
|
|
||||||
display: block;
|
|
||||||
text-indent: -9999px
|
|
||||||
}
|
}
|
||||||
|
|
||||||
header #logo {
|
header img {
|
||||||
position: absolute!important;
|
width: 50px;
|
||||||
top: 50%;
|
|
||||||
left: 10px;
|
|
||||||
-webkit-transform: translate(0, -50%);
|
|
||||||
transform: translate(0, -50%)
|
|
||||||
}
|
}
|
||||||
body.container-layout header #logo {
|
|
||||||
position: relative!important;
|
header h1 {
|
||||||
top: 0;
|
display: inline-block;
|
||||||
left: 0;
|
margin: 10px 0px 10px 10px;
|
||||||
-webkit-transform: translate(0, 0);
|
|
||||||
transform: translate(0, 0);
|
font-weight: 500;
|
||||||
margin: 0 auto;
|
|
||||||
display: block
|
|
||||||
}
|
}
|
||||||
.content {
|
|
||||||
padding-bottom: 40px;
|
|
||||||
overflow: hidden
|
section.server {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 50px;
|
||||||
|
margin-top: calc(50vh - 135px);
|
||||||
|
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
box-shadow: 0px 0px 100px rgba(0,0,0,0.15);
|
||||||
|
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
animation-name: pulse;
|
||||||
|
animation-duration: 2s;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
}
|
}
|
||||||
.container-layout .content {
|
|
||||||
max-width: 660px;
|
section.shake {
|
||||||
margin: 0 auto
|
animation-name: shake;
|
||||||
|
animation-duration: 0.5s;
|
||||||
|
animation-iteration-count: 1;
|
||||||
}
|
}
|
||||||
.content .server {
|
|
||||||
position: relative;
|
form label {
|
||||||
margin: 0 10px
|
display: block;
|
||||||
|
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
.content .server .container {
|
|
||||||
background: #fff;
|
form input[type=text] {
|
||||||
-webkit-box-sizing: border-box;
|
width: 300px;
|
||||||
box-sizing: border-box;
|
border: 2px solid #ccc;
|
||||||
padding: 50px 0 0;
|
padding: 10px 10px;
|
||||||
-webkit-border-radius: 4px;
|
|
||||||
border-radius: 4px;
|
outline: none;
|
||||||
position: relative;
|
|
||||||
z-index: 10;
|
transition: all 0.2s ease;
|
||||||
max-width: 580px
|
|
||||||
}
|
}
|
||||||
.content .server h1 {
|
|
||||||
|
form input[type=text]:hover,
|
||||||
|
form input[type=text]:focus {
|
||||||
|
border-color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
form button {
|
||||||
|
padding: 10px 10px;
|
||||||
|
|
||||||
|
background-color: #52c2af;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
border: 2px solid #52c2af;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
form button:hover {
|
||||||
|
background-color: #30b09a;
|
||||||
|
border-color: #30b09a;
|
||||||
|
}
|
||||||
|
|
||||||
|
form button:active {
|
||||||
|
background-color: #14957f;
|
||||||
|
border-color: #14957f;
|
||||||
|
}
|
||||||
|
|
||||||
|
form #error {
|
||||||
|
margin: 5px 0px 0px;
|
||||||
|
|
||||||
|
font-size: 0.8em;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
color: rgb(201, 107, 107);
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-10px);
|
||||||
|
|
||||||
|
height: 15px;
|
||||||
|
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
form #error.show {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- generic components -- */
|
||||||
|
.center {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 0 10%
|
|
||||||
}
|
}
|
||||||
.content .server h1 {
|
|
||||||
font-size: 2.4em;
|
@keyframes pulse {
|
||||||
line-height: 1.2em;
|
0% { box-shadow: 0px 0px 100px rgba(0,0,0,0.15); }
|
||||||
margin-bottom: 10px
|
50% { box-shadow: 0px 0px 100px rgba(0,0,0,0.30); }
|
||||||
|
100% { box-shadow: 0px 0px 100px rgba(0,0,0,0.15); }
|
||||||
}
|
}
|
||||||
.content .server fieldset {
|
|
||||||
padding: 25px 10% 80px 39px;
|
@keyframes shake {
|
||||||
position: relative
|
10%, 90% { transform: translate3d(-1px, 0, 0); }
|
||||||
}
|
20%, 80% { transform: translate3d(2px, 0, 0); }
|
||||||
.content .server fieldset .control-group .control-field input {
|
30%, 50%, 70% { transform: translate3d(-4px, 0, 0); }
|
||||||
width: 100%
|
40%, 60% { transform: translate3d(4px, 0, 0); }
|
||||||
}
|
|
||||||
.content .server button {
|
|
||||||
width: 100%
|
|
||||||
}
|
|
||||||
@media screen and (min-width: 749px) {
|
|
||||||
input[type=text] {
|
|
||||||
width: 60%
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media screen and (min-width: 1071px) {
|
|
||||||
h1 {
|
|
||||||
font-size: 3.2em;
|
|
||||||
line-height: 1.3em
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
width: 1070px;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-right: 10px;
|
|
||||||
}
|
|
||||||
.container:before,
|
|
||||||
.container:after {
|
|
||||||
content: "";
|
|
||||||
display: table
|
|
||||||
}
|
|
||||||
.container:after {
|
|
||||||
clear: both
|
|
||||||
}
|
|
||||||
.responsive .container {
|
|
||||||
max-width: 1070px;
|
|
||||||
width: auto;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-right: 10px;
|
|
||||||
}
|
|
||||||
.responsive .container:before,
|
|
||||||
.responsive .container:after {
|
|
||||||
content: "";
|
|
||||||
display: table
|
|
||||||
}
|
|
||||||
.responsive .container:after {
|
|
||||||
clear: both
|
|
||||||
}
|
|
||||||
@media screen and (max-width: 480px) {
|
|
||||||
.responsive h1 {
|
|
||||||
font-size: 1.7em;
|
|
||||||
line-height: 1.3em
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media screen and (min-width: 481px) and (max-width: 640px) {
|
|
||||||
.responsive h1 {
|
|
||||||
font-size: 1.9em;
|
|
||||||
line-height: 1.3em
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media screen and (min-width: 641px) and (max-width: 748px) {
|
|
||||||
.responsive h1 {
|
|
||||||
font-size: 2.2em;
|
|
||||||
line-height: 1.3em
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media screen and (max-width: 748px) {
|
|
||||||
.responsive input[type=text] {
|
|
||||||
width: 100%
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media screen and (min-width: 749px) and (max-width: 1070px) {
|
|
||||||
.responsive h1 {
|
|
||||||
font-size: 2.6em;
|
|
||||||
line-height: 1.3em
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#server-status {
|
|
||||||
text-align: center;
|
|
||||||
color: #c71212;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,12 +72,3 @@ button:focus {
|
|||||||
left: 25%;
|
left: 25%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pic {
|
|
||||||
width: 20px;
|
|
||||||
left: 36%;
|
|
||||||
margin-left: 4px;
|
|
||||||
top: 63%;
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB |
BIN
app/renderer/img/topography.png
Normal file
BIN
app/renderer/img/topography.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -7,36 +7,24 @@
|
|||||||
<title>Login - Zulip</title>
|
<title>Login - Zulip</title>
|
||||||
<link rel="stylesheet" href="css/main.css" type="text/css" media="screen">
|
<link rel="stylesheet" href="css/main.css" type="text/css" media="screen">
|
||||||
</head>
|
</head>
|
||||||
<body class="container-layout">
|
<body>
|
||||||
<div class="section-main">
|
<div class="center">
|
||||||
<header>
|
|
||||||
<div class="container">
|
|
||||||
<img src="../resources/zulip.png" id="logo"/>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
<hr>
|
|
||||||
<section class="content">
|
|
||||||
<section class="server">
|
<section class="server">
|
||||||
|
<header>
|
||||||
|
<img src="../resources/zulip.png" id="logo"/>
|
||||||
|
<h1>Zulip Login</h1>
|
||||||
|
</header>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Login to Zulip Server</h1>
|
|
||||||
<form id="frm-signInForm" class="form-large" onsubmit="addDomain(); return false">
|
<form id="frm-signInForm" class="form-large" onsubmit="addDomain(); return false">
|
||||||
<fieldset>
|
<label for="url">
|
||||||
<div class="control-group control-required">
|
Zulip Server URL
|
||||||
<div class="control-field">
|
</label>
|
||||||
<input type="text" id="url" autofocus="autofocus" spellcheck="false" placeholder="zulip.tabbott.net">
|
<input type="text" id="url" autofocus="autofocus" spellcheck="false" placeholder="Server URL">
|
||||||
</div>
|
<button type="submit" id="main" class="btn-primary btn-large" value="Submit">Connect</button>
|
||||||
</div>
|
<p id="error"></p>
|
||||||
<div class="control-group">
|
|
||||||
<div class="control-submit">
|
|
||||||
<button type="submit" id="main" class="btn-primary btn-large" value="Submit" onclick="addDomain();">Connect</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p id="server-status"><p>
|
|
||||||
</fieldset>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
80
app/renderer/js/domain.js
Normal file
80
app/renderer/js/domain.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
const {app} = require('electron').remote;
|
||||||
|
const ipcRenderer = require('electron').ipcRenderer;
|
||||||
|
const JsonDB = require('node-json-db');
|
||||||
|
const request = require('request');
|
||||||
|
|
||||||
|
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
|
||||||
|
|
||||||
|
window.addDomain = function () {
|
||||||
|
const el = sel => {
|
||||||
|
return document.querySelector(sel);
|
||||||
|
};
|
||||||
|
|
||||||
|
const $el = {
|
||||||
|
error: el('#error'),
|
||||||
|
main: el('#main'),
|
||||||
|
section: el('section')
|
||||||
|
};
|
||||||
|
|
||||||
|
const event = sel => {
|
||||||
|
return {
|
||||||
|
on: (event, callback) => {
|
||||||
|
document.querySelector(sel).addEventListener(event, callback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const displayError = msg => {
|
||||||
|
$el.error.innerText = msg;
|
||||||
|
$el.error.classList.add('show');
|
||||||
|
$el.section.classList.add('shake');
|
||||||
|
};
|
||||||
|
|
||||||
|
let newDomain = document.getElementById('url').value;
|
||||||
|
newDomain = newDomain.replace(/^https?:\/\//, '');
|
||||||
|
if (newDomain === '') {
|
||||||
|
displayError('Please input a valid URL.');
|
||||||
|
} else {
|
||||||
|
el('#main').innerHTML = 'Checking...';
|
||||||
|
if (newDomain.indexOf('localhost:') >= 0) {
|
||||||
|
const domain = 'http://' + newDomain;
|
||||||
|
const checkDomain = domain + '/static/audio/zulip.ogg';
|
||||||
|
request(checkDomain, (error, response) => {
|
||||||
|
if (!error && response.statusCode !== 404) {
|
||||||
|
document.getElementById('main').innerHTML = 'Connect';
|
||||||
|
db.push('/domain', domain);
|
||||||
|
ipcRenderer.send('new-domain', domain);
|
||||||
|
} else {
|
||||||
|
$el.main.innerHTML = 'Connect';
|
||||||
|
displayError('Not a valid Zulip local server');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// });
|
||||||
|
} else {
|
||||||
|
const domain = 'https://' + newDomain;
|
||||||
|
const checkDomain = domain + '/static/audio/zulip.ogg';
|
||||||
|
|
||||||
|
request(checkDomain, (error, response) => {
|
||||||
|
if (!error && response.statusCode !== 404) {
|
||||||
|
$el.main.innerHTML = 'Connect';
|
||||||
|
db.push('/domain', domain);
|
||||||
|
ipcRenderer.send('new-domain', domain);
|
||||||
|
} else if (error.toString().indexOf('Error: self signed certificate') >= 0) {
|
||||||
|
$el.main.innerHTML = 'Connect';
|
||||||
|
ipcRenderer.send('certificate-err', domain);
|
||||||
|
} else {
|
||||||
|
$el.main.innerHTML = 'Connect';
|
||||||
|
displayError('Not a valid Zulip server');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event('#url').on('input', () => {
|
||||||
|
el('#error').classList.remove('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
event('section').on('animationend', function () {
|
||||||
|
this.classList.remove('shake');
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
const {remote} = require('electron');
|
const {remote} = require('electron');
|
||||||
|
|
||||||
const prefWindow = remote.getCurrentWindow();
|
const prefWindow = remote.getCurrentWindow();
|
||||||
@@ -13,33 +14,56 @@ document.addEventListener('keydown', event => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function addDomain() {
|
window.prefDomain = function () {
|
||||||
const request = require('request');
|
const request = require('request');
|
||||||
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
const ipcRenderer = require('electron').ipcRenderer;
|
const ipcRenderer = require('electron').ipcRenderer;
|
||||||
const JsonDB = require('node-json-db');
|
const JsonDB = require('node-json-db');
|
||||||
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
const {app} = require('electron').remote;
|
const {app} = require('electron').remote;
|
||||||
|
|
||||||
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
|
const db = new JsonDB(app.getPath('userData') + '/domain.json', true, true);
|
||||||
document.getElementById('main').innerHTML = 'checking...';
|
|
||||||
document.getElementById('pic').style.display = 'block';
|
|
||||||
|
|
||||||
let newDomain = document.getElementById('url').value;
|
let newDomain = document.getElementById('url').value;
|
||||||
newDomain = newDomain.replace(/^https?:\/\//, '');
|
newDomain = newDomain.replace(/^https?:\/\//, '');
|
||||||
|
newDomain = newDomain.replace(/^http?:\/\//, '');
|
||||||
|
|
||||||
const domain = 'https://' + newDomain;
|
if (newDomain === '') {
|
||||||
|
document.getElementById('urladded').innerHTML = 'Please input a value';
|
||||||
|
} else {
|
||||||
|
document.getElementById('main').innerHTML = 'Checking...';
|
||||||
|
if (newDomain.indexOf('localhost:') >= 0) {
|
||||||
|
const domain = 'http://' + newDomain;
|
||||||
const checkDomain = domain + '/static/audio/zulip.ogg';
|
const checkDomain = domain + '/static/audio/zulip.ogg';
|
||||||
|
|
||||||
request(checkDomain, (error, response) => {
|
request(checkDomain, (error, response) => {
|
||||||
if (!error && response.statusCode !== 404) {
|
if (!error && response.statusCode !== 404) {
|
||||||
document.getElementById('pic').style.display = 'none';
|
|
||||||
document.getElementById('main').innerHTML = 'Switch';
|
document.getElementById('main').innerHTML = 'Switch';
|
||||||
document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain;
|
document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain;
|
||||||
db.push('/domain', domain);
|
db.push('/domain', domain);
|
||||||
ipcRenderer.send('new-domain', domain);
|
ipcRenderer.send('new-domain', domain);
|
||||||
} else {
|
} else {
|
||||||
document.getElementById('pic').style.display = 'none';
|
|
||||||
document.getElementById('main').innerHTML = 'Switch';
|
document.getElementById('main').innerHTML = 'Switch';
|
||||||
document.getElementById('urladded').innerHTML = 'Not a vaild Zulip Server.';
|
document.getElementById('urladded').innerHTML = 'Not a valid Zulip Local Server.';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
|
const domain = 'https://' + newDomain;
|
||||||
|
const checkDomain = domain + '/static/audio/zulip.ogg';
|
||||||
|
request(checkDomain, (error, response) => {
|
||||||
|
if (!error && response.statusCode !== 404) {
|
||||||
|
document.getElementById('main').innerHTML = 'Switch';
|
||||||
|
document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain;
|
||||||
|
db.push('/domain', domain);
|
||||||
|
ipcRenderer.send('new-domain', domain);
|
||||||
|
} else if (error.toString().indexOf('Error: self signed certificate') >= 0) {
|
||||||
|
document.getElementById('main').innerHTML = 'Switch';
|
||||||
|
ipcRenderer.send('certificate-err', domain);
|
||||||
|
document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain;
|
||||||
|
} else {
|
||||||
|
document.getElementById('main').innerHTML = 'Switch';
|
||||||
|
document.getElementById('urladded').innerHTML = 'Not a valid Zulip Server.';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
69
app/renderer/js/preload.js
Normal file
69
app/renderer/js/preload.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
'use strict';
|
||||||
|
const ipcRenderer = require('electron').ipcRenderer;
|
||||||
|
const {webFrame} = require('electron');
|
||||||
|
const {spellChecker} = require('./spellchecker');
|
||||||
|
|
||||||
|
const _setImmediate = setImmediate;
|
||||||
|
const _clearImmediate = clearImmediate;
|
||||||
|
process.once('loaded', () => {
|
||||||
|
global.setImmediate = _setImmediate;
|
||||||
|
global.clearImmediate = _clearImmediate;
|
||||||
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-unassigned-import
|
||||||
|
require('./domain');
|
||||||
|
// eslint-disable-next-line import/no-unassigned-import
|
||||||
|
require('./tray.js');
|
||||||
|
// Calling Tray.js in renderer process everytime app window loads
|
||||||
|
|
||||||
|
// Handle zooming functionality
|
||||||
|
const zoomIn = () => {
|
||||||
|
webFrame.setZoomFactor(webFrame.getZoomFactor() + 0.1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const zoomOut = () => {
|
||||||
|
webFrame.setZoomFactor(webFrame.getZoomFactor() - 0.1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const zoomActualSize = () => {
|
||||||
|
webFrame.setZoomFactor(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get zooming actions from main process
|
||||||
|
ipcRenderer.on('zoomIn', () => {
|
||||||
|
zoomIn();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('zoomOut', () => {
|
||||||
|
zoomOut();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('zoomActualSize', () => {
|
||||||
|
zoomActualSize();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('log-out', () => {
|
||||||
|
// Create the menu for the below
|
||||||
|
document.querySelector('.dropdown-toggle').click();
|
||||||
|
|
||||||
|
const nodes = document.querySelectorAll('.dropdown-menu li:last-child a');
|
||||||
|
nodes[nodes.length - 1].click();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('shortcut', () => {
|
||||||
|
// Create the menu for the below
|
||||||
|
const node = document.querySelector('a[data-overlay-trigger=keyboard-shortcuts]');
|
||||||
|
// Additional check
|
||||||
|
if (node.text.trim().toLowerCase() === 'keyboard shortcuts') {
|
||||||
|
node.click();
|
||||||
|
} else {
|
||||||
|
// Atleast click the dropdown
|
||||||
|
document.querySelector('.dropdown-toggle').click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// To prevent failing this script on linux we need to load it after the document loaded
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
// Init spellchecker
|
||||||
|
spellChecker();
|
||||||
|
});
|
||||||
27
app/renderer/js/spellchecker.js
Normal file
27
app/renderer/js/spellchecker.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
const {SpellCheckHandler, ContextMenuListener, ContextMenuBuilder} = require('electron-spellchecker');
|
||||||
|
|
||||||
|
function spellChecker() {
|
||||||
|
// Implement spellcheck using electron api
|
||||||
|
window.spellCheckHandler = new SpellCheckHandler();
|
||||||
|
window.spellCheckHandler.attachToInput();
|
||||||
|
|
||||||
|
// Start off as US English
|
||||||
|
window.spellCheckHandler.switchLanguage('en-US');
|
||||||
|
|
||||||
|
const contextMenuBuilder = new ContextMenuBuilder(window.spellCheckHandler);
|
||||||
|
const contextMenuListener = new ContextMenuListener(info => {
|
||||||
|
contextMenuBuilder.showPopupMenu(info);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Clean up events after you navigate away from this page;
|
||||||
|
// otherwise, you may experience errors
|
||||||
|
window.addEventListener('beforeunload', () => {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
spellCheckHandler.unsubscribe();
|
||||||
|
contextMenuListener.unsubscribe();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
spellChecker
|
||||||
|
};
|
||||||
188
app/renderer/js/tray.js
Normal file
188
app/renderer/js/tray.js
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
'use strict';
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const electron = require('electron');
|
||||||
|
|
||||||
|
const {ipcRenderer, remote} = electron;
|
||||||
|
|
||||||
|
const {Tray, Menu, nativeImage} = remote;
|
||||||
|
|
||||||
|
const APP_ICON = path.join(__dirname, '../../resources/tray', 'tray');
|
||||||
|
|
||||||
|
const iconPath = () => {
|
||||||
|
if (process.platform === 'linux') {
|
||||||
|
return APP_ICON + 'linux.png';
|
||||||
|
}
|
||||||
|
return APP_ICON + (process.platform === 'win32' ? 'win.ico' : 'osx.png');
|
||||||
|
};
|
||||||
|
|
||||||
|
let unread = 0;
|
||||||
|
|
||||||
|
const trayIconSize = () => {
|
||||||
|
switch (process.platform) {
|
||||||
|
case 'darwin':
|
||||||
|
return 20;
|
||||||
|
case 'win32':
|
||||||
|
return 100;
|
||||||
|
case 'linux':
|
||||||
|
return 100;
|
||||||
|
default: return 80;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Default config for Icon we might make it OS specific if needed like the size
|
||||||
|
const config = {
|
||||||
|
pixelRatio: window.devicePixelRatio,
|
||||||
|
unreadCount: 0,
|
||||||
|
showUnreadCount: true,
|
||||||
|
unreadColor: '#000000',
|
||||||
|
readColor: '#000000',
|
||||||
|
unreadBackgroundColor: '#B9FEEA',
|
||||||
|
readBackgroundColor: '#B9FEEA',
|
||||||
|
size: trayIconSize(),
|
||||||
|
thick: process.platform === 'win32'
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderCanvas = function (arg) {
|
||||||
|
config.unreadCount = arg;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const SIZE = config.size * config.pixelRatio;
|
||||||
|
const PADDING = SIZE * 0.05;
|
||||||
|
const CENTER = SIZE / 2;
|
||||||
|
const HAS_COUNT = config.showUnreadCount && config.unreadCount;
|
||||||
|
const color = config.unreadCount ? config.unreadColor : config.readColor;
|
||||||
|
const backgroundColor = config.unreadCount ? config.unreadBackgroundColor : config.readBackgroundColor;
|
||||||
|
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.width = SIZE;
|
||||||
|
canvas.height = SIZE;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
// Circle
|
||||||
|
// If (!config.thick || config.thick && HAS_COUNT) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(CENTER, CENTER, (SIZE / 2) - PADDING, 0, 2 * Math.PI, false);
|
||||||
|
ctx.fillStyle = backgroundColor;
|
||||||
|
ctx.fill();
|
||||||
|
ctx.lineWidth = SIZE / (config.thick ? 10 : 20);
|
||||||
|
ctx.strokeStyle = backgroundColor;
|
||||||
|
ctx.stroke();
|
||||||
|
// Count or Icon
|
||||||
|
if (HAS_COUNT) {
|
||||||
|
ctx.fillStyle = color;
|
||||||
|
ctx.textAlign = 'center';
|
||||||
|
if (config.unreadCount > 99) {
|
||||||
|
ctx.font = `${config.thick ? 'bold ' : ''}${SIZE * 0.4}px Helvetica`;
|
||||||
|
ctx.fillText('99+', CENTER, CENTER + (SIZE * 0.15));
|
||||||
|
} else if (config.unreadCount < 10) {
|
||||||
|
ctx.font = `${config.thick ? 'bold ' : ''}${SIZE * 0.5}px Helvetica`;
|
||||||
|
ctx.fillText(config.unreadCount, CENTER, CENTER + (SIZE * 0.20));
|
||||||
|
} else {
|
||||||
|
ctx.font = `${config.thick ? 'bold ' : ''}${SIZE * 0.5}px Helvetica`;
|
||||||
|
ctx.fillText(config.unreadCount, CENTER, CENTER + (SIZE * 0.15));
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(canvas);
|
||||||
|
} else {
|
||||||
|
reject(canvas);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Renders the tray icon as a native image
|
||||||
|
* @param arg: Unread count
|
||||||
|
* @return the native image
|
||||||
|
*/
|
||||||
|
const renderNativeImage = function (arg) {
|
||||||
|
return Promise.resolve()
|
||||||
|
.then(() => renderCanvas(arg))
|
||||||
|
.then(canvas => {
|
||||||
|
const pngData = nativeImage.createFromDataURL(canvas.toDataURL('image/png')).toPng();
|
||||||
|
return Promise.resolve(nativeImage.createFromBuffer(pngData, config.pixelRatio));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const createTray = function () {
|
||||||
|
window.tray = new Tray(iconPath());
|
||||||
|
const contextMenu = Menu.buildFromTemplate([{
|
||||||
|
label: 'About',
|
||||||
|
click() {
|
||||||
|
ipcRenderer.send('trayabout');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Change Zulip server',
|
||||||
|
click() {
|
||||||
|
ipcRenderer.send('traychangeserver');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Reload',
|
||||||
|
click() {
|
||||||
|
remote.getCurrentWindow().reload();
|
||||||
|
window.tray.destroy();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Quit',
|
||||||
|
click() {
|
||||||
|
remote.getCurrentWindow().close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
window.tray.setContextMenu(contextMenu);
|
||||||
|
};
|
||||||
|
|
||||||
|
ipcRenderer.on('destroytray', event => {
|
||||||
|
window.tray.destroy();
|
||||||
|
if (window.tray.isDestroyed()) {
|
||||||
|
window.tray = null;
|
||||||
|
} else {
|
||||||
|
throw new Error('Tray icon not properly destroyed.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return event;
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('tray', (event, arg) => {
|
||||||
|
if (arg === 0) {
|
||||||
|
unread = arg;
|
||||||
|
// Message Count // console.log("message count is zero.");
|
||||||
|
window.tray.setImage(iconPath());
|
||||||
|
window.tray.setToolTip('No unread messages');
|
||||||
|
} else {
|
||||||
|
unread = arg;
|
||||||
|
renderNativeImage(arg).then(image => {
|
||||||
|
window.tray.setImage(image);
|
||||||
|
window.tray.setToolTip(arg + ' unread messages');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.on('toggletray', event => {
|
||||||
|
if (event) {
|
||||||
|
if (window.tray) {
|
||||||
|
window.tray.destroy();
|
||||||
|
if (window.tray.isDestroyed()) {
|
||||||
|
window.tray = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
createTray();
|
||||||
|
renderNativeImage(unread).then(image => {
|
||||||
|
window.tray.setImage(image);
|
||||||
|
window.tray.setToolTip(unread + ' unread messages');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
createTray();
|
||||||
@@ -3,17 +3,14 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="stylesheet" href="css/pref.css">
|
<link rel="stylesheet" href="css/pref.css">
|
||||||
<script type="text/javascript">
|
|
||||||
</script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="close" id="close-button">Close</div>
|
<div class="close" id="close-button">Close</div>
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<form onsubmit="addDomain(); return false">
|
<form onsubmit="prefDomain(); return false">
|
||||||
<input id="url" type="text" placeholder="zulip.example.com">
|
<input id="url" type="text" placeholder="Server URL">
|
||||||
<button type="submit" id="main" value="Submit" onclick="addDomain();">
|
<button type="submit" id="main" value="Submit">
|
||||||
Switch</button>
|
Switch</button>
|
||||||
<img id="pic" src="img/loader.gif" />
|
|
||||||
</form>
|
</form>
|
||||||
<p id="urladded"><p>
|
<p id="urladded"><p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
55
package.json
55
package.json
@@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "zulip",
|
"name": "zulip",
|
||||||
"productName": "Zulip",
|
"productName": "Zulip",
|
||||||
"version": "0.5.2",
|
"version": "0.5.10",
|
||||||
|
"main": "./app/main",
|
||||||
"description": "Zulip Desktop App",
|
"description": "Zulip Desktop App",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"email":"<svnitakash@gmail.com>",
|
"email": "<svnitakash@gmail.com>",
|
||||||
"copyright": "©2016 Kandra Labs, Inc.",
|
"copyright": "©2017 Kandra Labs, Inc.",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Akash Nimare",
|
"name": "Akash Nimare",
|
||||||
"email": "svnitakash@gmail.com"
|
"email": "svnitakash@gmail.com"
|
||||||
@@ -24,30 +25,33 @@
|
|||||||
"dev": "gulp dev",
|
"dev": "gulp dev",
|
||||||
"pack": "build --dir",
|
"pack": "build --dir",
|
||||||
"dist": "build",
|
"dist": "build",
|
||||||
|
"build:win": "build --win nsis-web --ia32 --x64",
|
||||||
"travis": "cd ./scripts && ./travis-build-test.sh"
|
"travis": "cd ./scripts && ./travis-build-test.sh"
|
||||||
},
|
},
|
||||||
"build": {
|
"build": {
|
||||||
"appId": "org.zulip.zulip-electron",
|
"appId": "org.zulip.zulip-electron",
|
||||||
"asar": "true",
|
"asar": true,
|
||||||
"files": [
|
"files": [
|
||||||
"**/*",
|
"**/*",
|
||||||
"!node_modules/@paulcbetts/cld/deps/cld${/*}"
|
"!node_modules/@paulcbetts/cld/deps/cld${/*}"
|
||||||
],
|
],
|
||||||
"copyright": "©2016 Kandra Labs, Inc.",
|
"copyright": "©2017 Kandra Labs, Inc.",
|
||||||
"mac": {
|
"mac": {
|
||||||
"category": "public.app-category.productivity"
|
"category": "public.app-category.productivity"
|
||||||
},
|
},
|
||||||
"linux" : {
|
"linux": {
|
||||||
"synopsis": "Zulip Desktop App",
|
|
||||||
"category": "",
|
"category": "",
|
||||||
"packageCategory": "GNOME;GTK;Network;InstantMessaging",
|
"packageCategory": "GNOME;GTK;Network;InstantMessaging",
|
||||||
"description": "Zulip Desktop Client for Linux",
|
"description": "Zulip Desktop Client for Linux",
|
||||||
"target" : ["deb", "AppImage"],
|
"target": [
|
||||||
"version" : "0.5.1",
|
"deb",
|
||||||
"title" : "Zulip",
|
"AppImage"
|
||||||
"license": "Apache-2.0",
|
],
|
||||||
"maintainer": "Akash Nimare <svnitakash@gmail.com>"
|
"maintainer": "Akash Nimare <svnitakash@gmail.com>"
|
||||||
},
|
},
|
||||||
|
"deb": {
|
||||||
|
"synopsis": "Zulip Desktop App"
|
||||||
|
},
|
||||||
"dmg": {
|
"dmg": {
|
||||||
"background": "build/appdmg.png",
|
"background": "build/appdmg.png",
|
||||||
"icon": "build/icon.icns",
|
"icon": "build/icon.icns",
|
||||||
@@ -69,6 +73,10 @@
|
|||||||
"win": {
|
"win": {
|
||||||
"target": "nsis",
|
"target": "nsis",
|
||||||
"icon": "build/icon.ico"
|
"icon": "build/icon.ico"
|
||||||
|
},
|
||||||
|
"nsis": {
|
||||||
|
"perMachine": true,
|
||||||
|
"oneClick": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -80,15 +88,15 @@
|
|||||||
"InstantMessaging"
|
"InstantMessaging"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"assert": "^1.4.1",
|
"assert": "1.4.1",
|
||||||
"devtron": "^1.1.0",
|
"devtron": "1.4.0",
|
||||||
"electron-builder": "*",
|
"electron-builder": "16.6.0",
|
||||||
"electron": "1.4.7",
|
"electron": "1.4.15",
|
||||||
"electron-connect": "^0.4.6",
|
"electron-connect": "0.4.8",
|
||||||
"gulp": "^3.9.1",
|
"gulp": "3.9.1",
|
||||||
"gulp-mocha": "^3.0.1",
|
"gulp-mocha": "3.0.1",
|
||||||
"spectron": "^3.3.0",
|
"spectron": "3.6.1",
|
||||||
"xo": "*"
|
"xo": "0.18.1"
|
||||||
},
|
},
|
||||||
"xo": {
|
"xo": {
|
||||||
"esnext": true,
|
"esnext": true,
|
||||||
@@ -98,10 +106,13 @@
|
|||||||
"rules": {
|
"rules": {
|
||||||
"max-lines": [
|
"max-lines": [
|
||||||
"warn",
|
"warn",
|
||||||
350
|
500
|
||||||
],
|
],
|
||||||
"no-warning-comments": 0,
|
"no-warning-comments": 0,
|
||||||
"no-else-return": 0
|
"capitalized-comments": 0,
|
||||||
|
"no-else-return": 0,
|
||||||
|
"import/no-unresolved": 0,
|
||||||
|
"import/no-extraneous-dependencies": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||||
|
export {no_proxy,NO_PROXY}="127.0.0.1,localhost"
|
||||||
export DISPLAY=:99.0
|
export DISPLAY=:99.0
|
||||||
sh -e /etc/init.d/xvfb start
|
sh -e /etc/init.d/xvfb start
|
||||||
sleep 3
|
sleep 3
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ const assert = require('assert')
|
|||||||
const Application = require('spectron').Application
|
const Application = require('spectron').Application
|
||||||
|
|
||||||
describe('application launch', function () {
|
describe('application launch', function () {
|
||||||
this.timeout(10000)
|
this.timeout(15000)
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
this.app = new Application({
|
this.app = new Application({
|
||||||
path: require('electron'),
|
path: require('electron'),
|
||||||
args: [__dirname + '/../app/main/index.js']
|
args: [__dirname + '/../app/renderer/index.html']
|
||||||
})
|
})
|
||||||
return this.app.start()
|
return this.app.start()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -74,11 +74,11 @@ gitCheckout()
|
|||||||
}
|
}
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
# {{{ npmUpgradeStart()
|
# {{{ npmInstallStart()
|
||||||
|
|
||||||
npmUpgradeStart()
|
npmInstallStart()
|
||||||
{
|
{
|
||||||
npm upgrade
|
npm install
|
||||||
npm start &
|
npm start &
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,5 +105,5 @@ cleanUp()
|
|||||||
|
|
||||||
envSetup $*
|
envSetup $*
|
||||||
gitCheckout
|
gitCheckout
|
||||||
npmUpgradeStart
|
npmInstallStart
|
||||||
cleanUp
|
cleanUp
|
||||||
Reference in New Issue
Block a user