mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge branch 'master' into mascara
This commit is contained in:
commit
f81fdbc34f
@ -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.showPopup()
|
||||
}
|
||||
|
||||
// On first install, open a window to MetaMask website to how-it-works.
|
||||
|
@ -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')
|
||||
|
@ -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
|
@ -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
|
||||
|
74
app/scripts/lib/notification-manager.js
Normal file
74
app/scripts/lib/notification-manager.js
Normal file
@ -0,0 +1,74 @@
|
||||
const extension = require('extensionizer')
|
||||
const height = 520
|
||||
const width = 360
|
||||
|
||||
|
||||
class NotificationManager {
|
||||
|
||||
//
|
||||
// Public
|
||||
//
|
||||
|
||||
showPopup () {
|
||||
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)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
closePopup () {
|
||||
this._getPopup((err, popup) => {
|
||||
if (err) throw err
|
||||
if (!popup) return
|
||||
extension.windows.remove(popup.id, console.error)
|
||||
})
|
||||
}
|
||||
|
||||
//
|
||||
// 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) {
|
||||
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
|
@ -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)
|
||||
})
|
||||
}
|
@ -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 () {
|
||||
|
23
app/scripts/platforms/extension.js
Normal file
23
app/scripts/platforms/extension.js
Normal file
@ -0,0 +1,23 @@
|
||||
const extension = require('extensionizer')
|
||||
|
||||
class ExtensionPlatform {
|
||||
|
||||
//
|
||||
// Public
|
||||
//
|
||||
|
||||
reload () {
|
||||
extension.runtime.reload()
|
||||
}
|
||||
|
||||
openWindow ({ url }) {
|
||||
extension.tabs.create({ url })
|
||||
}
|
||||
|
||||
getVersion () {
|
||||
return extension.runtime.getManifest().version
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ExtensionPlatform
|
@ -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 = '<div class="critical-error">The MetaMask app failed to load: please open and close MetaMask again to restart.</div>'
|
||||
container.style.height = '80px'
|
||||
log.error(err.stack)
|
||||
throw err
|
||||
}
|
||||
|
||||
|
||||
MetaMaskUi({
|
||||
container: container,
|
||||
accountManager: accountManager,
|
||||
})
|
||||
}
|
||||
|
@ -3,23 +3,47 @@ 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 ExtensionPlatform = require('./platforms/extension')
|
||||
const NotificationManager = require('./lib/notification-manager')
|
||||
const notificationManager = new NotificationManager()
|
||||
|
||||
var css = MetaMaskUiCss()
|
||||
// create platform global
|
||||
global.platform = new ExtensionPlatform()
|
||||
|
||||
// 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)
|
||||
|
||||
var pluginPort = extension.runtime.connect({ name })
|
||||
var portStream = new PortStream(pluginPort)
|
||||
// setup stream to background
|
||||
const extensionPort = extension.runtime.connect({ name: windowType })
|
||||
const connectionStream = new PortStream(extensionPort)
|
||||
|
||||
startPopup(portStream)
|
||||
// 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()
|
||||
})
|
||||
})
|
||||
|
||||
function closePopupIfOpen (name) {
|
||||
if (name !== 'notification') {
|
||||
notification.closePopup()
|
||||
|
||||
function closePopupIfOpen (windowType) {
|
||||
if (windowType !== 'notification') {
|
||||
notificationManager.closePopup()
|
||||
}
|
||||
}
|
||||
|
||||
function displayCriticalError(err) {
|
||||
container.innerHTML = '<div class="critical-error">The MetaMask app failed to load: please open and close MetaMask again to restart.</div>'
|
||||
container.style.height = '80px'
|
||||
log.error(err.stack)
|
||||
throw err
|
||||
}
|
||||
|
@ -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 = [
|
||||
|
@ -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')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
})
|
@ -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('../../../app/scripts/lib/extension')
|
||||
|
||||
module.exports = AccountInfoLink
|
||||
|
||||
@ -35,7 +34,7 @@ AccountInfoLink.prototype.render = function () {
|
||||
style: {
|
||||
margin: '5px',
|
||||
},
|
||||
onClick () { extension.tabs.create({ url }) },
|
||||
onClick () { global.platform.openWindow({ url }) },
|
||||
}),
|
||||
]),
|
||||
])
|
||||
|
@ -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('../../../app/scripts/lib/extension')
|
||||
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 () {
|
||||
|
@ -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('../../../app/scripts/lib/extension')
|
||||
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: {
|
||||
|
@ -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')
|
||||
|
@ -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('../../app/scripts/lib/extension')
|
||||
|
||||
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 })
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
const extend = require('xtend')
|
||||
const actions = require('../actions')
|
||||
const txHelper = require('../../lib/tx-helper')
|
||||
const notification = require('../../../app/scripts/lib/notifications')
|
||||
|
||||
module.exports = reduceApp
|
||||
|
||||
|
||||
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'
|
||||
}
|
||||
@ -32,7 +32,9 @@ function reduceApp (state, action) {
|
||||
seedWords,
|
||||
}
|
||||
|
||||
// default state
|
||||
var appState = extend({
|
||||
shouldClose: false,
|
||||
menuOpen: false,
|
||||
currentView: seedWords ? seedConfView : defaultView,
|
||||
accountDetail: {
|
||||
@ -302,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,
|
||||
@ -312,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,
|
||||
@ -332,9 +330,9 @@ function reduceApp (state, action) {
|
||||
})
|
||||
} else {
|
||||
log.debug('attempting to close popup')
|
||||
notification.closePopup()
|
||||
|
||||
return extend(appState, {
|
||||
// indicate notification should close
|
||||
shouldClose: true,
|
||||
transForward: false,
|
||||
warning: null,
|
||||
currentView: {
|
||||
@ -580,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
|
||||
}
|
||||
|
23
ui/index.js
23
ui/index.js
@ -4,26 +4,27 @@ 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,
|
||||
@ -36,7 +37,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())
|
||||
}
|
||||
@ -52,4 +53,6 @@ function startApp (metamaskState, accountManager, opts) {
|
||||
store: store,
|
||||
}
|
||||
), opts.container)
|
||||
|
||||
return store
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user