mirror of
				https://github.com/zulip/zulip-desktop.git
				synced 2025-10-31 20:13:43 +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 | 
							
								
								
									
										24
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -1,12 +1,21 @@ | ||||
| language: node_js | ||||
| sudo: required | ||||
| dist: trusty | ||||
|  | ||||
| os: | ||||
| - osx | ||||
| - linux | ||||
| sudo: required | ||||
|  | ||||
| addons: | ||||
|   apt: | ||||
|     packages: | ||||
|     - build-essential | ||||
|     - libxext-dev | ||||
|     - libxtst-dev | ||||
|     - libxkbfile-dev | ||||
|  | ||||
| language: node_js | ||||
| node_js: | ||||
|   - 'node' | ||||
| - '6' | ||||
|  | ||||
| before_install: | ||||
| - npm install -g gulp | ||||
| @@ -14,7 +23,14 @@ before_install: | ||||
|  | ||||
| cache: | ||||
|   directories: | ||||
|     - node_modules | ||||
|   - node_modules | ||||
|   - app/node_modules | ||||
|  | ||||
| script: | ||||
| - 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! | ||||
|  | ||||
| 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 | ||||
|  | ||||
| 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 | ||||
| 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) | ||||
| 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. | ||||
|   | ||||
							
								
								
									
										15
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								README.md
									
									
									
									
									
								
							| @@ -13,11 +13,13 @@ multi-account, auto-updates etc. | ||||
