From be88c87b2560f0ae2afd668d9c10cadde0a4ebc3 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 30 Mar 2017 18:30:24 -0700 Subject: extension - prefer extensionizer module --- app/scripts/contentscript.js | 2 +- development/mockExtension.js | 2 +- ui/app/components/account-info-link.js | 2 +- ui/app/components/buy-button-subview.js | 2 +- ui/app/components/shift-list-item.js | 2 +- ui/app/components/transaction-list-item.js | 2 +- ui/app/info.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 9a390e580..4d7e682d3 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -2,7 +2,7 @@ const LocalMessageDuplexStream = require('post-message-stream') const PongStream = require('ping-pong-stream/pong') const PortStream = require('./lib/port-stream.js') const ObjectMultiplex = require('./lib/obj-multiplex') -const extension = require('./lib/extension') +const extension = require('extensionizer') const fs = require('fs') const path = require('path') diff --git a/development/mockExtension.js b/development/mockExtension.js index 509487cce..55799b2bf 100644 --- a/development/mockExtension.js +++ b/development/mockExtension.js @@ -4,7 +4,7 @@ * and stubbing out all the extension methods with appropriate mocks. */ -const extension = require('../app/scripts/lib/extension') +const extension = require('extensionizer') const noop = function () {} const apis = [ diff --git a/ui/app/components/account-info-link.js b/ui/app/components/account-info-link.js index 49c42e9ec..74bc7f40e 100644 --- a/ui/app/components/account-info-link.js +++ b/ui/app/components/account-info-link.js @@ -3,7 +3,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const Tooltip = require('./tooltip') const genAccountLink = require('../../lib/account-link') -const extension = require('../../../app/scripts/lib/extension') +const extension = require('extensionizer') module.exports = AccountInfoLink diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js index 7b993110d..19279d1f6 100644 --- a/ui/app/components/buy-button-subview.js +++ b/ui/app/components/buy-button-subview.js @@ -5,7 +5,7 @@ const connect = require('react-redux').connect const actions = require('../actions') const CoinbaseForm = require('./coinbase-form') const ShapeshiftForm = require('./shapeshift-form') -const extension = require('../../../app/scripts/lib/extension') +const extension = require('extensionizer') const Loading = require('./loading') const TabBar = require('./tab-bar') diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index e0243e247..da991f75f 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -4,7 +4,7 @@ const h = require('react-hyperscript') const connect = require('react-redux').connect const vreme = new (require('vreme')) const explorerLink = require('../../lib/explorer-link') -const extension = require('../../../app/scripts/lib/extension') +const extension = require('extensionizer') const actions = require('../actions') const addressSummary = require('../util').addressSummary diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js index ee32be7d3..0052d9c70 100644 --- a/ui/app/components/transaction-list-item.js +++ b/ui/app/components/transaction-list-item.js @@ -7,7 +7,7 @@ const addressSummary = require('../util').addressSummary const explorerLink = require('../../lib/explorer-link') const CopyButton = require('./copyButton') const vreme = new (require('vreme')) -const extension = require('../../../app/scripts/lib/extension') +const extension = require('extensionizer') const Tooltip = require('./tooltip') const TransactionIcon = require('./transaction-list-item-icon') diff --git a/ui/app/info.js b/ui/app/info.js index e79580be4..fa51ae41c 100644 --- a/ui/app/info.js +++ b/ui/app/info.js @@ -3,7 +3,7 @@ const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect const actions = require('./actions') -const extension = require('../../app/scripts/lib/extension') +const extension = require('extensionizer') module.exports = connect(mapStateToProps)(InfoScreen) -- cgit From 5036263f88a1f61957982b64d27472a516c28def Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 30 Mar 2017 18:33:19 -0700 Subject: introduce platform api and rename notifications to notification-manager --- app/scripts/background.js | 13 ++++-- app/scripts/lib/notification-manager.js | 74 +++++++++++++++++++++++++++++++++ app/scripts/lib/notifications.js | 67 ----------------------------- app/scripts/metamask-controller.js | 14 ++++--- app/scripts/platforms/extension.js | 19 +++++++++ app/scripts/popup.js | 8 ++-- ui/app/reducers/app.js | 2 +- 7 files changed, 117 insertions(+), 80 deletions(-) create mode 100644 app/scripts/lib/notification-manager.js delete mode 100644 app/scripts/lib/notifications.js create mode 100644 app/scripts/platforms/extension.js diff --git a/app/scripts/background.js b/app/scripts/background.js index 254737dec..5fb56d497 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -4,12 +4,13 @@ const asyncQ = require('async-q') const pipe = require('pump') const LocalStorageStore = require('obs-store/lib/localStorage') const storeTransform = require('obs-store/lib/transform') +const ExtensionPlatform = require('./platforms/extension') const Migrator = require('./lib/migrator/') const migrations = require('./migrations/') const PortStream = require('./lib/port-stream.js') -const notification = require('./lib/notifications.js') +const NotificationManager = require('./lib/notification-manager.js') const MetamaskController = require('./metamask-controller') -const extension = require('./lib/extension') +const extension = require('extensionizer') const firstTimeState = require('./first-time-state') const STORAGE_KEY = 'metamask-config' @@ -19,6 +20,10 @@ const log = require('loglevel') window.log = log log.setDefaultLevel(METAMASK_DEBUG ? 'debug' : 'warn') +const platform = new ExtensionPlatform() +const notificationManager = new NotificationManager() +global.METAMASK_NOTIFIER = notificationManager + let popupIsOpen = false // state persistence @@ -68,6 +73,8 @@ function setupController (initState) { showUnapprovedTx: triggerUi, // initial state initState, + // platform specific api + platform, }) global.metamaskController = controller @@ -140,7 +147,7 @@ function setupController (initState) { // popup trigger function triggerUi () { - if (!popupIsOpen) notification.show() + if (!popupIsOpen) notificationManager.show() } // On first install, open a window to MetaMask website to how-it-works. diff --git a/app/scripts/lib/notification-manager.js b/app/scripts/lib/notification-manager.js new file mode 100644 index 000000000..ff8a4b2e5 --- /dev/null +++ b/app/scripts/lib/notification-manager.js @@ -0,0 +1,74 @@ +const extension = require('extensionizer') +const height = 520 +const width = 360 + + +class NotificationManager { + + // + // Public + // + + show () { + this.getPopup((err, popup) => { + if (err) throw err + + if (popup) { + // bring focus to existing popup + extension.windows.update(popup.id, { focused: true }) + } else { + // create new popup + extension.windows.create({ + url: 'notification.html', + type: 'popup', + width, + height, + }) + .catch((reason) => { + log.error('failed to create poupup', reason) + }) + } + }) + } + + getPopup (cb) { + this._getWindows((err, windows) => { + if (err) throw err + cb(null, this._getPopupIn(windows)) + }) + } + + closePopup () { + this.getPopup((err, popup) => { + if (err) throw err + if (!popup) return + extension.windows.remove(popup.id, console.error) + }) + } + + // + // Private + // + + _getWindows (cb) { + // Ignore in test environment + if (!extension.windows) { + return cb() + } + + extension.windows.getAll({}, (windows) => { + cb(null, windows) + }) + } + + _getPopupIn (windows) { + return windows ? windows.find((win) => { + return (win && win.type === 'popup' && + win.height === height && + win.width === width) + }) : null + } + +} + +module.exports = NotificationManager \ No newline at end of file diff --git a/app/scripts/lib/notifications.js b/app/scripts/lib/notifications.js deleted file mode 100644 index 0ec01f3a7..000000000 --- a/app/scripts/lib/notifications.js +++ /dev/null @@ -1,67 +0,0 @@ -const extension = require('./extension') -const height = 520 -const width = 360 - -const notifications = { - show, - getPopup, - closePopup, -} -module.exports = notifications -window.METAMASK_NOTIFIER = notifications - -function show () { - getPopup((err, popup) => { - if (err) throw err - - if (popup) { - // bring focus to existing popup - extension.windows.update(popup.id, { focused: true }) - } else { - // create new popup - extension.windows.create({ - url: 'notification.html', - type: 'popup', - width, - height, - }) - .catch((reason) => { - log.error('failed to create poupup', reason) - }) - } - }) -} - -function getWindows (cb) { - // Ignore in test environment - if (!extension.windows) { - return cb() - } - - extension.windows.getAll({}, (windows) => { - cb(null, windows) - }) -} - -function getPopup (cb) { - getWindows((err, windows) => { - if (err) throw err - cb(null, getPopupIn(windows)) - }) -} - -function getPopupIn (windows) { - return windows ? windows.find((win) => { - return (win && win.type === 'popup' && - win.height === height && - win.width === width) - }) : null -} - -function closePopup () { - getPopup((err, popup) => { - if (err) throw err - if (!popup) return - extension.windows.remove(popup.id, console.error) - }) -} diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 03ea104e0..af8b4688d 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -20,7 +20,6 @@ const MessageManager = require('./lib/message-manager') const PersonalMessageManager = require('./lib/personal-message-manager') const TxManager = require('./transaction-manager') const ConfigManager = require('./lib/config-manager') -const extension = require('./lib/extension') const autoFaucet = require('./lib/auto-faucet') const nodeify = require('./lib/nodeify') const accountImporter = require('./account-import-strategies') @@ -34,6 +33,9 @@ module.exports = class MetamaskController extends EventEmitter { this.opts = opts let initState = opts.initState || {} + // platform-specific api + this.platform = opts.platform + // observable state store this.store = new ObservableStore(initState) @@ -629,7 +631,7 @@ module.exports = class MetamaskController extends EventEmitter { break } - if (url) extension.tabs.create({ url }) + if (url) this.platform.openWindow({ url }) } createShapeShiftTx (depositAddress, depositType) { @@ -647,7 +649,7 @@ module.exports = class MetamaskController extends EventEmitter { setDefaultRpc () { this.configManager.setRpcTarget('http://localhost:8545') - extension.runtime.reload() + this.platform.reload() this.lookupNetwork() return Promise.resolve('http://localhost:8545') } @@ -656,7 +658,7 @@ module.exports = class MetamaskController extends EventEmitter { this.configManager.setRpcTarget(rpcTarget) return this.preferencesController.updateFrequentRpcList(rpcTarget) .then(() => { - extension.runtime.reload() + this.platform.reload() this.lookupNetwork() return Promise.resolve(rpcTarget) }) @@ -664,13 +666,13 @@ module.exports = class MetamaskController extends EventEmitter { setProviderType (type) { this.configManager.setProviderType(type) - extension.runtime.reload() + this.platform.reload() this.lookupNetwork() } useEtherscanProvider () { this.configManager.useEtherscanProvider() - extension.runtime.reload() + this.platform.reload() } getNetworkState () { diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js new file mode 100644 index 000000000..cbb35768e --- /dev/null +++ b/app/scripts/platforms/extension.js @@ -0,0 +1,19 @@ +const extension = require('extensionizer') + +class ExtensionPlatform { + + // + // Public + // + + reload () { + extension.runtime.reload() + } + + openWindow ({ url }) { + extension.tabs.create({ url }) + } + +} + +module.exports = ExtensionPlatform diff --git a/app/scripts/popup.js b/app/scripts/popup.js index 62db68c10..6606c9584 100644 --- a/app/scripts/popup.js +++ b/app/scripts/popup.js @@ -3,8 +3,10 @@ const MetaMaskUiCss = require('../../ui/css') const startPopup = require('./popup-core') const PortStream = require('./lib/port-stream.js') const isPopupOrNotification = require('./lib/is-popup-or-notification') -const extension = require('./lib/extension') -const notification = require('./lib/notifications') +const extension = require('extensionizer') +const NotificationManager = require('./lib/notification-manager') + +const notificationManager = new NotificationManager() var css = MetaMaskUiCss() injectCss(css) @@ -20,6 +22,6 @@ startPopup(portStream) function closePopupIfOpen (name) { if (name !== 'notification') { - notification.closePopup() + notificationManager.closePopup() } } diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 3a6baca91..6f633ab4e 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -1,7 +1,7 @@ const extend = require('xtend') const actions = require('../actions') const txHelper = require('../../lib/tx-helper') -const notification = require('../../../app/scripts/lib/notifications') +const notification = require('../../../app/scripts/lib/notification-manager') module.exports = reduceApp -- cgit From 6259ffaef4f2045d2de069ea83de47b64b5fba86 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 30 Mar 2017 18:35:22 -0700 Subject: extension - remove local extension files, we use extensionizer --- app/scripts/lib/extension-instance.js | 68 ----------------------------------- app/scripts/lib/extension.js | 17 --------- 2 files changed, 85 deletions(-) delete mode 100644 app/scripts/lib/extension-instance.js delete mode 100644 app/scripts/lib/extension.js diff --git a/app/scripts/lib/extension-instance.js b/app/scripts/lib/extension-instance.js deleted file mode 100644 index 628b62e3f..000000000 --- a/app/scripts/lib/extension-instance.js +++ /dev/null @@ -1,68 +0,0 @@ -const apis = [ - 'alarms', - 'bookmarks', - 'browserAction', - 'commands', - 'contextMenus', - 'cookies', - 'downloads', - 'events', - 'extension', - 'extensionTypes', - 'history', - 'i18n', - 'idle', - 'notifications', - 'pageAction', - 'runtime', - 'storage', - 'tabs', - 'webNavigation', - 'webRequest', - 'windows', -] - -function Extension () { - const _this = this - - apis.forEach(function (api) { - - _this[api] = null - - try { - if (chrome[api]) { - _this[api] = chrome[api] - } - } catch (e) {} - - try { - if (window[api]) { - _this[api] = window[api] - } - } catch (e) {} - - try { - if (browser[api]) { - _this[api] = browser[api] - } - } catch (e) {} - try { - _this.api = browser.extension[api] - } catch (e) {} - }) - - try { - if (browser && browser.runtime) { - this.runtime = browser.runtime - } - } catch (e) {} - - try { - if (browser && browser.browserAction) { - this.browserAction = browser.browserAction - } - } catch (e) {} - -} - -module.exports = Extension diff --git a/app/scripts/lib/extension.js b/app/scripts/lib/extension.js deleted file mode 100644 index 6f8b5d800..000000000 --- a/app/scripts/lib/extension.js +++ /dev/null @@ -1,17 +0,0 @@ -/* Extension.js - * - * A module for unifying browser differences in the WebExtension API. - * - * Initially implemented because Chrome hides all of their WebExtension API - * behind a global `chrome` variable, but we'd like to start grooming - * the code-base for cross-browser extension support. - * - * You can read more about the WebExtension API here: - * https://developer.mozilla.org/en-US/Add-ons/WebExtensions - */ - -const Extension = require('./extension-instance') -const instance = new Extension() -window.METAMASK_EXTENSION = instance -module.exports = instance - -- cgit From bd704b1d7e7208fe1989bd7dde6ab81cb39bbfcc Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 30 Mar 2017 19:05:11 -0700 Subject: etc - fix notification-manager ref, remove duplicated test file --- test/unit/extension-test.js | 77 --------------------------------------------- ui/app/reducers/app.js | 6 ++-- 2 files changed, 4 insertions(+), 79 deletions(-) delete mode 100644 test/unit/extension-test.js diff --git a/test/unit/extension-test.js b/test/unit/extension-test.js deleted file mode 100644 index 8f259f05c..000000000 --- a/test/unit/extension-test.js +++ /dev/null @@ -1,77 +0,0 @@ -var assert = require('assert') -var sinon = require('sinon') -const ethUtil = require('ethereumjs-util') -global.chrome = {} -global.browser = {} - -var path = require('path') -var Extension = require(path.join(__dirname, '..', '..', 'app', 'scripts', 'lib', 'extension-instance.js')) - -describe('extension', function() { - - describe('extension.getURL', function() { - const desiredResult = 'http://the-desired-result.io' - - describe('in Chrome or Firefox', function() { - global.chrome.extension = { - getURL: () => desiredResult - } - - it('returns the desired result', function() { - const extension = new Extension() - const result = extension.extension.getURL() - assert.equal(result, desiredResult) - }) - }) - - describe('in Microsoft Edge', function() { - global.browser.extension = { - getURL: () => desiredResult - } - - it('returns the desired result', function() { - const extension = new Extension() - const result = extension.extension.getURL() - assert.equal(result, desiredResult) - }) - }) - }) - - describe('with chrome global', function() { - let extension - - beforeEach(function() { - global.chrome = { - alarms: 'foo' - } - extension = new Extension() - }) - - it('should use the chrome global apis', function() { - assert.equal(extension.alarms, 'foo') - }) - }) - - describe('without chrome global', function() { - let extension - let realWindow - - beforeEach(function() { - realWindow = window - window = global - global.chrome = undefined - global.alarms = 'foo' - extension = new Extension() - }) - - after(function() { - window = realWindow - }) - - it('should use the global apis', function() { - assert.equal(extension.alarms, 'foo') - }) - }) - - -}) diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 6f633ab4e..7595c60b3 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -1,7 +1,9 @@ const extend = require('xtend') const actions = require('../actions') const txHelper = require('../../lib/tx-helper') -const notification = require('../../../app/scripts/lib/notification-manager') +const NotificationManager = require('../../../app/scripts/lib/notification-manager') + +const notificationManager = new NotificationManager() module.exports = reduceApp @@ -332,7 +334,7 @@ function reduceApp (state, action) { }) } else { log.debug('attempting to close popup') - notification.closePopup() + notificationManager.closePopup() return extend(appState, { transForward: false, -- cgit From 0ef679388a9604c39a432408826c080d2d17c221 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 31 Mar 2017 12:38:20 -0700 Subject: ui - reducer - app - code cleanup --- ui/app/reducers/app.js | 47 ++++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 7595c60b3..e0c001546 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -11,12 +11,12 @@ function reduceApp (state, action) { log.debug('App Reducer got ' + action.type) // clone and defaults const selectedAddress = state.metamask.selectedAddress - let pendingTxs = hasPendingTxs(state) + const hasUnconfActions = checkUnconfActions(state) let name = 'accounts' if (selectedAddress) { name = 'accountDetail' } - if (pendingTxs) { + if (hasUnconfActions) { log.debug('pending txs detected, defaulting to conf-tx view.') name = 'confTx' } @@ -304,7 +304,7 @@ function reduceApp (state, action) { case actions.SHOW_CONF_MSG_PAGE: return extend(appState, { currentView: { - name: pendingTxs ? 'confTx' : 'account-detail', + name: hasUnconfActions ? 'confTx' : 'account-detail', context: 0, }, transForward: true, @@ -314,15 +314,11 @@ function reduceApp (state, action) { case actions.COMPLETED_TX: log.debug('reducing COMPLETED_TX for tx ' + action.value) - var { unapprovedTxs, unapprovedMsgs, - unapprovedPersonalMsgs, network } = state.metamask - - var unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, network) + const otherUnconfActions = getUnconfActionList(state) .filter(tx => tx.id !== action.value ) + const hasOtherUnconfActions = otherUnconfActions.length > 0 - pendingTxs = unconfTxList.length > 0 - - if (pendingTxs) { + if (hasOtherUnconfActions) { log.debug('reducer detected txs - rendering confTx view') return extend(appState, { transForward: false, @@ -582,26 +578,23 @@ function reduceApp (state, action) { } } -function hasPendingTxs (state) { - var { unapprovedTxs, unapprovedMsgs, +function checkUnconfActions (state) { + const unconfActionList = getUnconfActionList(state) + const hasUnconfActions = unconfActionList.length > 0 + return hasUnconfActions +} + +function getUnconfActionList (state) { + const { unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, network } = state.metamask - var unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, network) - var has = unconfTxList.length > 0 - return has + const unconfActionList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, network) + return unconfActionList } function indexForPending (state, txId) { - var unapprovedTxs = state.metamask.unapprovedTxs - var unapprovedMsgs = state.metamask.unapprovedMsgs - var unapprovedPersonalMsgs = state.metamask.unapprovedPersonalMsgs - var network = state.metamask.network - var unconfTxList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, network) - let idx - unconfTxList.forEach((tx, i) => { - if (tx.id === txId) { - idx = i - } - }) - return idx + const unconfTxList = getUnconfActionList(state) + const match = unconfTxList.find((tx) => tx.id === txId) + const index = unconfTxList.indexOf(match) + return index } -- cgit From 49d8877fd78b8251b6856292ca71a55773a74b0e Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 31 Mar 2017 13:20:16 -0700 Subject: ui - startPopup returns store after boot --- app/scripts/popup-core.js | 27 ++++++++------------------- app/scripts/popup.js | 34 ++++++++++++++++++++++++---------- ui/app/reducers/app.js | 1 + ui/index.js | 23 +++++++++++++---------- 4 files changed, 46 insertions(+), 39 deletions(-) diff --git a/app/scripts/popup-core.js b/app/scripts/popup-core.js index b1e521a7a..1e5d70e8b 100644 --- a/app/scripts/popup-core.js +++ b/app/scripts/popup-core.js @@ -1,7 +1,8 @@ const EventEmitter = require('events').EventEmitter +const async = require('async') const Dnode = require('dnode') const Web3 = require('web3') -const MetaMaskUi = require('../../ui') +const launchMetamaskUi = require('../../ui') const StreamProvider = require('web3-stream-provider') const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex @@ -9,9 +10,13 @@ const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex module.exports = initializePopup -function initializePopup (connectionStream) { +function initializePopup ({ container, connectionStream }, cb) { // setup app - connectToAccountManager(connectionStream, setupApp) + async.waterfall([ + (cb) => connectToAccountManager(connectionStream, cb), + (accountManager, cb) => launchMetamaskUi({ container, accountManager }, cb), + ], cb) + } function connectToAccountManager (connectionStream, cb) { @@ -47,19 +52,3 @@ function setupControllerConnection (connectionStream, cb) { cb(null, accountManager) }) } - -function setupApp (err, accountManager) { - var container = document.getElementById('app-content') - if (err) { - container.innerHTML = '
The MetaMask app failed to load: please open and close MetaMask again to restart.
' - container.style.height = '80px' - log.error(err.stack) - throw err - } - - - MetaMaskUi({ - container: container, - accountManager: accountManager, - }) -} diff --git a/app/scripts/popup.js b/app/scripts/popup.js index 6606c9584..f6dcb829b 100644 --- a/app/scripts/popup.js +++ b/app/scripts/popup.js @@ -5,23 +5,37 @@ const PortStream = require('./lib/port-stream.js') const isPopupOrNotification = require('./lib/is-popup-or-notification') const extension = require('extensionizer') const NotificationManager = require('./lib/notification-manager') - const notificationManager = new NotificationManager() -var css = MetaMaskUiCss() +// inject css +const css = MetaMaskUiCss() injectCss(css) -var name = isPopupOrNotification() -closePopupIfOpen(name) -window.METAMASK_UI_TYPE = name +// identify window type (popup, notification) +const windowType = isPopupOrNotification() +global.METAMASK_UI_TYPE = windowType +closePopupIfOpen(windowType) + +// setup stream to background +const extensionPort = extension.runtime.connect({ windowType }) +const connectionStream = new PortStream(extensionPort) -var pluginPort = extension.runtime.connect({ name }) -var portStream = new PortStream(pluginPort) +// start ui +const container = document.getElementById('app-content') +startPopup({ container, connectionStream }, (err, store) => { + if (err) return displayCriticalError(err) +}) -startPopup(portStream) -function closePopupIfOpen (name) { - if (name !== 'notification') { +function closePopupIfOpen (windowType) { + if (windowType !== 'notification') { notificationManager.closePopup() } } + +function displayCriticalError(err) { + container.innerHTML = '
The MetaMask app failed to load: please open and close MetaMask again to restart.
' + container.style.height = '80px' + log.error(err.stack) + throw err +} diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index e0c001546..46b27fe25 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -34,6 +34,7 @@ function reduceApp (state, action) { seedWords, } + // default state var appState = extend({ menuOpen: false, currentView: seedWords ? seedConfView : defaultView, diff --git a/ui/index.js b/ui/index.js index 1a65f813c..e3648c374 100644 --- a/ui/index.js +++ b/ui/index.js @@ -4,27 +4,28 @@ const Root = require('./app/root') const actions = require('./app/actions') const configureStore = require('./app/store') const txHelper = require('./lib/tx-helper') -module.exports = launchApp +global.log = require('loglevel') -let debugMode = window.METAMASK_DEBUG -const log = require('loglevel') -window.log = log -log.setLevel(debugMode ? 'debug' : 'warn') +module.exports = launchMetamaskUi -function launchApp (opts) { + +log.setLevel(global.METAMASK_DEBUG ? 'debug' : 'warn') + +function launchMetamaskUi (opts, cb) { var accountManager = opts.accountManager actions._setBackgroundConnection(accountManager) // check if we are unlocked first accountManager.getState(function (err, metamaskState) { - if (err) throw err - startApp(metamaskState, accountManager, opts) + if (err) return cb(err) + const store = startApp(metamaskState, accountManager, opts) + cb(null, store) }) } function startApp (metamaskState, accountManager, opts) { // parse opts - var store = configureStore({ + const store = configureStore({ // metamaskState represents the cross-tab state metamask: metamaskState, @@ -37,7 +38,7 @@ function startApp (metamaskState, accountManager, opts) { }) // if unconfirmed txs, start on txConf page - var unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.network) + const unapprovedTxsAll = txHelper(metamaskState.unapprovedTxs, metamaskState.unapprovedMsgs, metamaskState.unapprovedPersonalMsgs, metamaskState.network) if (unapprovedTxsAll.length > 0) { store.dispatch(actions.showConfTxPage()) } @@ -53,4 +54,6 @@ function startApp (metamaskState, accountManager, opts) { store: store, } ), opts.container) + + return store } -- cgit From 60a48e713fb341c0eba893bd0c37e02315c8b320 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 31 Mar 2017 13:32:47 -0700 Subject: ui - move popup auto-close after tx conf to ui entrypoint --- app/scripts/popup.js | 6 +++++- ui/app/reducers/app.js | 9 ++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/scripts/popup.js b/app/scripts/popup.js index f6dcb829b..ce18dc422 100644 --- a/app/scripts/popup.js +++ b/app/scripts/popup.js @@ -17,13 +17,17 @@ global.METAMASK_UI_TYPE = windowType closePopupIfOpen(windowType) // setup stream to background -const extensionPort = extension.runtime.connect({ windowType }) +const extensionPort = extension.runtime.connect({ name: windowType }) const connectionStream = new PortStream(extensionPort) // start ui const container = document.getElementById('app-content') startPopup({ container, connectionStream }, (err, store) => { if (err) return displayCriticalError(err) + store.subscribe(() => { + const state = store.getState() + if (state.appState.shouldClose) notificationManager.closePopup() + }) }) diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js index 46b27fe25..7ad1229e5 100644 --- a/ui/app/reducers/app.js +++ b/ui/app/reducers/app.js @@ -1,12 +1,10 @@ const extend = require('xtend') const actions = require('../actions') const txHelper = require('../../lib/tx-helper') -const NotificationManager = require('../../../app/scripts/lib/notification-manager') - -const notificationManager = new NotificationManager() module.exports = reduceApp + function reduceApp (state, action) { log.debug('App Reducer got ' + action.type) // clone and defaults @@ -36,6 +34,7 @@ function reduceApp (state, action) { // default state var appState = extend({ + shouldClose: false, menuOpen: false, currentView: seedWords ? seedConfView : defaultView, accountDetail: { @@ -331,9 +330,9 @@ function reduceApp (state, action) { }) } else { log.debug('attempting to close popup') - notificationManager.closePopup() - return extend(appState, { + // indicate notification should close + shouldClose: true, transForward: false, warning: null, currentView: { -- cgit From aa06183c64b79316a4622e25791c29e785c7bce0 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 31 Mar 2017 18:04:13 -0700 Subject: ui - use global.platform for extension interaction --- app/scripts/platforms/extension.js | 4 ++++ app/scripts/popup.js | 4 ++++ ui/app/components/account-info-link.js | 3 +-- ui/app/components/buy-button-subview.js | 3 +-- ui/app/components/shift-list-item.js | 5 +---- ui/app/info.js | 24 ++++++++++-------------- 6 files changed, 21 insertions(+), 22 deletions(-) diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js index cbb35768e..00c2aa275 100644 --- a/app/scripts/platforms/extension.js +++ b/app/scripts/platforms/extension.js @@ -14,6 +14,10 @@ class ExtensionPlatform { extension.tabs.create({ url }) } + getVersion () { + return extension.runtime.getManifest().version + } + } module.exports = ExtensionPlatform diff --git a/app/scripts/popup.js b/app/scripts/popup.js index ce18dc422..0fbde54b3 100644 --- a/app/scripts/popup.js +++ b/app/scripts/popup.js @@ -4,9 +4,13 @@ const startPopup = require('./popup-core') const PortStream = require('./lib/port-stream.js') const isPopupOrNotification = require('./lib/is-popup-or-notification') const extension = require('extensionizer') +const ExtensionPlatform = require('./platforms/extension') const NotificationManager = require('./lib/notification-manager') const notificationManager = new NotificationManager() +// create platform global +global.platform = new ExtensionPlatform() + // inject css const css = MetaMaskUiCss() injectCss(css) diff --git a/ui/app/components/account-info-link.js b/ui/app/components/account-info-link.js index 74bc7f40e..6526ab502 100644 --- a/ui/app/components/account-info-link.js +++ b/ui/app/components/account-info-link.js @@ -3,7 +3,6 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const Tooltip = require('./tooltip') const genAccountLink = require('../../lib/account-link') -const extension = require('extensionizer') module.exports = AccountInfoLink @@ -35,7 +34,7 @@ AccountInfoLink.prototype.render = function () { style: { margin: '5px', }, - onClick () { extension.tabs.create({ url }) }, + onClick () { global.platform.openWindow({ url }) }, }), ]), ]) diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js index 19279d1f6..2b1675b6d 100644 --- a/ui/app/components/buy-button-subview.js +++ b/ui/app/components/buy-button-subview.js @@ -5,7 +5,6 @@ const connect = require('react-redux').connect const actions = require('../actions') const CoinbaseForm = require('./coinbase-form') const ShapeshiftForm = require('./shapeshift-form') -const extension = require('extensionizer') const Loading = require('./loading') const TabBar = require('./tab-bar') @@ -142,7 +141,7 @@ BuyButtonSubview.prototype.formVersionSubview = function () { } BuyButtonSubview.prototype.navigateTo = function (url) { - extension.tabs.create({ url }) + global.platform.openWindow({ url }) } BuyButtonSubview.prototype.backButtonContext = function () { diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index da991f75f..96a7cba6e 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -4,7 +4,6 @@ const h = require('react-hyperscript') const connect = require('react-redux').connect const vreme = new (require('vreme')) const explorerLink = require('../../lib/explorer-link') -const extension = require('extensionizer') const actions = require('../actions') const addressSummary = require('../util').addressSummary @@ -172,9 +171,7 @@ ShiftListItem.prototype.renderInfo = function () { width: '200px', overflow: 'hidden', }, - onClick: () => extension.tabs.create({ - url, - }), + onClick: () => global.platform.openWindow({ url }), }, [ h('div', { style: { diff --git a/ui/app/info.js b/ui/app/info.js index fa51ae41c..a6fdeb315 100644 --- a/ui/app/info.js +++ b/ui/app/info.js @@ -3,7 +3,6 @@ const Component = require('react').Component const h = require('react-hyperscript') const connect = require('react-redux').connect const actions = require('./actions') -const extension = require('extensionizer') module.exports = connect(mapStateToProps)(InfoScreen) @@ -17,13 +16,8 @@ function InfoScreen () { } InfoScreen.prototype.render = function () { - var state = this.props - var manifest - try { - manifest = extension.runtime.getManifest() - } catch (e) { - manifest = { version: '2.0.0' } - } + const state = this.props + const version = global.platform.getVersion() return ( h('.flex-column.flex-grow', [ @@ -53,7 +47,7 @@ InfoScreen.prototype.render = function () { style: { marginBottom: '10px', }, - }, `Version: ${manifest.version}`), + }, `Version: ${version}`), ]), h('div', { @@ -110,10 +104,12 @@ InfoScreen.prototype.render = function () { onClick (event) { this.navigateTo(event.target.href) }, }, [ h('img.icon-size', { - src: manifest.icons['128'], + src: 'images/icon-128.png', style: { - filter: 'grayscale(100%)', /* IE6-9 */ - WebkitFilter: 'grayscale(100%)', /* Microsoft Edge and Firefox 35+ */ + // IE6-9 + filter: 'grayscale(100%)', + // Microsoft Edge and Firefox 35+ + WebkitFilter: 'grayscale(100%)', }, }), h('div.info', 'Visit our web site'), @@ -139,7 +135,7 @@ InfoScreen.prototype.render = function () { h('a.info', { target: '_blank', style: { width: '85vw' }, - onClick () { extension.tabs.create({url: 'mailto:help@metamask.io?subject=Feedback'}) }, + onClick () { this.navigateTo('mailto:help@metamask.io?subject=Feedback') }, }, 'Email us!'), ]), @@ -158,5 +154,5 @@ InfoScreen.prototype.render = function () { } InfoScreen.prototype.navigateTo = function (url) { - extension.tabs.create({ url }) + global.platform.openWindow({ url }) } -- cgit From 86e882c51afca3a44bf20bcd1025161e214e6998 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 31 Mar 2017 18:41:51 -0700 Subject: notification-manager - rename show -> showPoup + make getPopup private --- app/scripts/background.js | 2 +- app/scripts/lib/notification-manager.js | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/scripts/background.js b/app/scripts/background.js index 5fb56d497..7211f1e0c 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -147,7 +147,7 @@ function setupController (initState) { // popup trigger function triggerUi () { - if (!popupIsOpen) notificationManager.show() + if (!popupIsOpen) notificationManager.showPopup() } // On first install, open a window to MetaMask website to how-it-works. diff --git a/app/scripts/lib/notification-manager.js b/app/scripts/lib/notification-manager.js index ff8a4b2e5..55e5b8dd2 100644 --- a/app/scripts/lib/notification-manager.js +++ b/app/scripts/lib/notification-manager.js @@ -9,8 +9,8 @@ class NotificationManager { // Public // - show () { - this.getPopup((err, popup) => { + showPopup () { + this._getPopup((err, popup) => { if (err) throw err if (popup) { @@ -31,15 +31,8 @@ class NotificationManager { }) } - getPopup (cb) { - this._getWindows((err, windows) => { - if (err) throw err - cb(null, this._getPopupIn(windows)) - }) - } - closePopup () { - this.getPopup((err, popup) => { + this._getPopup((err, popup) => { if (err) throw err if (!popup) return extension.windows.remove(popup.id, console.error) @@ -50,6 +43,13 @@ class NotificationManager { // Private // + _getPopup (cb) { + this._getWindows((err, windows) => { + if (err) throw err + cb(null, this._getPopupIn(windows)) + }) + } + _getWindows (cb) { // Ignore in test environment if (!extension.windows) { -- cgit