diff --git a/app/browser/electronDownloadItem.js b/app/browser/electronDownloadItem.js
new file mode 100644
index 00000000000..01b6721b875
--- /dev/null
+++ b/app/browser/electronDownloadItem.js
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const downloadStates = require('../../js/constants/downloadStates')
+
+/**
+ * Maps downloadId to an electron download-item
+ */
+const downloadMap = {}
+
+module.exports.updateElectronDownloadItem = (downloadId, item, state) => {
+ if (state === downloadStates.INTERRUPTED || state === downloadStates.CANCELLED || state === downloadStates.COMPLETED) {
+ delete downloadMap[downloadId]
+ } else {
+ downloadMap[downloadId] = item
+ }
+}
+
+module.exports.cancelDownload = (downloadId) =>
+ downloadMap[downloadId] && downloadMap[downloadId].cancel()
+
+module.exports.pauseDownload = (downloadId) =>
+ downloadMap[downloadId] && downloadMap[downloadId].pause()
+
+module.exports.resumeDownload = (downloadId) =>
+ downloadMap[downloadId] && downloadMap[downloadId].resume()
diff --git a/app/browser/reducers/downloadsReducer.js b/app/browser/reducers/downloadsReducer.js
new file mode 100644
index 00000000000..02547ab1200
--- /dev/null
+++ b/app/browser/reducers/downloadsReducer.js
@@ -0,0 +1,96 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+'use strict'
+
+const appConstants = require('../../../js/constants/appConstants')
+const downloadStates = require('../../../js/constants/downloadStates')
+const {clipboard, BrowserWindow, shell} = require('electron')
+const fs = require('fs')
+const path = require('path')
+const {cancelDownload, pauseDownload, resumeDownload} = require('../electronDownloadItem')
+const {CANCEL, PAUSE, RESUME} = require('../../common/constants/electronDownloadItemActions')
+
+const downloadsReducer = (state, action) => {
+ const download = action.downloadId ? state.getIn(['downloads', action.downloadId]) : undefined
+ if (!download &&
+ ![appConstants.APP_MERGE_DOWNLOAD_DETAIL,
+ appConstants.APP_CLEAR_COMPLETED_DOWNLOADS].includes(action.actionType)) {
+ return state
+ }
+ switch (action.actionType) {
+ case appConstants.APP_DOWNLOAD_REVEALED:
+ fs.exists(download.get('savePath'), (exists) => {
+ if (exists) {
+ shell.showItemInFolder(download.get('savePath'))
+ } else {
+ shell.openItem(path.dirname(download.get('savePath')))
+ }
+ })
+ break
+ case appConstants.APP_DOWNLOAD_OPENED:
+ fs.exists(download.get('savePath'), (exists) => {
+ if (exists) {
+ shell.openItem(download.get('savePath'))
+ } else {
+ shell.beep()
+ }
+ })
+ break
+ case appConstants.APP_DOWNLOAD_ACTION_PERFORMED:
+ switch (action.downloadAction) {
+ case CANCEL:
+ // It's important to update state before the cancel since it'll remove the reference
+ state = state.setIn(['downloads', action.downloadId, 'state'], downloadStates.CANCELLED)
+ cancelDownload(action.downloadId)
+ break
+ case PAUSE:
+ pauseDownload(action.downloadId)
+ state = state.setIn(['downloads', action.downloadId, 'state'], downloadStates.PAUSED)
+ break
+ case RESUME:
+ resumeDownload(action.downloadId)
+ state = state.setIn(['downloads', action.downloadId, 'state'], downloadStates.IN_PROGRESS)
+ break
+ }
+ break
+ case appConstants.APP_DOWNLOAD_COPIED_TO_CLIPBOARD:
+ clipboard.writeText(download.get('url'))
+ break
+ case appConstants.APP_DOWNLOAD_DELETED:
+ shell.moveItemToTrash(download.get('savePath'))
+ state = state.deleteIn(['downloads', action.downloadId])
+ break
+ case appConstants.APP_DOWNLOAD_CLEARED:
+ state = state.deleteIn(['downloads', action.downloadId])
+ break
+ case appConstants.APP_DOWNLOAD_REDOWNLOADED:
+ const win = BrowserWindow.getFocusedWindow()
+ if (win) {
+ win.webContents.downloadURL(download.get('url'))
+ state = state.deleteIn(['downloads', action.downloadId])
+ } else {
+ shell.beep()
+ }
+ break
+ case appConstants.APP_MERGE_DOWNLOAD_DETAIL:
+ if (action.downloadDetail) {
+ state = state.mergeIn(['downloads', action.downloadId], action.downloadDetail)
+ } else {
+ state = state.deleteIn(['downloads', action.downloadId])
+ }
+ break
+ case appConstants.APP_CLEAR_COMPLETED_DOWNLOADS:
+ if (state.get('downloads')) {
+ const downloads = state.get('downloads')
+ .filter((download) =>
+ ![downloadStates.COMPLETED, downloadStates.INTERRUPTED, downloadStates.CANCELLED].includes(download.get('state')))
+ state = state.set('downloads', downloads)
+ }
+ break
+ }
+ return state
+}
+
+module.exports = downloadsReducer
diff --git a/js/constants/downloadActions.js b/app/common/constants/electronDownloadItemActions.js
similarity index 59%
rename from js/constants/downloadActions.js
rename to app/common/constants/electronDownloadItemActions.js
index 3c662abbe61..48af3c48785 100644
--- a/js/constants/downloadActions.js
+++ b/app/common/constants/electronDownloadItemActions.js
@@ -2,13 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
-const mapValuesByKeys = require('../lib/functional').mapValuesByKeys
+const mapValuesByKeys = require('../../../js/lib/functional').mapValuesByKeys
const _ = null
-const downloadActions = {
+const electronDownloadItemActions = {
PAUSE: _,
RESUME: _,
CANCEL: _
}
-module.exports = mapValuesByKeys(downloadActions)
+module.exports = mapValuesByKeys(electronDownloadItemActions)
diff --git a/app/filtering.js b/app/filtering.js
index cdb6df8f2d5..77054d25b1a 100644
--- a/app/filtering.js
+++ b/app/filtering.js
@@ -12,7 +12,6 @@ const webContents = electron.webContents
const appActions = require('../js/actions/appActions')
const appConfig = require('../js/constants/appConfig')
const downloadStates = require('../js/constants/downloadStates')
-const downloadActions = require('../js/constants/downloadActions')
const urlParse = require('url').parse
const getBaseDomain = require('../js/lib/baseDomain').getBaseDomain
const getSetting = require('../js/settings').getSetting
@@ -31,6 +30,7 @@ const uuid = require('node-uuid')
const path = require('path')
const getOrigin = require('../js/state/siteUtil').getOrigin
const {adBlockResourceName} = require('./adBlock')
+const {updateElectronDownloadItem} = require('./browser/electronDownloadItem')
let appStore = null
@@ -46,11 +46,6 @@ const pdfjsOrigin = `chrome-extension://${config.PDFJSExtensionId}`
// Third party domains that require a valid referer to work
const refererExceptions = ['use.typekit.net', 'cloud.typography.com']
-/**
- * Maps downloadId to an electron download-item
- */
-const downloadMap = {}
-
/**
* Maps partition name to the session object
*/
@@ -467,11 +462,7 @@ module.exports.isThirdPartyHost = (baseContextHost, testHost) => {
}
function updateDownloadState (downloadId, item, state) {
- if (state === downloadStates.INTERRUPTED || state === downloadStates.CANCELLED || state === downloadStates.COMPLETED) {
- delete downloadMap[downloadId]
- } else {
- downloadMap[downloadId] = item
- }
+ updateElectronDownloadItem(downloadId, item, state)
if (!item) {
appActions.mergeDownloadDetail(downloadId, { state: downloadStates.INTERRUPTED })
@@ -602,29 +593,6 @@ module.exports.init = (state, action, store) => {
e.returnValue = true
return e.returnValue
})
- ipcMain.on(messages.DOWNLOAD_ACTION, (e, downloadId, action) => {
- const item = downloadMap[downloadId]
- switch (action) {
- case downloadActions.CANCEL:
- updateDownloadState(downloadId, item, downloadStates.CANCELLED)
- if (item) {
- item.cancel()
- }
- break
- case downloadActions.PAUSE:
- if (item) {
- item.pause()
- }
- updateDownloadState(downloadId, item, downloadStates.PAUSED)
- break
- case downloadActions.RESUME:
- if (item) {
- item.resume()
- }
- updateDownloadState(downloadId, item, downloadStates.IN_PROGRESS)
- break
- }
- })
ipcMain.on(messages.NOTIFICATION_RESPONSE, (e, message, buttonIndex, persist) => {
if (permissionCallbacks[message]) {
permissionCallbacks[message](buttonIndex, persist)
diff --git a/app/index.js b/app/index.js
index e0d925a2c41..c9abcdece2a 100644
--- a/app/index.js
+++ b/app/index.js
@@ -52,7 +52,6 @@ const Importer = require('./importer')
const messages = require('../js/constants/messages')
const appConfig = require('../js/constants/appConfig')
const appActions = require('../js/actions/appActions')
-const downloadActions = require('../js/actions/downloadActions')
const SessionStore = require('./sessionStore')
const AppStore = require('../js/stores/appStore')
const PackageLoader = require('./package-loader')
@@ -490,10 +489,6 @@ app.on('ready', () => {
electron.clipboard.writeText(text)
})
- ipcMain.on(messages.OPEN_DOWNLOAD_PATH, (e, download) => {
- downloadActions.openDownloadPath(Immutable.fromJS(download))
- })
-
ipcMain.on(messages.CERT_ERROR_ACCEPTED, (event, url) => {
try {
let host = urlParse(url).host
diff --git a/docs/appActions.md b/docs/appActions.md
index 8f52d4397e2..744628cb03c 100644
--- a/docs/appActions.md
+++ b/docs/appActions.md
@@ -541,6 +541,85 @@ Dispatch a message to copy data URL to clipboard
+### shuttingDown()
+
+Dispatches a message when the app is shutting down.
+
+
+
+### downloadRevealed(downloadId)
+
+Dispatches a message when a download is being revealed.
+Typically this will open the download directory in finder / explorer and select the icon.
+
+**Parameters**
+
+**downloadId**: `string`, ID of the download being revealed
+
+
+
+### downloadOpened(downloadId)
+
+Dispatches a message when a download is being opened.
+
+**Parameters**
+
+**downloadId**: `string`, ID of the download being opened
+
+
+
+### downloadActionPerformed(downloadId, downloadAction)
+
+Dispatches a message when an electron download action is being performed (pause, resume, cancel)
+
+**Parameters**
+
+**downloadId**: `string`, ID of the download item the action is being performed to
+
+**downloadAction**: `string`, the action to perform from constants/electronDownloadItemActions.js
+
+
+
+### downloadCopiedToClipboard(downloadId)
+
+Dispatches a message when a download URL is being copied to the clipboard
+
+**Parameters**
+
+**downloadId**: `string`, ID of the download item being copied to the clipboard
+
+
+
+### downloadDeleted(downloadId)
+
+Dispatches a message when a download is being deleted
+
+**Parameters**
+
+**downloadId**: `string`, ID of the download item being deleted
+
+
+
+### downloadCleared(downloadId)
+
+Dispatches a message when a download is being cleared
+
+**Parameters**
+
+**downloadId**: `string`, ID of the download item being cleared
+
+
+
+### downloadRedownloaded(downloadId)
+
+Dispatches a message when a download is being redownloaded
+
+**Parameters**
+
+**downloadId**: `string`, ID of the download item being redownloaded
+
+
+
* * *
diff --git a/js/about/aboutActions.js b/js/about/aboutActions.js
index 4a5e6bab9cf..9e871f0e1d9 100644
--- a/js/about/aboutActions.js
+++ b/js/about/aboutActions.js
@@ -154,8 +154,11 @@ const aboutActions = {
})
},
- openDownloadPath: function (download) {
- ipc.send(messages.OPEN_DOWNLOAD_PATH, download.toJS())
+ downloadRevealed: function (downloadId) {
+ aboutActions.dispatchAction({
+ actionType: appConstants.APP_DOWNLOAD_REVEALED,
+ downloadId
+ })
},
decryptPassword: function (encryptedPassword, authTag, iv, id) {
diff --git a/js/about/downloads.js b/js/about/downloads.js
index 5d4b1a3577f..ce8fc001681 100644
--- a/js/about/downloads.js
+++ b/js/about/downloads.js
@@ -29,7 +29,7 @@ class DownloadItem extends ImmutableComponent {
className='listItem'
onContextMenu={aboutActions.contextMenu.bind(this, contextMenuDownload, 'download')}
data-context-menu-disable
- onDoubleClick={aboutActions.openDownloadPath.bind(this, this.props.download)}>
+ onDoubleClick={aboutActions.downloadRevealed.bind(this, this.props.downloadId)}>
{
{this.props.download.get('filename')}
diff --git a/js/actions/appActions.js b/js/actions/appActions.js
index fc7ddee7b45..b1aa8df48c7 100644
--- a/js/actions/appActions.js
+++ b/js/actions/appActions.js
@@ -4,7 +4,7 @@
'use strict'
const AppDispatcher = require('../dispatcher/appDispatcher')
-const AppConstants = require('../constants/appConstants')
+const appConstants = require('../constants/appConstants')
const appActions = {
/**
@@ -15,7 +15,7 @@ const appActions = {
*/
setState: function (appState) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_SET_STATE,
+ actionType: appConstants.APP_SET_STATE,
appState
})
},
@@ -29,7 +29,7 @@ const appActions = {
*/
newWindow: function (frameOpts, browserOpts, restoredState, cb) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_NEW_WINDOW,
+ actionType: appConstants.APP_NEW_WINDOW,
frameOpts,
browserOpts,
restoredState,
@@ -39,28 +39,28 @@ const appActions = {
closeWindow: function (windowId) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_CLOSE_WINDOW,
+ actionType: appConstants.APP_CLOSE_WINDOW,
windowId
})
},
windowClosed: function (windowValue) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_WINDOW_CLOSED,
+ actionType: appConstants.APP_WINDOW_CLOSED,
windowValue
})
},
windowCreated: function (windowValue) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_WINDOW_CREATED,
+ actionType: appConstants.APP_WINDOW_CREATED,
windowValue
})
},
windowUpdated: function (windowValue) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_WINDOW_UPDATED,
+ actionType: appConstants.APP_WINDOW_UPDATED,
windowValue
})
},
@@ -71,7 +71,7 @@ const appActions = {
*/
newTab: function (frameProps) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_NEW_TAB,
+ actionType: appConstants.APP_NEW_TAB,
frameProps
})
},
@@ -82,7 +82,7 @@ const appActions = {
*/
tabCreated: function (tabValue) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_TAB_CREATED,
+ actionType: appConstants.APP_TAB_CREATED,
tabValue
})
},
@@ -93,7 +93,7 @@ const appActions = {
*/
tabUpdated: function (tabValue) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_TAB_UPDATED,
+ actionType: appConstants.APP_TAB_UPDATED,
tabValue
})
},
@@ -104,7 +104,7 @@ const appActions = {
*/
tabClosed: function (tabValue) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_TAB_CLOSED,
+ actionType: appConstants.APP_TAB_CLOSED,
tabValue
})
},
@@ -119,7 +119,7 @@ const appActions = {
*/
addSite: function (siteDetail, tag, originalSiteDetail, destinationDetail) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_ADD_SITE,
+ actionType: appConstants.APP_ADD_SITE,
siteDetail,
tag,
originalSiteDetail,
@@ -132,7 +132,7 @@ const appActions = {
*/
clearHistory: function () {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_CLEAR_HISTORY
+ actionType: appConstants.APP_CLEAR_HISTORY
})
},
@@ -143,7 +143,7 @@ const appActions = {
*/
removeSite: function (siteDetail, tag) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_REMOVE_SITE,
+ actionType: appConstants.APP_REMOVE_SITE,
siteDetail,
tag
})
@@ -160,7 +160,7 @@ const appActions = {
*/
moveSite: function (sourceDetail, destinationDetail, prepend, destinationIsParent) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_MOVE_SITE,
+ actionType: appConstants.APP_MOVE_SITE,
sourceDetail,
destinationDetail,
prepend,
@@ -176,7 +176,7 @@ const appActions = {
*/
mergeDownloadDetail: function (downloadId, downloadDetail) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_MERGE_DOWNLOAD_DETAIL,
+ actionType: appConstants.APP_MERGE_DOWNLOAD_DETAIL,
downloadId,
downloadDetail
})
@@ -187,7 +187,7 @@ const appActions = {
*/
clearCompletedDownloads: function () {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_CLEAR_COMPLETED_DOWNLOADS
+ actionType: appConstants.APP_CLEAR_COMPLETED_DOWNLOADS
})
},
@@ -196,7 +196,7 @@ const appActions = {
*/
ledgerRecoverySucceeded: function () {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_LEDGER_RECOVERY_SUCCEEDED
+ actionType: appConstants.APP_LEDGER_RECOVERY_SUCCEEDED
})
},
@@ -205,7 +205,7 @@ const appActions = {
*/
ledgerRecoveryFailed: function () {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_LEDGER_RECOVERY_FAILED
+ actionType: appConstants.APP_LEDGER_RECOVERY_FAILED
})
},
@@ -216,7 +216,7 @@ const appActions = {
*/
defaultWindowParamsChanged: function (size, position) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_DEFAULT_WINDOW_PARAMS_CHANGED,
+ actionType: appConstants.APP_DEFAULT_WINDOW_PARAMS_CHANGED,
size,
position
})
@@ -231,7 +231,7 @@ const appActions = {
*/
setResourceETag: function (resourceName, etag) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_SET_DATA_FILE_ETAG,
+ actionType: appConstants.APP_SET_DATA_FILE_ETAG,
resourceName,
etag
})
@@ -244,7 +244,7 @@ const appActions = {
*/
setResourceLastCheck: function (resourceName, lastCheckVersion, lastCheckDate) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_SET_DATA_FILE_LAST_CHECK,
+ actionType: appConstants.APP_SET_DATA_FILE_LAST_CHECK,
resourceName,
lastCheckVersion,
lastCheckDate
@@ -258,7 +258,7 @@ const appActions = {
*/
setResourceEnabled: function (resourceName, enabled) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_SET_RESOURCE_ENABLED,
+ actionType: appConstants.APP_SET_RESOURCE_ENABLED,
resourceName,
enabled
})
@@ -270,7 +270,7 @@ const appActions = {
*/
resourceReady: function (resourceName) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_RESOURCE_READY,
+ actionType: appConstants.APP_RESOURCE_READY,
resourceName
})
},
@@ -282,7 +282,7 @@ const appActions = {
*/
addResourceCount: function (resourceName, count) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_ADD_RESOURCE_COUNT,
+ actionType: appConstants.APP_ADD_RESOURCE_COUNT,
resourceName,
count
})
@@ -294,7 +294,7 @@ const appActions = {
*/
setUpdateLastCheck: function () {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_UPDATE_LAST_CHECK
+ actionType: appConstants.APP_UPDATE_LAST_CHECK
})
},
@@ -306,7 +306,7 @@ const appActions = {
*/
setUpdateStatus: function (status, verbose, metadata) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_SET_UPDATE_STATUS,
+ actionType: appConstants.APP_SET_UPDATE_STATUS,
status,
verbose,
metadata
@@ -319,7 +319,7 @@ const appActions = {
*/
savePassword: function (passwordDetail) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_ADD_PASSWORD,
+ actionType: appConstants.APP_ADD_PASSWORD,
passwordDetail
})
},
@@ -330,7 +330,7 @@ const appActions = {
*/
deletePassword: function (passwordDetail) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_REMOVE_PASSWORD,
+ actionType: appConstants.APP_REMOVE_PASSWORD,
passwordDetail
})
},
@@ -340,7 +340,7 @@ const appActions = {
*/
clearPasswords: function () {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_CLEAR_PASSWORDS
+ actionType: appConstants.APP_CLEAR_PASSWORDS
})
},
@@ -351,7 +351,7 @@ const appActions = {
*/
changeSetting: function (key, value) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_CHANGE_SETTING,
+ actionType: appConstants.APP_CHANGE_SETTING,
key,
value
})
@@ -367,7 +367,7 @@ const appActions = {
*/
changeSiteSetting: function (hostPattern, key, value, temp) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_CHANGE_SITE_SETTING,
+ actionType: appConstants.APP_CHANGE_SITE_SETTING,
hostPattern,
key,
value,
@@ -384,7 +384,7 @@ const appActions = {
*/
removeSiteSetting: function (hostPattern, key, temp) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_REMOVE_SITE_SETTING,
+ actionType: appConstants.APP_REMOVE_SITE_SETTING,
hostPattern,
key,
temporary: temp || false
@@ -397,7 +397,7 @@ const appActions = {
*/
updateLedgerInfo: function (ledgerInfo) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_UPDATE_LEDGER_INFO,
+ actionType: appConstants.APP_UPDATE_LEDGER_INFO,
ledgerInfo
})
},
@@ -408,7 +408,7 @@ const appActions = {
*/
updatePublisherInfo: function (publisherInfo) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_UPDATE_PUBLISHER_INFO,
+ actionType: appConstants.APP_UPDATE_PUBLISHER_INFO,
publisherInfo
})
},
@@ -419,7 +419,7 @@ const appActions = {
*/
showMessageBox: function (detail) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_SHOW_MESSAGE_BOX,
+ actionType: appConstants.APP_SHOW_MESSAGE_BOX,
detail
})
},
@@ -430,7 +430,7 @@ const appActions = {
*/
hideMessageBox: function (message) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_HIDE_MESSAGE_BOX,
+ actionType: appConstants.APP_HIDE_MESSAGE_BOX,
message
})
},
@@ -441,7 +441,7 @@ const appActions = {
*/
clearMessageBoxes: function (origin) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_CLEAR_MESSAGE_BOXES,
+ actionType: appConstants.APP_CLEAR_MESSAGE_BOXES,
origin
})
},
@@ -453,7 +453,7 @@ const appActions = {
*/
addWord: function (word, learn) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_ADD_WORD,
+ actionType: appConstants.APP_ADD_WORD,
word,
learn
})
@@ -465,7 +465,7 @@ const appActions = {
*/
setDictionary: function (locale) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_SET_DICTIONARY,
+ actionType: appConstants.APP_SET_DICTIONARY,
locale
})
},
@@ -477,7 +477,7 @@ const appActions = {
*/
setLoginRequiredDetail: function (tabId, detail) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_SET_LOGIN_REQUIRED_DETAIL,
+ actionType: appConstants.APP_SET_LOGIN_REQUIRED_DETAIL,
tabId,
detail
})
@@ -485,7 +485,7 @@ const appActions = {
setLoginResponseDetail: function (tabId, detail) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_SET_LOGIN_RESPONSE_DETAIL,
+ actionType: appConstants.APP_SET_LOGIN_RESPONSE_DETAIL,
tabId,
detail
})
@@ -497,7 +497,7 @@ const appActions = {
*/
clearAppData: function (clearDataDetail) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_CLEAR_DATA,
+ actionType: appConstants.APP_CLEAR_DATA,
clearDataDetail
})
},
@@ -508,7 +508,7 @@ const appActions = {
*/
importBrowserData: function (selected) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_IMPORT_BROWSER_DATA,
+ actionType: appConstants.APP_IMPORT_BROWSER_DATA,
selected
})
},
@@ -520,7 +520,7 @@ const appActions = {
*/
addAutofillAddress: function (detail, originalDetail) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_ADD_AUTOFILL_ADDRESS,
+ actionType: appConstants.APP_ADD_AUTOFILL_ADDRESS,
detail,
originalDetail
})
@@ -532,7 +532,7 @@ const appActions = {
*/
removeAutofillAddress: function (detail) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_REMOVE_AUTOFILL_ADDRESS,
+ actionType: appConstants.APP_REMOVE_AUTOFILL_ADDRESS,
detail
})
},
@@ -544,7 +544,7 @@ const appActions = {
*/
addAutofillCreditCard: function (detail, originalDetail) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_ADD_AUTOFILL_CREDIT_CARD,
+ actionType: appConstants.APP_ADD_AUTOFILL_CREDIT_CARD,
detail,
originalDetail
})
@@ -556,7 +556,7 @@ const appActions = {
*/
removeAutofillCreditCard: function (detail) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_REMOVE_AUTOFILL_CREDIT_CARD,
+ actionType: appConstants.APP_REMOVE_AUTOFILL_CREDIT_CARD,
detail
})
},
@@ -568,7 +568,7 @@ const appActions = {
*/
autofillDataChanged: function (addressGuids, creditCardGuids) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_AUTOFILL_DATA_CHANGED,
+ actionType: appConstants.APP_AUTOFILL_DATA_CHANGED,
addressGuids,
creditCardGuids
})
@@ -582,7 +582,7 @@ const appActions = {
*/
windowBlurred: function (windowId) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_WINDOW_BLURRED,
+ actionType: appConstants.APP_WINDOW_BLURRED,
windowId: windowId
})
},
@@ -593,7 +593,7 @@ const appActions = {
*/
setMenubarTemplate: function (menubarTemplate) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_SET_MENUBAR_TEMPLATE,
+ actionType: appConstants.APP_SET_MENUBAR_TEMPLATE,
menubarTemplate
})
},
@@ -604,7 +604,7 @@ const appActions = {
*/
networkConnected: function () {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_NETWORK_CONNECTED
+ actionType: appConstants.APP_NETWORK_CONNECTED
})
},
@@ -613,7 +613,7 @@ const appActions = {
*/
networkDisconnected: function () {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_NETWORK_DISCONNECTED
+ actionType: appConstants.APP_NETWORK_DISCONNECTED
})
},
@@ -624,7 +624,7 @@ const appActions = {
*/
defaultBrowserUpdated: function (useBrave) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_DEFAULT_BROWSER_UPDATED,
+ actionType: appConstants.APP_DEFAULT_BROWSER_UPDATED,
useBrave
})
},
@@ -634,7 +634,7 @@ const appActions = {
*/
defaultBrowserCheckComplete: function () {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_DEFAULT_BROWSER_CHECK_COMPLETE
+ actionType: appConstants.APP_DEFAULT_BROWSER_CHECK_COMPLETE
})
},
@@ -643,7 +643,7 @@ const appActions = {
*/
populateHistory: function () {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_POPULATE_HISTORY
+ actionType: appConstants.APP_POPULATE_HISTORY
})
},
@@ -652,16 +652,99 @@ const appActions = {
**/
dataURLCopied: function (dataURL, html, text) {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_DATA_URL_COPIED,
+ actionType: appConstants.APP_DATA_URL_COPIED,
dataURL,
html,
text
})
},
+ /**
+ * Dispatches a message when the app is shutting down.
+ */
shuttingDown: function () {
AppDispatcher.dispatch({
- actionType: AppConstants.APP_SHUTTING_DOWN
+ actionType: appConstants.APP_SHUTTING_DOWN
+ })
+ },
+
+ /**
+ * Dispatches a message when a download is being revealed.
+ * Typically this will open the download directory in finder / explorer and select the icon.
+ * @param {string} downloadId - ID of the download being revealed
+ */
+ downloadRevealed: function (downloadId) {
+ AppDispatcher.dispatch({
+ actionType: appConstants.APP_DOWNLOAD_REVEALED,
+ downloadId
+ })
+ },
+
+ /**
+ * Dispatches a message when a download is being opened.
+ * @param {string} downloadId - ID of the download being opened
+ */
+ downloadOpened: function (downloadId) {
+ AppDispatcher.dispatch({
+ actionType: appConstants.APP_DOWNLOAD_OPENED,
+ downloadId
+ })
+ },
+
+ /**
+ * Dispatches a message when an electron download action is being performed (pause, resume, cancel)
+ * @param {string} downloadId - ID of the download item the action is being performed to
+ * @param {string} downloadAction - the action to perform from constants/electronDownloadItemActions.js
+ */
+ downloadActionPerformed: function (downloadId, downloadAction) {
+ AppDispatcher.dispatch({
+ actionType: appConstants.APP_DOWNLOAD_ACTION_PERFORMED,
+ downloadId,
+ downloadAction
+ })
+ },
+
+ /**
+ * Dispatches a message when a download URL is being copied to the clipboard
+ * @param {string} downloadId - ID of the download item being copied to the clipboard
+ */
+ downloadCopiedToClipboard: function (downloadId) {
+ AppDispatcher.dispatch({
+ actionType: appConstants.APP_DOWNLOAD_COPIED_TO_CLIPBOARD,
+ downloadId
+ })
+ },
+
+ /**
+ * Dispatches a message when a download is being deleted
+ * @param {string} downloadId - ID of the download item being deleted
+ */
+ downloadDeleted: function (downloadId) {
+ AppDispatcher.dispatch({
+ actionType: appConstants.APP_DOWNLOAD_DELETED,
+ downloadId
+ })
+ },
+
+ /**
+ * Dispatches a message when a download is being cleared
+ * @param {string} downloadId - ID of the download item being cleared
+ */
+ downloadCleared: function (downloadId) {
+ AppDispatcher.dispatch({
+ actionType: appConstants.APP_DOWNLOAD_CLEARED,
+ downloadId
+ })
+ },
+
+ /**
+ * Dispatches a message when a download is being redownloaded
+ * @param {string} downloadId - ID of the download item being redownloaded
+ */
+ downloadRedownloaded: function (downloadId) {
+ AppDispatcher.dispatch({
+ actionType: appConstants.APP_DOWNLOAD_REDOWNLOADED,
+ downloadId
})
}
}
diff --git a/js/actions/downloadActions.js b/js/actions/downloadActions.js
deleted file mode 100644
index d22a8bb4bef..00000000000
--- a/js/actions/downloadActions.js
+++ /dev/null
@@ -1,85 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-'use strict'
-
-const electron = require('electron')
-
-let shell, ipc, clipboard, getCurrentWebContents
-if (process.type === 'browser') {
- shell = electron.shell
- ipc = electron.ipcRenderer
- clipboard = electron.clipboard
- getCurrentWebContents = electron.getCurrentWebContents
-} else {
- shell = electron.remote.shell
- ipc = electron.ipcRenderer
- clipboard = electron.remote.clipboard
- getCurrentWebContents = electron.remote.getCurrentWebContents
-}
-
-const appDownloadActions = require('../constants/downloadActions')
-const appActions = require('../actions/appActions')
-const messages = require('../constants/messages')
-// const fs = require('fs')
-// const path = require('path')
-
-/**
- * Creates an action function for the specified app download action
- * @param {string} appDownloadAction - The ID of the app action to send
- */
-const appActionForDownload = (appDownloadAction) => (downloadId) =>
- ipc.send(messages.DOWNLOAD_ACTION, downloadId, appDownloadAction)
-
-const downloadActions = {
- cancelDownload: appActionForDownload(appDownloadActions.CANCEL),
- pauseDownload: appActionForDownload(appDownloadActions.PAUSE),
- resumeDownload: appActionForDownload(appDownloadActions.RESUME),
- copyLinkToClipboard: function (download) {
- clipboard.writeText(download.get('url'))
- // disabling notificiations from the main window until we have a
- // better way to do it
- // void new window.Notification(locale.translation('urlCopied'))
- },
- openDownloadPath: function (download) {
- // fs.exists(download.get('savePath'), (exists) => {
- // if (exists) {
- // shell.openItem(download.get('savePath'))
- // } else {
- // shell.beep()
- // }
- // })
- },
- locateShellPath: function (download) {
- // fs.exists(download.get('savePath'), (exists) => {
- // if (exists) {
- // shell.showItemInFolder(download.get('savePath'))
- // } else {
- // shell.openItem(path.dirname(download.get('savePath')))
- // }
- // })
- },
- hideDownloadsToolbar: function () {
- if (process.type === 'renderer') {
- const windowActions = require('../actions/windowActions')
- windowActions.setDownloadsToolbarVisible(false)
- }
- },
- deleteDownload: function (downloads, download, downloadId) {
- shell.moveItemToTrash(download.get('savePath'))
- downloadActions.clearDownload(downloads, downloadId)
- },
- clearDownload: function (downloads, downloadId) {
- if (downloads && downloads.size === 1) {
- downloadActions.hideDownloadsToolbar()
- }
- appActions.mergeDownloadDetail(downloadId)
- },
- redownloadURL: function (download, downloadId) {
- getCurrentWebContents().downloadURL(download.get('url'))
- downloadActions.clearDownload(undefined, downloadId)
- }
-}
-
-module.exports = downloadActions
diff --git a/js/components/downloadsBar.js b/js/components/downloadsBar.js
index 3123163eb57..56899af1100 100644
--- a/js/components/downloadsBar.js
+++ b/js/components/downloadsBar.js
@@ -7,11 +7,46 @@ const ImmutableComponent = require('./immutableComponent')
const Button = require('./button')
const contextMenus = require('../contextMenus')
const downloadStates = require('../constants/downloadStates')
-const downloadActions = require('../actions/downloadActions')
+const {PAUSE, RESUME, CANCEL} = require('../../app/common/constants/electronDownloadItemActions')
+const appActions = require('../actions/appActions')
+const windowActions = require('../actions/windowActions')
const downloadUtil = require('../state/downloadUtil')
const cx = require('../lib/classSet')
class DownloadItem extends ImmutableComponent {
+ constructor () {
+ super()
+ this.onRevealDownload = this.onRevealDownload.bind(this)
+ this.onOpenDownload = this.onOpenDownload.bind(this)
+ this.onPauseDownload = this.onDownloadActionPerformed.bind(this, PAUSE)
+ this.onResumeDownload = this.onDownloadActionPerformed.bind(this, RESUME)
+ this.onCancelDownload = this.onDownloadActionPerformed.bind(this, CANCEL)
+ this.onClearDownload = this.onClearDownload.bind(this)
+ this.onDeleteDownload = this.onDeleteDownload.bind(this)
+ this.onRedownload = this.onRedownload.bind(this)
+ this.onCopyLinkToClipboard = this.onCopyLinkToClipboard.bind(this)
+ }
+ onRevealDownload () {
+ appActions.downloadRevealed(this.props.downloadId)
+ }
+ onOpenDownload () {
+ appActions.downloadOpened(this.props.downloadId)
+ }
+ onClearDownload () {
+ appActions.downloadCleared(this.props.downloadId)
+ }
+ onDeleteDownload () {
+ appActions.downloadDeleted(this.props.downloadId)
+ }
+ onDownloadActionPerformed (downloadAction) {
+ appActions.downloadActionPerformed(this.props.downloadId, downloadAction)
+ }
+ onCopyLinkToClipboard () {
+ appActions.downloadCopiedToClipboard(this.props.downloadId)
+ }
+ onRedownload () {
+ appActions.downloadRedownloaded(this.props.downloadId)
+ }
get isInterrupted () {
return this.props.download.get('state') === downloadStates.INTERRUPTED
}
@@ -39,7 +74,7 @@ class DownloadItem extends ImmutableComponent {
}
return
{
downloadUtil.shouldAllowPause(this.props.download)
- ?
+ ?
: null
}
{
downloadUtil.shouldAllowResume(this.props.download)
- ?
+ ?
: null
}
{
downloadUtil.shouldAllowCancel(this.props.download)
- ?
+ ?
: null
}
{
downloadUtil.shouldAllowRedownload(this.props.download)
- ?
+ ?
: null
}
{
downloadUtil.shouldAllowCopyLink(this.props.download)
- ?
+ ?
: null
}
{
downloadUtil.shouldAllowOpenDownloadLocation(this.props.download)
- ?
+ ?
: null
}
{
downloadUtil.shouldAllowDelete(this.props.download)
- ?
+ ?
: null
}
{
downloadUtil.shouldAllowRemoveFromList(this.props.download)
- ?
+ ?
: null
}
@@ -112,6 +147,13 @@ class DownloadItem extends ImmutableComponent {
}
class DownloadsBar extends ImmutableComponent {
+ constructor () {
+ super()
+ this.onHideDownloadsToolbar = this.onHideDownloadsToolbar.bind(this)
+ }
+ onHideDownloadsToolbar () {
+ windowActions.setDownloadsToolbarVisible(false)
+ }
render () {
const downloadItemWidth = Number.parseInt(window.getComputedStyle(document.querySelector(':root')).getPropertyValue('--download-item-width'), 10)
const downloadItemMargin = Number.parseInt(window.getComputedStyle(document.querySelector(':root')).getPropertyValue('--download-item-margin'), 10)
@@ -135,7 +177,7 @@ class DownloadsBar extends ImmutableComponent {