|  | ||||
| ## Prerequisites | ||||
| * node >= v6.3.1 | ||||
| * npm >= 3.10.3 | ||||
| * If you're on Debian or Ubuntu, you'll also need to install | ||||
| `nodejs-legacy`: | ||||
| > Use [nvm](https://github.com/creationix/nvm) to install the current stable version of node | ||||
|  | ||||
|  | ||||
| * python (v2.7.x recommended) | ||||
| * If you're on Debian or Ubuntu, you'll need to install following packages: | ||||
| ```sh | ||||
| $ sudo apt-get install nodejs-legacy | ||||
| $ sudo apt-get install build-essential libxext-dev libxtst-dev libxkbfile-dev | ||||
| ``` | ||||
|  | ||||
| ## Installation | ||||
| @@ -60,6 +62,8 @@ You can create Windows installer only when running on Windows, the same is true | ||||
|  | ||||
| - [x] Native Notifications | ||||
| - [x] SpellChecker | ||||
| - [x] OSX/Win/Linux installer | ||||
| - [x] Automatic Updates (macOS/Windows) | ||||
| - [x] Keyboard shortcuts | ||||
|  | ||||
| Description            | Keys | ||||
| @@ -69,9 +73,6 @@ Change Zulip Server    | <kbd>Cmd/Ctrl</kbd> <kbd>,</kbd> | ||||
| Back                   | <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 | ||||
|  | ||||
|   | ||||
| @@ -1,49 +1,47 @@ | ||||
| 'use strict'; | ||||
| const {app, autoUpdater, dialog} = require('electron'); | ||||
| const version = app.getVersion(); | ||||
| const os = require('os'); | ||||
| const platform = os.platform() + '_' + os.arch();  // usually returns darwin_64 | ||||
|  | ||||
| const updaterFeedURL = 'http://zulipdesktop.herokuapp.com/update/'+ platform + '/' + version; | ||||
| const {app, dialog} = require('electron'); | ||||
| const {autoUpdater} = require('electron-updater'); | ||||
|  | ||||
| function appUpdater() { | ||||
|  | ||||
| 	autoUpdater.setFeedURL(updaterFeedURL); | ||||
|  | ||||
| 	// Log whats happening | ||||
| 	autoUpdater.on('error', err => console.log(err)) | ||||
|     autoUpdater.on('checking-for-update', () => console.log('checking-for-update')) | ||||
| 	autoUpdater.on('update-available', () => console.log('update-available')) | ||||
| 	autoUpdater.on('update-not-available', () => console.log('update-not-available')) | ||||
| 	const log = require('electron-log'); | ||||
| 	log.transports.file.level = 'info'; | ||||
| 	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 | ||||
| 	autoUpdater.on('update-downloaded', (event, releaseNotes, releaseName, releaseDate) => { | ||||
|  | ||||
| 		let message = app.getName() + ' ' + releaseName + ' is now available. It will be installed the next time you restart the application.'; | ||||
| 		if (releaseNotes) { | ||||
| 			let splitNotes = releaseNotes.split(/[^\r]\n/); | ||||
| 			message += '\n\nRelease notes:\n'; | ||||
| 			splitNotes.forEach(function (notes) { | ||||
| 				message += notes + '\n\n'; | ||||
| 			}) | ||||
| 		}; | ||||
| 	// eslint-disable-next-line no-unused-vars | ||||
| 	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 | ||||
| 		dialog.showMessageBox({ | ||||
| 			type: 'question', | ||||
| 		    buttons: ['Install and Relaunch' ,'Cancel'], | ||||
| 		    defaultId: 0, | ||||
| 		    message: 'A new version of ' + app.getName() + ' has been downloaded', | ||||
| 		    detail: message | ||||
| 		  }, response => { | ||||
| 		  	if (response === 0) { | ||||
| 		  		setTimeout(() => autoUpdater.quitAndInstall(), 1); | ||||
| 		  	} | ||||
| 		  }) | ||||
| 	}) | ||||
| 	// init for updates | ||||
| 	autoUpdater.checkForUpdates() | ||||
| 			buttons: ['Install and Relaunch', 'Later'], | ||||
| 			defaultId: 0, | ||||
| 			message: 'A new version of ' + app.getName() + ' has been downloaded', | ||||
| 			detail: 'It will be installed the next time you restart the application' | ||||
| 		}, response => { | ||||
| 			if (response === 0) { | ||||
| 				setTimeout(() => autoUpdater.quitAndInstall(), 1); | ||||
| 			} | ||||
| 		}); | ||||
| 	}); | ||||
| 	// Init for updates | ||||
| 	autoUpdater.checkForUpdates(); | ||||
| } | ||||
|  | ||||
| exports = module.exports = { | ||||
| module.exports = { | ||||
| 	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'; | ||||
| const path = require('path'); | ||||
| const fs = require('fs'); | ||||
| const os = require('os'); | ||||
| const electron = require('electron'); | ||||
| const {app} = require('electron'); | ||||
| const electronLocalshortcut = require('electron-localshortcut'); | ||||
| 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 isDev = require('electron-is-dev'); | ||||
| const tray = require('./tray'); | ||||
| const appMenu = require('./menu'); | ||||
| 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 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')(); | ||||
|  | ||||
| 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 targetLink; | ||||
|  | ||||
| @@ -31,11 +53,77 @@ const staticURL = 'file://' + path.join(__dirname, '../renderer', 'index.html'); | ||||
| const targetURL = function () { | ||||
| 	if (data.domain === undefined) { | ||||
| 		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(() => { | ||||
| 	if (mainWindow) { | ||||
| 		if (mainWindow.isMinimized()) { | ||||
| @@ -57,6 +145,10 @@ function checkWindowURL() { | ||||
| 	return targetLink; | ||||
| } | ||||
|  | ||||
| function isWindowsOrmacOS() { | ||||
| 	return process.platform === 'darwin' || process.platform === 'win32'; | ||||
| } | ||||
|  | ||||
| const APP_ICON = path.join(__dirname, '../resources', 'Icon'); | ||||
|  | ||||
| const iconPath = () => { | ||||
| @@ -64,8 +156,8 @@ const iconPath = () => { | ||||
| }; | ||||
|  | ||||
| function onClosed() { | ||||
| 	// dereference the window | ||||
| 	// for multiple windows store them in an array | ||||
| 	// Dereference the window | ||||
| 	// For multiple windows, store them in an array | ||||
| 	mainWindow = null; | ||||
| } | ||||
|  | ||||
| @@ -80,6 +172,7 @@ function updateDockBadge(title) { | ||||
| 	if (process.platform === 'darwin') { | ||||
| 		app.setBadgeCount(messageCount); | ||||
| 	} | ||||
| 	mainWindow.webContents.send('tray', messageCount); | ||||
| } | ||||
|  | ||||
| function createMainWindow() { | ||||
| @@ -92,14 +185,24 @@ function createMainWindow() { | ||||
| 		minWidth: 600, | ||||
| 		minHeight: 400, | ||||
| 		webPreferences: { | ||||
| 			preload: path.join(__dirname, 'preload.js'), | ||||
| 			preload: path.join(__dirname, '../renderer/js/preload.js'), | ||||
| 			plugins: true, | ||||
| 			allowDisplayingInsecureContent: true, | ||||
| 			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.setTitle('Zulip'); | ||||
|  | ||||
| @@ -129,7 +232,7 @@ function createMainWindow() { | ||||
| 		}); | ||||
| 	}); | ||||
|  | ||||
| 	// on osx it's 'moved' | ||||
| 	// On osx it's 'moved' | ||||
| 	win.on('move', function () { | ||||
| 		const pos = this.getPosition(); | ||||
| 		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) => { | ||||
| 		e.preventDefault(); | ||||
| 		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; | ||||
| } | ||||
|  | ||||
| // 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', () => { | ||||
| 	// Unregister all the shortcuts so that they don't interfare with other apps | ||||
| 	electronLocalshortcut.unregisterAll(mainWindow); | ||||
| 	if (process.platform !== 'darwin') { | ||||
| 		app.quit(); | ||||
| 	} | ||||
| @@ -165,13 +304,14 @@ app.on('activate', () => { | ||||
| app.on('ready', () => { | ||||
| 	electron.Menu.setApplicationMenu(appMenu); | ||||
| 	mainWindow = createMainWindow(); | ||||
| 	tray.create(mainWindow); | ||||
| 	// Not using for now // tray.create(); | ||||
|  | ||||
| 	const page = mainWindow.webContents; | ||||
|  | ||||
| 	// TODO - use global shortcut instead | ||||
| 	electronLocalshortcut.register(mainWindow, 'CommandOrControl+R', () => { | ||||
| 		mainWindow.reload(); | ||||
| 		mainWindow.webContents.send('destroytray'); | ||||
| 	}); | ||||
|  | ||||
| 	electronLocalshortcut.register(mainWindow, 'CommandOrControl+[', () => { | ||||
| @@ -187,7 +327,7 @@ app.on('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(); | ||||
| 	}); | ||||
|  | ||||
| @@ -200,26 +340,35 @@ app.on('ready', () => { | ||||
| 		electron.shell.openExternal(url); | ||||
| 	}); | ||||
|  | ||||
| 	page.once('did-frame-finish-load', () => { | ||||
| 		const checkOS = isWindowsOrmacOS(); | ||||
| 		if (checkOS && !isDev) { | ||||
| 			// Initate auto-updates on MacOS and Windows | ||||
| 			appUpdater(); | ||||
| 		} | ||||
| 	}); | ||||
| 	checkConnection(); | ||||
| }); | ||||
|  | ||||
| 	page.once("did-frame-finish-load", () => { | ||||
| 	  if (process.platform === 'darwin' && !isDev) { | ||||
| 	  	// Initate auto-updates | ||||
| 	  	appUpdater() | ||||
| 	  } | ||||
| 	}) | ||||
|  | ||||
| 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) => { | ||||
| 	// mainWindow.loadURL(domain); | ||||
| 	// MainWindow.loadURL(domain); | ||||
| 	if (!mainWindow) { | ||||
| 		mainWindow = createMainWindow(); | ||||
| 		mainWindow.loadURL(domain); | ||||
| 		mainWindow.webContents.send('destroytray'); | ||||
| 	} else if (mainWindow.isMinimized()) { | ||||
| 		mainWindow.webContents.send('destroytray'); | ||||
| 		mainWindow.loadURL(domain); | ||||
| 		mainWindow.show(); | ||||
| 	} else { | ||||
| 		mainWindow.webContents.send('destroytray'); | ||||
| 		mainWindow.loadURL(domain); | ||||
| 		serverError(domain); | ||||
| 	} | ||||
| 	targetLink = domain; | ||||
| }); | ||||
|   | ||||
| @@ -10,6 +10,7 @@ function linkIsInternal(currentUrl, newUrl) { | ||||
| // We'll be needing this to open images in default browser | ||||
| const skipImages = '.jpg|.gif|.png|.jpeg|.JPG|.PNG'; | ||||
|  | ||||
| exports = module.exports = { | ||||
| 	linkIsInternal, skipImages | ||||
| module.exports = { | ||||
| 	linkIsInternal, | ||||
| 	skipImages | ||||
| }; | ||||
|   | ||||
| @@ -2,10 +2,13 @@ | ||||
| const os = require('os'); | ||||
| const electron = require('electron'); | ||||
|  | ||||
| const {dialog} = require('electron'); | ||||
|  | ||||
| const app = electron.app; | ||||
| const BrowserWindow = electron.BrowserWindow; | ||||
| const shell = electron.shell; | ||||
| const appName = app.getName(); | ||||
| //	Const tray = require('./tray'); | ||||
|  | ||||
| const {addDomain, about} = require('./windowmanager'); | ||||
|  | ||||
| @@ -19,13 +22,21 @@ function sendAction(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 = [ | ||||
| 	{ | ||||
| 		label: 'Reload', | ||||
| 		accelerator: 'CmdOrCtrl+R', | ||||
| 		click(item, focusedWindow) { | ||||
| 			if (focusedWindow) { | ||||
| 				focusedWindow.reload(); | ||||
| 				focusedWindow.webContents.send('destroytray'); | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
| @@ -65,6 +76,14 @@ const viewSubmenu = [ | ||||
| 	{ | ||||
| 		type: 'separator' | ||||
| 	}, | ||||
| 	{ | ||||
| 		label: 'Toggle Tray Icon', | ||||
| 		click(item, focusedWindow) { | ||||
| 			if (focusedWindow) { | ||||
| 				focusedWindow.webContents.send('toggletray'); | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
| 	{ | ||||
| 		label: 'Toggle Developer Tools', | ||||
| 		accelerator: process.platform === 'darwin' ? 'Alt+Command+I' : 'Ctrl+Shift+I', | ||||
| @@ -135,8 +154,15 @@ const darwinTpl = [ | ||||
| 			{ | ||||
| 				type: 'separator' | ||||
| 			}, | ||||
| 			{ | ||||
| 				label: 'Clear Cache', | ||||
| 				click() { | ||||
| 					clearCache(); | ||||
| 				} | ||||
| 			}, | ||||
| 			{ | ||||
| 				label: 'Log Out', | ||||
| 				accelerator: 'Cmd+L', | ||||
| 				click(item, focusedWindow) { | ||||
| 					if (focusedWindow) { | ||||
| 						sendAction('log-out'); | ||||
| @@ -264,8 +290,15 @@ const otherTpl = [ | ||||
| 			{ | ||||
| 				type: 'separator' | ||||
| 			}, | ||||
| 			{ | ||||
| 				label: 'Clear Cache', | ||||
| 				click() { | ||||
| 					clearCache(); | ||||
| 				} | ||||
| 			}, | ||||
| 			{ | ||||
| 				label: 'Log Out', | ||||
| 				accelerator: 'Ctrl+L', | ||||
| 				click(item, focusedWindow) { | ||||
| 					if (focusedWindow) { | ||||
| 						sendAction('log-out'); | ||||
| @@ -313,7 +346,6 @@ const otherTpl = [ | ||||
| 			{ | ||||
| 				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'; | ||||
| 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 | ||||
| 	// Dereference the window | ||||
| 	domainWindow = null; | ||||
| 	aboutWindow = null; | ||||
| } | ||||
| @@ -14,10 +20,14 @@ function onClosed() { | ||||
| // Change Zulip server Window | ||||
| function createdomainWindow() { | ||||
| 	const domainwin = new electron.BrowserWindow({ | ||||
| 		title: 'Switch Server', | ||||
| 		frame: false, | ||||
| 		height: 300, | ||||
| 		resizable: false, | ||||
| 		width: 400 | ||||
| 		width: 400, | ||||
| 		show: false, | ||||
| 		icon: iconPath() | ||||
|  | ||||
| 	}); | ||||
| 	const domainURL = 'file://' + path.join(__dirname, '../renderer', 'pref.html'); | ||||
| 	domainwin.loadURL(domainURL); | ||||
| @@ -25,13 +35,20 @@ function createdomainWindow() { | ||||
|  | ||||
| 	return domainwin; | ||||
| } | ||||
|  | ||||
| // Call this window onClick addDomain in tray | ||||
| function addDomain() { | ||||
| 	domainWindow = createdomainWindow(); | ||||
| 	domainWindow.show(); | ||||
| 	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({ | ||||
| @@ -48,7 +65,7 @@ function createAboutWindow() { | ||||
| 	aboutwin.loadURL(aboutURL); | ||||
| 	aboutwin.on('closed', onClosed); | ||||
|  | ||||
| 	// stop page to update it's title | ||||
| 	// Stop page to update it's title | ||||
| 	aboutwin.on('page-title-updated', e => { | ||||
| 		e.preventDefault(); | ||||
| 	}); | ||||
| @@ -61,9 +78,23 @@ function createAboutWindow() { | ||||
| // Call this onClick About in tray | ||||
| function about() { | ||||
| 	aboutWindow = createAboutWindow(); | ||||
| 	aboutWindow.show(); | ||||
| 	aboutWindow.once('ready-to-show', () => { | ||||
| 		aboutWindow.show(); | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| exports = module.exports = { | ||||
| 	addDomain, about | ||||
| ipc.on('trayabout', event => { | ||||
| 	if (event) { | ||||
| 		about(); | ||||
| 	} | ||||
| }); | ||||
|  | ||||
| ipc.on('traychangeserver', event => { | ||||
| 	if (event) { | ||||
| 		addDomain(); | ||||
| 	} | ||||
| }); | ||||
| module.exports = { | ||||
| 	addDomain, | ||||
| 	about | ||||
| }; | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| { | ||||
|   "name": "zulip", | ||||
|   "productName": "Zulip", | ||||
|   "version": "0.5.2", | ||||
|   "version": "0.5.10", | ||||
|   "description": "Zulip Desktop App", | ||||
|   "license": "Apache-2.0", | ||||
|   "email":"<svnitakash@gmail.com>", | ||||
|   "copyright": "©2016 Kandra Labs, Inc.", | ||||
|   "email": "<svnitakash@gmail.com>", | ||||
|   "copyright": "©2017 Kandra Labs, Inc.", | ||||
|   "author": { | ||||
|     "name": "Akash Nimare", | ||||
|     "email": "svnitakash@gmail.com" | ||||
| @@ -27,16 +27,16 @@ | ||||
|     "InstantMessaging" | ||||
|   ], | ||||
|   "dependencies": { | ||||
|     "electron-is-dev": "*", | ||||
|     "configstore": "^2.0.0", | ||||
|     "dialogs": "1.1.14", | ||||
|     "electron-context-menu": "0.4.0", | ||||
|     "electron-debug": "^1.0.0", | ||||
|     "electron-dl": "^0.2.0", | ||||
|     "electron-localshortcut": "^0.6.1", | ||||
|     "node-json-db": "^0.7.2", | ||||
|     "request": "^2.74.0", | ||||
|     "electron-spellchecker": "^0.5.12", | ||||
|     "wurl": "^2.1.0" | ||||
|     "electron-config":"0.2.1", | ||||
|     "electron-debug": "1.1.0", | ||||
|     "electron-is-dev": "0.1.2", | ||||
|     "electron-localshortcut": "1.0.0", | ||||
|     "electron-log": "1.3.0", | ||||
|     "electron-spellchecker": "1.0.5", | ||||
|     "electron-updater": "1.11.2", | ||||
|     "https": "^1.0.0", | ||||
|     "node-json-db": "0.7.3", | ||||
|     "request": "2.79.0", | ||||
|     "wurl": "2.1.0" | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -6,17 +6,19 @@ | ||||
| 	</head> | ||||
| 	<body> | ||||
| 	<div class="about"> | ||||
| 		<center><img src="../resources/zulip.png"></center> | ||||
| 		<center><p class="detail" id="version"> Version : ?.?.? </p> | ||||
| 		<center><p class="detail"> License : Apache </p> | ||||
| 		<center><p class="detail"> Maintainer : Zulip </p> | ||||
| 		<p class="left"><a class="bug" onclick="linkInBrowser()" href="#">Found bug?</a></p> | ||||
| 		<img class="logo" src="../resources/zulip.png" /> | ||||
| 		<p class="detail" id="version">version ?.?.?</p> | ||||
| 		<div class="maintenance-info"> | ||||
| 			<p class="detail maintainer">Maintained by Zulip</p> | ||||
| 			<p class="detail license">Available under the Apache License</p> | ||||
| 			<a class="bug" onclick="linkInBrowser()" href="#">Found bug?</a> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 	<script> | ||||
|  | ||||
| 	const app = require('electron').remote.app; | ||||
| 	const version_tag = document.getElementById('version'); | ||||
| 	version_tag.innerHTML = ' Version : ' + app.getVersion() + ' '; | ||||
| 	version_tag.innerHTML = 'version ' + app.getVersion(); | ||||
|  | ||||
| 	function linkInBrowser(event) { | ||||
|  | ||||
|   | ||||
| @@ -1,15 +1,22 @@ | ||||
| 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 { | ||||
| 	margin-top: 50px; | ||||
| } | ||||
|  | ||||
| .left { | ||||
| 	position: absolute; | ||||
| 	top:89%; | ||||
| 	left:76%; | ||||
| 	text-align: center; | ||||
| } | ||||
|  | ||||
| .about p { | ||||
| @@ -18,10 +25,49 @@ body { | ||||
| } | ||||
|  | ||||
| .about img { | ||||
| 	width:160px; | ||||
| 	width: 150px; | ||||
| } | ||||
|  | ||||
| .detail { | ||||
| 	text-align: left; | ||||
| 	margin-left: 35%; | ||||
| } | ||||
| 	text-align: center; | ||||
| } | ||||
|  | ||||
| .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, | ||||
| section { | ||||
|     display: block | ||||
| * { | ||||
|     font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", | ||||
|                  Helvetica, Arial, sans-serif, "Apple Color Emoji", | ||||
|                  "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 { | ||||
|     height: 100%; | ||||
|     margin: 0 | ||||
| } | ||||
| img { | ||||
|     border: 0; | ||||
|     -ms-interpolation-mode: bicubic | ||||
| } | ||||
| img { | ||||
|     vertical-align: middle | ||||
| } | ||||
| form { | ||||
|     margin: 0 | ||||
| } | ||||
| fieldset { | ||||
|     border: 0; | ||||
|     margin: 0; | ||||
|     padding: 0 | ||||
| } | ||||
| button, | ||||
| input { | ||||
|     font-size: 100%; | ||||
|     margin: 0; | ||||
|     vertical-align: baseline; | ||||
|     box-sizing: content-box; | ||||
|     -webkit-box-sizing: content-box | ||||
| } | ||||
| button, | ||||
| input { | ||||
|     line-height: normal | ||||
|     background-image: url(../img/topography.png); | ||||
| } | ||||
|  | ||||
| input, | ||||
| button { | ||||
|     cursor: pointer; | ||||
|     -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 | ||||
|     font-size: 1em; | ||||
| } | ||||
|  | ||||
| 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 { | ||||
|     z-index: 800; | ||||
|     border-bottom: 1px solid #dae0e7; | ||||
|     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 | ||||
|     text-align: center; | ||||
|     margin: 0px 0px 30px 0px; | ||||
| } | ||||
|  | ||||
|  header #logo { | ||||
|     position: absolute!important; | ||||
|     top: 50%; | ||||
|     left: 10px; | ||||
|     -webkit-transform: translate(0, -50%); | ||||
|     transform: translate(0, -50%) | ||||
| header img { | ||||
|     width: 50px; | ||||
| } | ||||
| body.container-layout header #logo { | ||||
|     position: relative!important; | ||||
|     top: 0; | ||||
|     left: 0; | ||||
|     -webkit-transform: translate(0, 0); | ||||
|     transform: translate(0, 0); | ||||
|     margin: 0 auto; | ||||
|     display: block | ||||
|  | ||||
| header h1 { | ||||
|     display: inline-block; | ||||
|     margin: 10px 0px 10px 10px; | ||||
|  | ||||
|     font-weight: 500; | ||||
| } | ||||
| .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; | ||||
|     margin: 0 auto | ||||
|  | ||||
| section.shake { | ||||
|     animation-name: shake; | ||||
|     animation-duration: 0.5s; | ||||
|     animation-iteration-count: 1; | ||||
| } | ||||
| .content .server { | ||||
|     position: relative; | ||||
|     margin: 0 10px | ||||
|  | ||||
| form label { | ||||
|     display: block; | ||||
|  | ||||
|     font-weight: 600; | ||||
|     margin-bottom: 5px; | ||||
| } | ||||
| .content .server .container { | ||||
|     background: #fff; | ||||
|     -webkit-box-sizing: border-box; | ||||
|     box-sizing: border-box; | ||||
|     padding: 50px 0 0; | ||||
|     -webkit-border-radius: 4px; | ||||
|     border-radius: 4px; | ||||
|     position: relative; | ||||
|     z-index: 10; | ||||
|     max-width: 580px | ||||
|  | ||||
| form input[type=text] { | ||||
|     width: 300px; | ||||
|     border: 2px solid #ccc; | ||||
|     padding: 10px 10px; | ||||
|  | ||||
|     outline: none; | ||||
|  | ||||
|     transition: all 0.2s ease; | ||||
| } | ||||
| .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; | ||||
|     padding: 0 10% | ||||
| } | ||||
| .content .server h1 { | ||||
|     font-size: 2.4em; | ||||
|     line-height: 1.2em; | ||||
|     margin-bottom: 10px | ||||
|  | ||||
| @keyframes pulse { | ||||
|     0% { box-shadow: 0px 0px 100px rgba(0,0,0,0.15); } | ||||
|     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; | ||||
|     position: relative | ||||
| } | ||||
| .content .server fieldset .control-group .control-field input { | ||||
|     width: 100% | ||||
| } | ||||
| .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; | ||||
|  | ||||
| @keyframes shake { | ||||
|   10%, 90% { transform: translate3d(-1px, 0, 0); } | ||||
|   20%, 80% { transform: translate3d(2px, 0, 0); } | ||||
|   30%, 50%, 70% { transform: translate3d(-4px, 0, 0); } | ||||
|   40%, 60% { transform: translate3d(4px, 0, 0); } | ||||
| } | ||||
|   | ||||
| @@ -71,13 +71,4 @@ button:focus { | ||||
|     top: -61%; | ||||
|     left: 25%; | ||||
|     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> | ||||
|     <link rel="stylesheet" href="css/main.css" type="text/css" media="screen"> | ||||
|   </head> | ||||
|   <body class="container-layout"> | ||||
|     <div class="section-main"> | ||||
|       <header> | ||||
|         <div class="container"> | ||||
|           <img src="../resources/zulip.png" id="logo"/> | ||||
|     <body> | ||||
|         <div class="center"> | ||||
|             <section class="server"> | ||||
|                 <header> | ||||
|                     <img src="../resources/zulip.png" id="logo"/> | ||||
|                     <h1>Zulip Login</h1> | ||||
|                 </header> | ||||
|                 <div class="container"> | ||||
|                     <form id="frm-signInForm" class="form-large" onsubmit="addDomain(); return false"> | ||||
|                         <label for="url"> | ||||
|                             Zulip Server URL | ||||
|                         </label> | ||||
|                         <input type="text" id="url"  autofocus="autofocus" spellcheck="false" placeholder="Server URL"> | ||||
|                         <button type="submit" id="main" class="btn-primary btn-large" value="Submit">Connect</button> | ||||
|                         <p id="error"></p> | ||||
|                     </form> | ||||
|                 </div> | ||||
|             </section> | ||||
|         </div> | ||||
|       </header> | ||||
|       <hr> | ||||
|       <section class="content"> | ||||
|         <section class="server"> | ||||
|           <div class="container"> | ||||
|             <h1>Login to Zulip Server</h1> | ||||
|             <form id="frm-signInForm" class="form-large" onsubmit="addDomain(); return false"> | ||||
|               <fieldset> | ||||
|                 <div class="control-group control-required"> | ||||
|                   <div class="control-field"> | ||||
|                     <input type="text" id="url"  autofocus="autofocus" spellcheck="false" placeholder="zulip.tabbott.net"> | ||||
|                   </div> | ||||
|                 </div> | ||||
|                 <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> | ||||
|           </div> | ||||
|         </section> | ||||
|       </section> | ||||
|     </div> | ||||
|   </body> | ||||
|     </body> | ||||
| </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'; | ||||
| // eslint-disable-next-line import/no-extraneous-dependencies | ||||
| const {remote} = require('electron'); | ||||
|  | ||||
| const prefWindow = remote.getCurrentWindow(); | ||||
| @@ -13,33 +14,56 @@ document.addEventListener('keydown', event => { | ||||
| 	} | ||||
| }); | ||||
| // eslint-disable-next-line no-unused-vars | ||||
| function addDomain() { | ||||
| window.prefDomain = function () { | ||||
| 	const request = require('request'); | ||||
| 	// eslint-disable-next-line import/no-extraneous-dependencies | ||||
| 	const ipcRenderer = require('electron').ipcRenderer; | ||||
| 	const JsonDB = require('node-json-db'); | ||||
| 	// eslint-disable-next-line import/no-extraneous-dependencies | ||||
| 	const {app} = require('electron').remote; | ||||
|  | ||||
| 	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; | ||||
| 	newDomain = newDomain.replace(/^https?:\/\//, ''); | ||||
| 	newDomain = newDomain.replace(/^http?:\/\//, ''); | ||||
|  | ||||
| 	const domain = 'https://' + newDomain; | ||||
| 	const checkDomain = domain + '/static/audio/zulip.ogg'; | ||||
|  | ||||
| 	request(checkDomain, (error, response) => { | ||||
| 		if (!error && response.statusCode !== 404) { | ||||
| 			document.getElementById('pic').style.display = 'none'; | ||||
| 			document.getElementById('main').innerHTML = 'Switch'; | ||||
| 			document.getElementById('urladded').innerHTML = 'Switched to ' + newDomain; | ||||
| 			db.push('/domain', domain); | ||||
| 			ipcRenderer.send('new-domain', domain); | ||||
| 	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'; | ||||
| 			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 { | ||||
| 					document.getElementById('main').innerHTML = 'Switch'; | ||||
| 					document.getElementById('urladded').innerHTML = 'Not a valid Zulip Local Server.'; | ||||
| 				} | ||||
| 			}); | ||||
| 		} else { | ||||
| 			document.getElementById('pic').style.display = 'none'; | ||||
| 			document.getElementById('main').innerHTML = 'Switch'; | ||||
| 			document.getElementById('urladded').innerHTML = 'Not a vaild Zulip Server.'; | ||||
| 			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,20 +3,17 @@ | ||||
| 	<head> | ||||
| 		<meta charset="UTF-8"> | ||||
| 		<link rel="stylesheet" href="css/pref.css"> | ||||
| 		<script type="text/javascript"> | ||||
| 		</script> | ||||
| 	</head> | ||||
| 	<body> | ||||
| 		<div class="close" id="close-button">Close</div> | ||||
| 		<div class="form"> | ||||
| 			<form onsubmit="addDomain(); return false"> | ||||
| 				<input id="url" type="text" placeholder="zulip.example.com"> | ||||
| 				<button type="submit" id="main" value="Submit" onclick="addDomain();"> | ||||
| 			<form onsubmit="prefDomain(); return false"> | ||||
| 				<input id="url" type="text" placeholder="Server URL"> | ||||
| 				<button type="submit" id="main" value="Submit"> | ||||
| 				Switch</button> | ||||
| 				<img id="pic" src="img/loader.gif" /> | ||||
| 			</form> | ||||
| 			<p id="urladded"><p> | ||||
| 			</div> | ||||
| 			<script src="js/pref.js"></script> | ||||
| 		</body> | ||||
| 	</html> | ||||
| 	</html> | ||||
|   | ||||
							
								
								
									
										67
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,11 +1,12 @@ | ||||
| { | ||||
|   "name": "zulip", | ||||
|   "productName": "Zulip", | ||||
|   "version": "0.5.2", | ||||
|   "version": "0.5.10", | ||||
|   "main": "./app/main", | ||||
|   "description": "Zulip Desktop App", | ||||
|   "license": "Apache-2.0", | ||||
|   "email":"<svnitakash@gmail.com>", | ||||
|   "copyright": "©2016 Kandra Labs, Inc.", | ||||
|   "email": "<svnitakash@gmail.com>", | ||||
|   "copyright": "©2017 Kandra Labs, Inc.", | ||||
|   "author": { | ||||
|     "name": "Akash Nimare", | ||||
|     "email": "svnitakash@gmail.com" | ||||
| @@ -24,30 +25,33 @@ | ||||
|     "dev": "gulp dev", | ||||
|     "pack": "build --dir", | ||||
|     "dist": "build", | ||||
|     "build:win": "build --win nsis-web --ia32 --x64", | ||||
|     "travis": "cd ./scripts && ./travis-build-test.sh" | ||||
|   }, | ||||
|   "build": { | ||||
|     "appId": "org.zulip.zulip-electron", | ||||
|     "asar": "true", | ||||
|     "asar": true, | ||||
|     "files": [ | ||||
|       "**/*", | ||||
|       "!node_modules/@paulcbetts/cld/deps/cld${/*}" | ||||
|     ], | ||||
|     "copyright": "©2016 Kandra Labs, Inc.", | ||||
|     "copyright": "©2017 Kandra Labs, Inc.", | ||||
|     "mac": { | ||||
|       "category": "public.app-category.productivity" | ||||
|     }, | ||||
|     "linux" : { | ||||
|       "synopsis": "Zulip Desktop App", | ||||
|     "linux": { | ||||
|       "category": "", | ||||
|       "packageCategory": "GNOME;GTK;Network;InstantMessaging", | ||||
|       "description": "Zulip Desktop Client for Linux", | ||||
|       "target" : ["deb", "AppImage"], | ||||
|       "version" : "0.5.1", | ||||
|       "title" : "Zulip", | ||||
|       "license": "Apache-2.0", | ||||
|       "target": [ | ||||
|         "deb", | ||||
|         "AppImage" | ||||
|       ], | ||||
|       "maintainer": "Akash Nimare <svnitakash@gmail.com>" | ||||
|     }, | ||||
|     "deb": { | ||||
|       "synopsis": "Zulip Desktop App" | ||||
|     }, | ||||
|     "dmg": { | ||||
|       "background": "build/appdmg.png", | ||||
|       "icon": "build/icon.icns", | ||||
| @@ -69,26 +73,30 @@ | ||||
|     "win": { | ||||
|       "target": "nsis", | ||||
|       "icon": "build/icon.ico" | ||||
|       }, | ||||
|     "nsis": { | ||||
|       "perMachine": true, | ||||
|       "oneClick": false | ||||
|     } | ||||
|   }, | ||||
|   "keywords": [ | ||||
|   	"Zulip", | ||||
|   	"Group Chat app", | ||||
|   	"electron-app", | ||||
|   	"electron", | ||||
|   	"Desktop app", | ||||
|   	"InstantMessaging" | ||||
|     "Zulip", | ||||
|     "Group Chat app", | ||||
|     "electron-app", | ||||
|     "electron", | ||||
|     "Desktop app", | ||||
|     "InstantMessaging" | ||||
|   ], | ||||
|   "devDependencies": { | ||||
|     "assert": "^1.4.1", | ||||
|     "devtron": "^1.1.0", | ||||
|     "electron-builder": "*", | ||||
|     "electron": "1.4.7", | ||||
|     "electron-connect": "^0.4.6", | ||||
|     "gulp": "^3.9.1", | ||||
|     "gulp-mocha": "^3.0.1", | ||||
|     "spectron": "^3.3.0", | ||||
|     "xo": "*" | ||||
|     "assert": "1.4.1", | ||||
|     "devtron": "1.4.0", | ||||
|     "electron-builder": "16.6.0", | ||||
|     "electron": "1.4.15", | ||||
|     "electron-connect": "0.4.8", | ||||
|     "gulp": "3.9.1", | ||||
|     "gulp-mocha": "3.0.1", | ||||
|     "spectron": "3.6.1", | ||||
|     "xo": "0.18.1" | ||||
|   }, | ||||
|   "xo": { | ||||
|     "esnext": true, | ||||
| @@ -98,10 +106,13 @@ | ||||
|         "rules": { | ||||
|           "max-lines": [ | ||||
|             "warn", | ||||
|             350 | ||||
|             500 | ||||
|           ], | ||||
|           "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,7 +1,8 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then | ||||
|   export DISPLAY=:99.0 | ||||
|   export {no_proxy,NO_PROXY}="127.0.0.1,localhost" | ||||
| 	export DISPLAY=:99.0 | ||||
|   sh -e /etc/init.d/xvfb start | ||||
|   sleep 3 | ||||
| fi | ||||
|   | ||||
| @@ -2,12 +2,12 @@ const assert = require('assert') | ||||
| const Application = require('spectron').Application | ||||
|  | ||||
| describe('application launch', function () { | ||||
|   this.timeout(10000) | ||||
|   this.timeout(15000) | ||||
|  | ||||
|   beforeEach(function () { | ||||
|     this.app = new Application({ | ||||
|       path: require('electron'), | ||||
|       args: [__dirname + '/../app/main/index.js'] | ||||
|       args: [__dirname + '/../app/renderer/index.html'] | ||||
|     }) | ||||
|     return this.app.start() | ||||
|   }) | ||||
|   | ||||
| @@ -74,11 +74,11 @@ gitCheckout() | ||||
| } | ||||
| 
 | ||||
| # }}} | ||||
| # {{{ npmUpgradeStart() | ||||
| # {{{ npmInstallStart() | ||||
| 
 | ||||
| npmUpgradeStart() | ||||
| npmInstallStart() | ||||
| { | ||||
| 	npm upgrade | ||||
| 	npm install | ||||
| 	npm start & | ||||
| } | ||||
| 
 | ||||
| @@ -105,5 +105,5 @@ cleanUp() | ||||
| 
 | ||||
| envSetup $* | ||||
| gitCheckout | ||||
| npmUpgradeStart | ||||
| cleanUp | ||||
| npmInstallStart | ||||
| cleanUp | ||||
		Reference in New Issue
	
	Block a user