├── .gitignore ├── .npmignore ├── CHANGELOG.md ├── README.md ├── lib ├── __tests__ │ ├── args.test.js │ └── main.test.js ├── args.js ├── index.js ├── main.js ├── renderer-preload.js └── renderer.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.test.js 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 0.8.1 / 2016-05-14 2 | ------------------ 3 | - removed dep `object-assign`. See: [#14][#14] 4 | 5 | 0.8.0 / 2016-05-11 6 | ------------------ 7 | - **BREAKING CHANGE**: you must at least use Electron v1.0.0. 8 | 9 | 0.7.0 / 2016-05-01 10 | ------------------ 11 | - fix deprecation notice for old Electron [#13][#13] 12 | - Standard upgrade 13 | 14 | 0.6.4 / 2016-04-07 15 | ------------------ 16 | - fix renderer tests v37.5 17 | 18 | 0.6.3 / 2016-04-06 19 | ------------------ 20 | - remove v37 deprecation errors. [#9][#9] 21 | 22 | 0.6.2 / 2015-12-11 23 | ------------------ 24 | - Bug in closing window. See: https://github.com/jprichardson/electron-window/issues/5 https://github.com/jprichardson/electron-window/pull/7 25 | 26 | 0.6.1 / 2015-12-11 27 | ------------------ 28 | - use `loadURL` if available instead of `loadUrl`. See: https://github.com/jprichardson/electron-window/pull/6#issuecomment-163826265 29 | 30 | 0.6.0 / 2015-08-27 31 | ------------------ 32 | - added support for data uris. See: https://github.com/jprichardson/electron-window/pull/2 33 | 34 | 0.5.0 / 2015-07-15 35 | ------------------ 36 | - upgraded to `is-electron-renderer@2.0` (Electron removed `global` for non-node integration) 37 | 38 | 0.4.3 / 2015-07-13 39 | ------------------ 40 | - regression: `showUrl()` without window arguments wouldn't actually show window 41 | 42 | 0.4.2 / 2015-07-10 43 | ------------------ 44 | - made callback optional in `showUrl()` 45 | 46 | 0.4.1 / 2015-07-10 47 | ------------------ 48 | - bug fix: wrong `this context` 49 | 50 | 0.4.0 / 2015-07-09 51 | ------------------ 52 | - Removed passing defaults of `resizable: false` and `frame: true`. 53 | - refactored, added tests 54 | 55 | 0.3.0 / 2015-05-27 56 | ------------------ 57 | - `showUrl()`: actually display window when contents loaded 58 | 59 | 0.2.1 / 2015-05-22 60 | ------------------ 61 | - fixed package.json main path bug 62 | 63 | 0.2.0 / 2015-05-22 64 | ------------------ 65 | - changed so `window.__args__` would be available right away 66 | - changed examples 67 | - exposed `parseArgs()` for renderer scripts 68 | 69 | 0.1.1 / 2015-05-22 70 | ------------------ 71 | - fix `package.json` Github repo 72 | 73 | 0.1.0 / 2015-05-22 74 | ------------------ 75 | - initial release 76 | 77 | 78 | 79 | [#19]: https://github.com/jprichardson/electron-window/pull/19 "Use Electron 1.0 API consistently" 80 | [#18]: https://github.com/jprichardson/electron-window/pull/18 "Support Electron 1.0" 81 | [#17]: https://github.com/jprichardson/electron-window/pull/17 "Update README" 82 | [#16]: https://github.com/jprichardson/electron-window/issues/16 "Update README" 83 | [#15]: https://github.com/jprichardson/electron-window/issues/15 "Electron complains on launch: (electron) options.preload is deprecated. Use options.webPreferences.preload instead." 84 | [#14]: https://github.com/jprichardson/electron-window/issues/14 "Remove object-assign dependency." 85 | [#13]: https://github.com/jprichardson/electron-window/pull/13 "Use opts.preload when Electron version is less than 0.37.3" 86 | [#12]: https://github.com/jprichardson/electron-window/pull/12 "removed options.preload deprecation errors." 87 | [#11]: https://github.com/jprichardson/electron-window/issues/11 "replace options.preload with options.webPreferences.preload" 88 | [#10]: https://github.com/jprichardson/electron-window/pull/10 "Fix preload scripts in electron-window" 89 | [#9]: https://github.com/jprichardson/electron-window/pull/9 "Remove 0.37 deprecation warnings" 90 | [#8]: https://github.com/jprichardson/electron-window/issues/8 "Deprecated Url methods in favor of URL (following Electron convention)" 91 | [#7]: https://github.com/jprichardson/electron-window/pull/7 "Remove window reference on `close` instead of `closed`" 92 | [#6]: https://github.com/jprichardson/electron-window/pull/6 "Change win.loadUrl to win.loadURL" 93 | [#5]: https://github.com/jprichardson/electron-window/issues/5 "Error message when closing window" 94 | [#4]: https://github.com/jprichardson/electron-window/issues/4 "loadUrl deprecation in BrowserWindow" 95 | [#3]: https://github.com/jprichardson/electron-window/pull/3 "added `showUrl` `show` arg" 96 | [#2]: https://github.com/jprichardson/electron-window/pull/2 "added datauri case and test" 97 | [#1]: https://github.com/jprichardson/electron-window/issues/1 "BrowserWindow Methods?" 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | electron-window 2 | =============== 3 | 4 | Convenience methods for Electron windows. 5 | 6 | 7 | Installation 8 | ------------ 9 | 10 | npm i --save electron-window 11 | 12 | 13 | Usage 14 | ----- 15 | 16 | ### TL;DR: 17 | 18 | `electron-window` converts this: 19 | 20 | ```js 21 | const { 22 | app, 23 | BrowserWindow 24 | } = require('electron') 25 | 26 | const path = require('path') 27 | const url = require('url') 28 | 29 | // Keep a global reference of the window object, if you don't, the window will 30 | // be closed automatically when the javascript object is GCed. 31 | let mainWindow = null 32 | 33 | app.on('ready', () => { 34 | mainWindow = new BrowserWindow({ width: 1000, height: 400, show: false }) 35 | 36 | const someArgs = { data: 'hi' } 37 | const indexPath = path.resolve(__dirname, '..', 'weird-location', 'index.html') 38 | const indexUrl = url.format({ 39 | protocol: 'file', 40 | pathname: indexPath, 41 | slashes: true, 42 | hash: encodeURIComponent(JSON.stringify(someArgs)) 43 | }) 44 | 45 | mainWindow.on('closed', () => { 46 | mainWindow = null 47 | }) 48 | 49 | mainWindow.webContents.on('did-finish-load', () => { 50 | mainWindow.show() 51 | console.log('window is now visible!') 52 | }) 53 | 54 | mainWindow.loadUrl(indexUrl) 55 | }) 56 | ``` 57 | 58 | to this: 59 | 60 | ```js 61 | const { app } = require('electron') 62 | const path = require('path') 63 | const window = require('electron-window') 64 | 65 | app.on('ready', () => { 66 | const mainWindow = window.createWindow({ width: 1000, height: 400 }) 67 | const someArgs = { data: 'hi' } 68 | const indexPath = path.resolve(__dirname, '..', 'weird-location', 'index.html') 69 | 70 | mainWindow.showUrl(indexPath, someArgs, () => { 71 | console.log('window is now visible!') 72 | }) 73 | }) 74 | ``` 75 | 76 | 77 | ### API Methods 78 | 79 | #### createWindow(options) 80 | 81 | Class method that creates a new [BrowserWindow](https://github.com/atom/electron/blob/master/docs/api/browser-window.md) with 82 | the following default `options`: `{ show: false }`. No need to worry about keeping a global reference 83 | to prevent garbage collection, this is handled for you. 84 | 85 | 86 | #### parseArgs() 87 | 88 | Instance method to parse arguments in window. You would only need to call from your renderer preload script if you pass in 89 | [`preload`](https://github.com/atom/electron/blob/master/docs/api/browser-window.md#new-browserwindowoptions). 90 | 91 | 92 | #### showUrl(httpOrFileUrl, [argsForRenderer], [callback]) 93 | 94 | Instance method that shows the url. When the url is finished loading, the callback is returned. If the optional `argsForRenderer` is set 95 | then `__args__` will be a global object for the page in the renderer process. This is a convenient way to pass 96 | arguments from the main process to the renderer process. 97 | 98 | 99 | #### unref() 100 | 101 | Instance method to call if you ever want to remove the global reference. Should only need to be called if 102 | [`destroy()`](https://github.com/atom/electron/blob/master/docs/api/browser-window.md#browserwindowdestroy) is ever called. 103 | Most likely, you won't need to use this. 104 | 105 | 106 | ### API Properties 107 | 108 | #### windows 109 | 110 | Class property to get a reference to all windows created and their ids. This is in the form of an object where the keys are window ids, and the values are instances of `BrowserWindow`. 111 | 112 | 113 | 114 | ### Example 115 | 116 | **main process** 117 | 118 | ```js 119 | const window = require('electron-window') 120 | 121 | const windowOptions = { 122 | width: 1000, 123 | height: 400 124 | } 125 | 126 | const mainWindow = window.createWindow(windowOptions) 127 | 128 | // can access at window.__args__ from scripts 129 | // ran from index.html 130 | const args = { 131 | data: 'some secret data' 132 | } 133 | 134 | mainWindow.showUrl('index.html', args, () => { 135 | console.log('the window should be showing with the contents of the URL now') 136 | }) 137 | ``` 138 | 139 | **renderer process** 140 | 141 | ```js 142 | // only call if `preload` is set in `windowOptions` 143 | require('electron-window').parseArgs() 144 | 145 | console.log(window.__args__) 146 | // => Object {data: "some secret data"} 147 | ``` 148 | 149 | 150 | License 151 | ------- 152 | 153 | MIT 154 | 155 | 156 | -------------------------------------------------------------------------------- /lib/__tests__/args.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var args = require('../args') 3 | 4 | /* global describe it */ 5 | 6 | describe('args', function () { 7 | describe('encode()', function () { 8 | it('should hash encode object', function () { 9 | var obj = {name: 'jp'} 10 | var str = args.encode(obj) 11 | assert.strictEqual(str, '%7B%22name%22%3A%22jp%22%7D') 12 | 13 | str = args.encode(null) 14 | assert.strictEqual(str, '') 15 | }) 16 | }) 17 | 18 | describe('urlWithArgs()', function () { 19 | describe('> when url', function () { 20 | it('should create a url with encoded args in hash', function () { 21 | var url = args.urlWithArgs('http://google.com', {doThat: 'ok'}) 22 | assert.strictEqual(url, 'http://google.com/#%7B%22doThat%22%3A%22ok%22%7D') 23 | 24 | url = args.urlWithArgs('http://google.com') 25 | assert.strictEqual(url, 'http://google.com/') 26 | }) 27 | }) 28 | 29 | describe('> when file', function () { 30 | it('should create a url with encoded args in hash', function () { 31 | var url = args.urlWithArgs('/tmp/index.html', {doThat: 'ok'}) 32 | assert.strictEqual(url, 'file:///tmp/index.html#%7B%22doThat%22%3A%22ok%22%7D') 33 | 34 | url = args.urlWithArgs('/tmp/index.html') 35 | assert.strictEqual(url, 'file:///tmp/index.html') 36 | }) 37 | }) 38 | 39 | describe('> when data uri', function () { 40 | it('should create a url with encoded args in hash', function () { 41 | var uri = 'data:text/plain;charset=utf-8;base64,dGhpcyBpcyBhIHRlc3QK' 42 | var url = args.urlWithArgs(uri, {doThat: 'ok'}) 43 | assert.strictEqual(url, uri + '#%7B%22doThat%22%3A%22ok%22%7D') 44 | 45 | url = args.urlWithArgs(uri) 46 | assert.strictEqual(url, uri) 47 | }) 48 | }) 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /lib/__tests__/main.test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var EventEmitter = require('events').EventEmitter 3 | var proxyquire = require('proxyquire') 4 | // var stubo = require('stubo') 5 | 6 | /* global describe it */ 7 | 8 | describe('main', function () { 9 | describe('_createWindow()', function () { 10 | it('should should create the window with options and set global window references', function () { 11 | function BrowserWindow (options) { this.id = 5; this._captureOptions = options } 12 | var stubs = { 13 | electron: { 14 | BrowserWindow: BrowserWindow 15 | } 16 | } 17 | stubs.electron['@noCallThru'] = true 18 | var main = proxyquire('../main', stubs) 19 | 20 | var win = main._createWindow({frame: 'something'}) 21 | assert(win instanceof BrowserWindow) 22 | assert.strictEqual(main.windows['5'], win) 23 | assert.strictEqual(win._captureOptions.frame, 'something') 24 | }) 25 | }) 26 | 27 | describe('_loadURLWithArgs()', function () { 28 | it('should load url and callback when finished', function (done) { 29 | var stubs = { electron: { BrowserWindow: {} } } 30 | stubs.electron['@noCallThru'] = true 31 | var main = proxyquire('../main', stubs) 32 | 33 | var win = { 34 | webContents: new EventEmitter(), 35 | loadURL: function () { 36 | this.webContents.emit('did-finish-load') 37 | } 38 | } 39 | 40 | var fn = main._loadURLWithArgs.bind(win) 41 | fn('http://somesite.com', {}, function () { 42 | done() 43 | }) 44 | }) 45 | }) 46 | 47 | describe('_unref()', function () { 48 | it('should delete global reference', function () { 49 | var stubs = { electron: { BrowserWindow: {} } } 50 | stubs.electron['@noCallThru'] = true 51 | var main = proxyquire('../main', stubs) 52 | 53 | var win = {id: 3} 54 | main.windows[win.id] = win 55 | assert.strictEqual(main.windows[3], win) 56 | assert.strictEqual(Object.keys(main.windows).length, 1) 57 | 58 | main._unref.call(win) 59 | assert.strictEqual(main.windows[3], undefined) 60 | assert.strictEqual(Object.keys(main.windows).length, 0) 61 | }) 62 | }) 63 | }) 64 | -------------------------------------------------------------------------------- /lib/args.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | var path = require('path') 3 | var url = require('url') 4 | 5 | function encode (args) { 6 | args = args || null 7 | assert.strictEqual(typeof args, 'object', 'args must be an object') 8 | // stringify the args 9 | args = args ? encodeURIComponent(JSON.stringify(args)) : '' 10 | return args 11 | } 12 | 13 | function urlWithArgs (urlOrFile, args) { 14 | args = encode(args) 15 | 16 | var u 17 | if (urlOrFile.indexOf('http') === 0 || urlOrFile.indexOf('data') === 0) { 18 | var urlData = url.parse(urlOrFile) 19 | var hash = urlData.hash || args ? args : undefined 20 | u = url.format(Object.assign(urlData, { hash: hash })) 21 | } else { // presumably a file url 22 | u = url.format({ 23 | protocol: 'file', 24 | pathname: path.resolve(urlOrFile), 25 | slashes: true, 26 | hash: args || undefined 27 | }) 28 | } 29 | 30 | return u 31 | } 32 | 33 | module.exports = { 34 | encode: encode, 35 | urlWithArgs: urlWithArgs 36 | } 37 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | if (require('is-electron-renderer')) { 2 | module.exports = require('./renderer') 3 | } else { 4 | module.exports = require('./main') 5 | } 6 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var BrowserWindow = require('electron').BrowserWindow 3 | var wargs = require('./args') 4 | 5 | // retain global references, if not, window will be closed automatically when 6 | // garbage collected 7 | var _windows = {} 8 | 9 | function _createWindow (options) { 10 | var opts = Object.assign({ 11 | show: false 12 | }, options) 13 | 14 | opts.webPreferences = Object.assign({ 15 | preload: path.join(__dirname, 'renderer-preload') 16 | }, options.webPreferences) 17 | 18 | var window = new BrowserWindow(opts) 19 | _windows[window.id] = window 20 | 21 | return window 22 | } 23 | 24 | // should not need to be called directly, but just in case 25 | // window.destroy() is ever called 26 | function _unref () { 27 | delete _windows[this.id] 28 | } 29 | 30 | function _loadURLWithArgs (httpOrFileUrl, args, callback) { 31 | if (typeof args === 'function') { 32 | callback = args 33 | args = null 34 | } 35 | 36 | var win = this 37 | win.webContents.once('did-finish-load', function () { 38 | callback.apply(this, arguments) 39 | }) 40 | 41 | var url = wargs.urlWithArgs(httpOrFileUrl, args) 42 | 43 | win.loadURL(url) 44 | } 45 | 46 | function createWindow (options) { 47 | var window = _createWindow(options) 48 | window.unref = _unref.bind(window) 49 | window.once('close', window.unref) 50 | window._loadURLWithArgs = _loadURLWithArgs.bind(window) 51 | 52 | window.showURL = function (httpOrFileUrl, args, callback) { 53 | if (typeof args === 'function') { 54 | callback = args 55 | args = null 56 | } 57 | 58 | window._loadURLWithArgs(httpOrFileUrl, args, function () { 59 | window.show() 60 | callback && callback.apply(this, arguments) 61 | }) 62 | } 63 | 64 | window.showUrl = window.showURL // backwards-compatibility 65 | 66 | return window 67 | } 68 | 69 | module.exports = { 70 | createWindow: createWindow, 71 | windows: _windows, 72 | _createWindow: _createWindow, 73 | _loadURLWithArgs: _loadURLWithArgs, 74 | _loadUrlWithArgs: _loadURLWithArgs, // backwards-compatibility 75 | _unref: _unref 76 | } 77 | -------------------------------------------------------------------------------- /lib/renderer-preload.js: -------------------------------------------------------------------------------- 1 | // fired from 'preload' in context of window renderer 2 | if (require('is-electron-renderer')) { 3 | require('./renderer').parseArgs() 4 | } 5 | -------------------------------------------------------------------------------- /lib/renderer.js: -------------------------------------------------------------------------------- 1 | // executed in context of window renderer 2 | function parseArgs () { 3 | if (!window.location.hash) { 4 | window.__args__ = {} 5 | } else { 6 | var hash = window.location.hash.slice(1) 7 | window.__args__ = Object.freeze(JSON.parse(decodeURIComponent(hash))) 8 | } 9 | } 10 | 11 | module.exports = { 12 | parseArgs: parseArgs 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-window", 3 | "version": "0.8.1", 4 | "description": "Convenience methods for Electron windows.", 5 | "main": "./lib/index.js", 6 | "scripts": { 7 | "test": "standard && find ./lib -name *.test.js | xargs mocha" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/jprichardson/electron-window" 12 | }, 13 | "keywords": [ 14 | "window", 15 | "atom", 16 | "atom-shell", 17 | "electron", 18 | "gui", 19 | "electron-component" 20 | ], 21 | "author": "JP Richardson", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/jprichardson/electron-window/issues" 25 | }, 26 | "homepage": "https://github.com/jprichardson/electron-window", 27 | "devDependencies": { 28 | "mocha": "2.x", 29 | "proxyquire": "^1.6.0", 30 | "standard": "^6.0.8", 31 | "stubo": "^0.1.0" 32 | }, 33 | "dependencies": { 34 | "is-electron-renderer": "^2.0.0" 35 | } 36 | } 37 | --------------------------------------------------------------------------------