Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Rework alert/confirm to be tab-modal (instead of application-modal) #7107

Merged
merged 6 commits into from
Feb 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/browser/reducers/passwordManagerReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ const init = () => {

if (!(message in passwordCallbacks)) {
// Notification not shown already
appActions.showMessageBox({
appActions.showNotification({
buttons: [
{text: locale.translation('yes')},
{text: locale.translation('no')},
Expand All @@ -228,7 +228,7 @@ const init = () => {

passwordCallbacks[message] = (buttonIndex) => {
delete passwordCallbacks[message]
appActions.hideMessageBox(message)
appActions.hideNotification(message)

if (buttonIndex === 1) {
return
Expand Down
35 changes: 35 additions & 0 deletions app/browser/reducers/tabMessageBoxReducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* 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 tabMessageBox = require('../tabMessageBox')
const tabMessageBoxState = require('../../common/state/tabMessageBoxState')

const tabMessageBoxReducer = (state, action) => {
switch (action.actionType) {
case appConstants.APP_SET_STATE:
state = tabMessageBox.init(state, action)
break
case appConstants.APP_TAB_UPDATED:
state = tabMessageBox.onTabUpdated(state, action)
break
case appConstants.APP_TAB_CLOSED:
state = tabMessageBox.onTabClosed(state, action)
break
case appConstants.APP_TAB_MESSAGE_BOX_SHOWN:
state = tabMessageBoxState.show(state, action)
break
case appConstants.APP_TAB_MESSAGE_BOX_DISMISSED:
state = tabMessageBox.close(state, action)
break
case appConstants.APP_TAB_MESSAGE_BOX_UPDATED:
state = tabMessageBoxState.update(state, action)
break
}
return state
}

module.exports = tabMessageBoxReducer
132 changes: 132 additions & 0 deletions app/browser/tabMessageBox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
const appActions = require('../../js/actions/appActions')
const tabMessageBoxState = require('../common/state/tabMessageBoxState')
const {makeImmutable} = require('../common/state/immutableUtil')

// callbacks for alert, confirm, etc.
let messageBoxCallbacks = {}

const cleanupCallback = (tabId) => {
if (messageBoxCallbacks[tabId]) {
delete messageBoxCallbacks[tabId]
return true
}
return false
}

const tabMessageBox = {
init: (state, action) => {
process.on('window-alert', (webContents, extraData, title, message, defaultPromptText,
shouldDisplaySuppressCheckbox, isBeforeUnloadDialog, isReload, cb) => {
const tabId = webContents.getId()
const detail = {
message,
title,
buttons: ['ok'],
suppress: false,
showSuppress: shouldDisplaySuppressCheckbox
}

tabMessageBox.show(tabId, detail, cb)
})

process.on('window-confirm', (webContents, extraData, title, message, defaultPromptText,
shouldDisplaySuppressCheckbox, isBeforeUnloadDialog, isReload, cb) => {
const tabId = webContents.getId()
const detail = {
message,
title,
buttons: ['ok', 'cancel'],
cancelId: 1,
suppress: false,
showSuppress: shouldDisplaySuppressCheckbox
}

tabMessageBox.show(tabId, detail, cb)
})

process.on('window-prompt', (webContents, extraData, title, message, defaultPromptText,
shouldDisplaySuppressCheckbox, isBeforeUnloadDialog, isReload, cb) => {
console.warn('window.prompt is not supported yet')
let suppress = false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use const

cb(false, '', suppress)
})

return state
},

show: (tabId, detail, cb) => {
if (cb) {
messageBoxCallbacks[tabId] = cb
}
setImmediate(() => {
appActions.tabMessageBoxShown(tabId, detail)
})
},

close: (state, action) => {
action = makeImmutable(action)
const tabId = action.get('tabId')
const detail = action.get('detail')
const cb = messageBoxCallbacks[tabId]
let suppress = false
let result = true
state = tabMessageBoxState.removeDetail(state, action)
if (cb) {
cleanupCallback(tabId)
if (detail) {
if (detail.has('suppress')) {
suppress = detail.get('suppress')
}
if (detail.has('result')) {
result = detail.get('result')
}
cb(result, '', suppress)
} else {
cb(false, '', false)
}
}
return state
},

onTabClosed: (state, action) => {
action = makeImmutable(action)
const tabId = action.getIn(['tabValue', 'tabId'])
if (tabId) {
// remove callback; call w/ defaults
const cb = messageBoxCallbacks[tabId]
if (cb) {
cleanupCallback(tabId)
cb(false, '', false)
}
}
return state
},

onTabUpdated: (state, action) => {
action = makeImmutable(action)
const tabId = action.getIn(['tabValue', 'tabId'])
const detail = tabMessageBoxState.getDetail(state, tabId)
if (detail && detail.get('opener')) {
const url = action.getIn(['tabValue', 'url'])
// check if user has navigated away from site which opened the alert
if (url && url !== detail.get('opener')) {
const removeAction = makeImmutable({tabId: tabId})
// remove detail from state
state = tabMessageBoxState.removeDetail(state, removeAction)
// remove callback; call w/ defaults
const cb = messageBoxCallbacks[tabId]
if (cb) {
cleanupCallback(tabId)
cb(false, '', false)
}
}
}
return state
},

getCallbacks: () => {
return messageBoxCallbacks
}
}

module.exports = tabMessageBox
62 changes: 62 additions & 0 deletions app/common/state/tabMessageBoxState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* 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 tabState = require('./tabState')
const {makeImmutable} = require('./immutableUtil')

const messageBoxDetail = 'messageBoxDetail'

const tabMessageBoxState = {
show: (state, action) => {
state = makeImmutable(state)
action = makeImmutable(action)
const tabId = action.get('tabId')
let tabValue = tabId && tabState.getByTabId(state, tabId)

if (!tabValue) {
return state
}

let detail = action.get('detail')
if (!detail || detail.size === 0) {
tabValue = tabValue.delete(messageBoxDetail)
} else {
detail = detail.set('opener', tabValue.get('url'))
tabValue = tabValue.set(messageBoxDetail, detail)
}
return tabState.updateTab(state, {tabValue, replace: true})
},

getDetail: (state, tabId) => {
if (typeof tabId !== 'number') {
return null
}

const tabValue = tabState.getByTabId(state, tabId)
if (tabValue) {
return tabValue.get(messageBoxDetail) || null
}
return null
},

update: (state, action) => {
return tabMessageBoxState.show(state, action)
},

removeDetail: (state, action) => {
state = makeImmutable(state)
action = makeImmutable(action)
const tabId = action.get('tabId')
let tabValue = tabId && tabState.getByTabId(state, tabId)

if (!tabValue) {
return state
}

tabValue = tabValue.delete(messageBoxDetail)
return tabState.updateTab(state, {tabValue, replace: true})
}
}

module.exports = tabMessageBoxState
15 changes: 14 additions & 1 deletion app/common/state/tabState.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,22 @@ const api = {
return state.set('tabs', tabs)
},

removeTabField: (state, field) => {
state = makeImmutable(state)

let tabs = state.get('tabs')
for (let i = 0; i < tabs.size; i++) {
tabs = tabs.deleteIn([i, field])
}
return state.set('tabs', tabs)
},

getPersistentState: (state) => {
// TODO(bridiver) - handle restoring tabs
state = makeImmutable(state)

state = api.removeTabField(state, 'messageBoxDetail')

// TODO(bridiver) - handle restoring tabs
return state.delete('tabs')
}
}
Expand Down
1 change: 1 addition & 0 deletions app/extensions/brave/locales/en-US/app.properties
Original file line number Diff line number Diff line change
Expand Up @@ -247,4 +247,5 @@ widevinePanelTitle=Brave needs to install Google Widevine to proceed
installAndAllow=Install and Allow
rememberThisDecision=Remember this decision for {{origin}}
copyToClipboard.title=Copy to clipboard
preventMoreAlerts=Prevent this page from creating additional dialogs
copied=Copied!
6 changes: 3 additions & 3 deletions app/filtering.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ function registerPermissionHandler (session, partition) {
permissionCallbacks[message](0, false)
}

appActions.showMessageBox({
appActions.showNotification({
buttons: [
{text: locale.translation('deny')},
{text: locale.translation('allow')}
Expand All @@ -440,8 +440,8 @@ function registerPermissionHandler (session, partition) {

permissionCallbacks[message] = (buttonIndex, persist) => {
permissionCallbacks[message] = null
// hide the message box if this was triggered automatically
appActions.hideMessageBox(message)
// hide the notification if this was triggered automatically
appActions.hideNotification(message)
const result = !!(buttonIndex)
cb(result)
if (persist) {
Expand Down
42 changes: 21 additions & 21 deletions app/importer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ const importer = electron.importer
const dialog = electron.dialog
const BrowserWindow = electron.BrowserWindow
const session = electron.session
const Immutable = require('immutable')
const siteUtil = require('../js/state/siteUtil')
const AppStore = require('../js/stores/appStore')
const siteTags = require('../js/constants/siteTags')
const appActions = require('../js/actions/appActions')
const messages = require('../js/constants/messages')
const settings = require('../js/constants/settings')
const getSetting = require('../js/settings').getSetting
const path = require('path')
const locale = require('./locale')
const tabMessageBox = require('./browser/tabMessageBox')
const {makeImmutable} = require('./common/state/immutableUtil')

var isMergeFavorites = false
var isImportingBookmarks = false
Expand Down Expand Up @@ -88,7 +88,7 @@ importer.on('add-history-page', (e, history, visitSource) => {
}
sites.push(site)
}
appActions.addSite(Immutable.fromJS(sites))
appActions.addSite(makeImmutable(sites))
})

importer.on('add-homepage', (e, detail) => {
Expand Down Expand Up @@ -172,8 +172,8 @@ importer.on('add-bookmarks', (e, bookmarks, topLevelFolder) => {
sites.push(site)
}
}
importedSites = Immutable.fromJS(sites)
appActions.addSite(Immutable.fromJS(sites))
importedSites = makeImmutable(sites)
appActions.addSite(makeImmutable(sites))
})

importer.on('add-favicons', (e, detail) => {
Expand Down Expand Up @@ -228,32 +228,32 @@ importer.on('add-cookies', (e, cookies) => {
}
})

const getActiveTabId = () => {
const tabs = makeImmutable(AppStore.getState()).get('tabs')
const activeTab = tabs.find((tab) => tab.get('active'))
return activeTab && activeTab.get('id')
}

const showImportWarning = function () {
// The timeout is in case there's a call just after the modal to hide the menu.
// showMessageBox is a modal and blocks everything otherwise, so menu would remain open
// while the dialog is displayed.
setTimeout(() => {
dialog.showMessageBox({
title: 'Brave',
const tabId = getActiveTabId()
if (tabId) {
tabMessageBox.show(tabId, {
message: `${locale.translation('closeFirefoxWarning')}`,
icon: path.join(__dirname, '..', 'app', 'extensions', 'brave', 'img', 'braveAbout.png'),
title: 'Brave',
buttons: [locale.translation('closeFirefoxWarningOk')]
})
}, 50)
}
}

const showImportSuccess = function () {
// The timeout is in case there's a call just after the modal to hide the menu.
// showMessageBox is a modal and blocks everything otherwise, so menu would remain open
// while the dialog is displayed.
setTimeout(() => {
dialog.showMessageBox({
title: 'Brave',
const tabId = getActiveTabId()
if (tabId) {
tabMessageBox.show(tabId, {
message: `${locale.translation('importSuccess')}`,
icon: path.join(__dirname, '..', 'app', 'extensions', 'brave', 'img', 'braveAbout.png'),
title: 'Brave',
buttons: [locale.translation('importSuccessOk')]
})
}, 50)
}
}

importer.on('show-warning-dialog', (e) => {
Expand Down
Loading