diff --git a/app/extensions/brave/about-autofill.html b/app/extensions/brave/about-autofill.html
new file mode 100644
index 00000000000..40ec9641bcf
--- /dev/null
+++ b/app/extensions/brave/about-autofill.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/extensions/brave/locales/en-US/app.properties b/app/extensions/brave/locales/en-US/app.properties
index 01ab7bb9038..ec93ead057e 100644
--- a/app/extensions/brave/locales/en-US/app.properties
+++ b/app/extensions/brave/locales/en-US/app.properties
@@ -175,3 +175,15 @@ allSiteCookies=All site cookies
clear=Clear
clearDataWarning=Warning: Selected data, back to the day you installed Brave will be cleared and cannot be undone.
clearBrowsingData=Clear browsing data
+nameOnCard=Name
+creditCardNumber=Card Number
+expirationDate=Expiration date
+nameOnAddress=Name
+organization=Organization
+streetAddress=Street Address
+city=City
+state=State
+postalCode=Postal Code
+country=Country
+phone=Phone
+email=Email
diff --git a/app/extensions/brave/locales/en-US/autofill.properties b/app/extensions/brave/locales/en-US/autofill.properties
new file mode 100644
index 00000000000..5c9bc2ad7c8
--- /dev/null
+++ b/app/extensions/brave/locales/en-US/autofill.properties
@@ -0,0 +1,19 @@
+autofillTitle=Autofill Settings
+addresses=Addresses
+creditCards=Credit Cards
+addAddress=Add Address
+addCreditCard=Add Credit Card
+nameOnCard=Name on card
+creditCardNumber=Credit card number
+expirationDate=Expiration date
+noCreditCardsSaved=No saved credit cards
+nameOnAddress=Name
+organization=Organization
+streetAddress=Street Address
+city=City
+state=State
+postalCode=Postal Code
+country=Country
+phone=Phone
+email=Email
+noAddressesSaved=No saved addresses
diff --git a/app/extensions/brave/locales/en-US/preferences.properties b/app/extensions/brave/locales/en-US/preferences.properties
index 7e5191aafca..9e907c1adf2 100644
--- a/app/extensions/brave/locales/en-US/preferences.properties
+++ b/app/extensions/brave/locales/en-US/preferences.properties
@@ -164,3 +164,6 @@ allSiteCookies=All site cookies
passwordsAndForms=Passwords and Forms
tabSettings=Tab Settings
clearBrowsingDataNow=Clear Browsing Data Now...
+autofillSettings=Autofill Settings
+manageAutofillData=Manage Autofill Data...
+enableAutofill=Enable Autofill
diff --git a/app/filtering.js b/app/filtering.js
index ebab24ea6de..5c6dd503c1e 100644
--- a/app/filtering.js
+++ b/app/filtering.js
@@ -570,3 +570,56 @@ module.exports.setDefaultZoomLevel = (zoom) => {
ses.userPrefs.setDefaultZoomLevel(zoom)
}
}
+
+module.exports.addAutofillAddress = (detail) => {
+ let guidMap = {}
+ for (let partition in registeredSessions) {
+ let ses = registeredSessions[partition]
+ let guid = ses.autofill.addProfile({
+ full_name: detail.name,
+ company_name: detail.organization,
+ street_address: detail.streetAddress,
+ city: detail.city,
+ state: detail.state,
+ postal_code: detail.postalCode,
+ country_code: detail.country,
+ phone: detail.phone,
+ email: detail.email
+ })
+ guidMap[partition] = guid
+ }
+ return guidMap
+}
+
+module.exports.removeAutofillAddress = (guid) => {
+ for (let partition in registeredSessions) {
+ let ses = registeredSessions[partition]
+ if (guid[partition] !== undefined) {
+ ses.autofill.removeProfile(guid[partition])
+ }
+ }
+}
+
+module.exports.addAutofillCreditCard = (detail) => {
+ let guidMap = {}
+ for (let partition in registeredSessions) {
+ let ses = registeredSessions[partition]
+ let guid = ses.autofill.addCreditCard({
+ name: detail.name,
+ card_number: detail.card,
+ expiration_month: detail.month,
+ expiration_year: detail.year
+ })
+ guidMap[partition] = guid
+ }
+ return guidMap
+}
+
+module.exports.removeAutofillCreditCard = (guid) => {
+ for (let partition in registeredSessions) {
+ let ses = registeredSessions[partition]
+ if (guid[partition] !== undefined) {
+ ses.autofill.removeCreditCard(guid[partition])
+ }
+ }
+}
diff --git a/app/index.js b/app/index.js
index ef3e1f6187e..5995c609623 100644
--- a/app/index.js
+++ b/app/index.js
@@ -61,6 +61,7 @@ const ledger = require('./ledger')
const flash = require('../js/flash')
const contentSettings = require('../js/state/contentSettings')
const FrameStateUtil = require('../js/state/frameStateUtil')
+const privacy = require('../js/state/privacy')
// Used to collect the per window state when shutting down the application
let perWindowState = []
@@ -398,6 +399,7 @@ app.on('ready', () => {
return loadedPerWindowState
}).then((loadedPerWindowState) => {
contentSettings.init()
+ privacy.init()
Extensions.init()
Filtering.init()
SiteHacks.init()
@@ -749,6 +751,14 @@ app.on('ready', () => {
}
})
+ ipcMain.on(messages.REMOVE_AUTOFILL_ADDRESS, (e, address) => {
+ appActions.removeAutofillAddress(address)
+ })
+
+ ipcMain.on(messages.REMOVE_AUTOFILL_CREDIT_CARD, (e, card) => {
+ appActions.removeAutofillCreditCard(card)
+ })
+
// Setup the crash handling
CrashHerald.init()
diff --git a/js/about/aboutActions.js b/js/about/aboutActions.js
index 4253df12e48..8321e17161b 100644
--- a/js/about/aboutActions.js
+++ b/js/about/aboutActions.js
@@ -133,6 +133,30 @@ const AboutActions = {
setLedgerEnabled: function (enabled) {
ipc.send(messages.LEDGER_ENABLE, enabled)
+ },
+
+ addAutofillAddress: function () {
+ ipc.sendToHost(messages.ADD_AUTOFILL_ADDRESS)
+ },
+
+ removeAutofillAddress: function (address) {
+ ipc.send(messages.REMOVE_AUTOFILL_ADDRESS, address)
+ },
+
+ editAutofillAddress: function (address) {
+ ipc.sendToHost(messages.EDIT_AUTOFILL_ADDRESS, address)
+ },
+
+ addAutofillCreditCard: function () {
+ ipc.sendToHost(messages.ADD_AUTOFILL_CREDIT_CARD)
+ },
+
+ removeAutofillCreditCard: function (card) {
+ ipc.send(messages.REMOVE_AUTOFILL_CREDIT_CARD, card)
+ },
+
+ editAutofillCreditCard: function (card) {
+ ipc.sendToHost(messages.EDIT_AUTOFILL_CREDIT_CARD, card)
}
}
module.exports = AboutActions
diff --git a/js/about/autofill.js b/js/about/autofill.js
new file mode 100644
index 00000000000..bc4d81a5a76
--- /dev/null
+++ b/js/about/autofill.js
@@ -0,0 +1,204 @@
+/* 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 React = require('react')
+const messages = require('../constants/messages')
+const Immutable = require('immutable')
+const ImmutableComponent = require('../components/immutableComponent')
+const aboutActions = require('./aboutActions')
+const Button = require('../components/button')
+
+const ipc = window.chrome.ipc
+
+require('../../less/about/autofill.less')
+require('../../node_modules/font-awesome/css/font-awesome.css')
+
+class AddressItem extends ImmutableComponent {
+ constructor () {
+ super()
+ this.onDelete = this.onDelete.bind(this)
+ this.onEdit = this.onEdit.bind(this)
+ }
+
+ onDelete () {
+ aboutActions.removeAutofillAddress(this.props.address.toJS())
+ }
+
+ onEdit () {
+ aboutActions.editAutofillAddress(this.props.address.toJS())
+ }
+
+ render () {
+ const address = this.props.address
+ return
+
+
+
+ |
+ {address.get('name')} |
+ {address.get('organization')} |
+ {address.get('streetAddress')} |
+ {address.get('city')} |
+ {address.get('state')} |
+ {address.get('postalCode')} |
+ {address.get('country')} |
+ {address.get('phone')} |
+ {address.get('email')} |
+
+
+
+ |
+
+ }
+}
+
+class CreditCardItem extends ImmutableComponent {
+ constructor () {
+ super()
+ this.onDelete = this.onDelete.bind(this)
+ this.onEdit = this.onEdit.bind(this)
+ }
+
+ onDelete () {
+ aboutActions.removeAutofillCreditCard(this.props.creditCard.toJS())
+ }
+
+ onEdit () {
+ aboutActions.editAutofillCreditCard(this.props.creditCard.toJS())
+ }
+
+ render () {
+ const creditCard = this.props.creditCard
+ return
+
+
+
+ |
+ {creditCard.get('name')} |
+ {creditCard.get('card')} |
+
+ {creditCard.get('month') + '/' + creditCard.get('year')}
+ |
+
+
+
+ |
+
+ }
+}
+
+class AboutAutofill extends React.Component {
+ constructor () {
+ super()
+ this.state = {
+ addressesDetails: new Immutable.List(),
+ creditCardsDetails: new Immutable.List()
+ }
+ ipc.on(messages.AUTOFILL_ADDRESSES_UPDATED, (e, detail) => {
+ if (detail) {
+ this.setState({
+ addressesDetails: Immutable.fromJS(detail)
+ })
+ }
+ })
+ ipc.on(messages.AUTOFILL_CREDIT_CARDS_UPDATED, (e, detail) => {
+ if (detail) {
+ this.setState({
+ creditCardsDetails: Immutable.fromJS(detail)
+ })
+ }
+ })
+ this.onAddAddress = this.onAddAddress.bind(this)
+ this.onAddCreditCard = this.onAddCreditCard.bind(this)
+ }
+
+ onAddAddress () {
+ aboutActions.addAutofillAddress()
+ }
+
+ onAddCreditCard () {
+ aboutActions.addAutofillCreditCard()
+ }
+
+ get isAddresssEmpty () {
+ return !this.state.addressesDetails || !this.state.addressesDetails.size
+ }
+
+ get isCreditCardsEmpty () {
+ return !this.state.creditCardsDetails || !this.state.creditCardsDetails.size
+ }
+
+ render () {
+ var savedAddresssPage = this.isAddresssEmpty
+ ?
+ :
+
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+ {
+ this.state.addressesDetails.sort((a, b) => {
+ return a.get('name') > b.get('name') ? 1 : -1
+ }).map((item) =>
+ )
+ }
+
+
+
+
+
+ var savedCreditCardsPage = this.isCreditCardsEmpty
+ ?
+ :
+
+
+
+
+
+ |
+ |
+ |
+ |
+
+
+
+ {
+ this.state.creditCardsDetails.sort((a, b) => {
+ return a.get('name') > b.get('name') ? 1 : -1
+ }).map((item) =>
+ )
+ }
+
+
+
+
+ return
+
+ {savedAddresssPage}
+
+ {savedCreditCardsPage}
+
+
+ }
+}
+
+module.exports =
diff --git a/js/about/entry.js b/js/about/entry.js
index 8891698c559..20351284766 100644
--- a/js/about/entry.js
+++ b/js/about/entry.js
@@ -38,6 +38,9 @@ switch (getBaseUrl(getSourceAboutUrl(window.location.href))) {
break
case 'about:history':
element = require('./history')
+ break
+ case 'about:autofill':
+ element = require('./autofill')
}
if (element) {
diff --git a/js/about/preferences.js b/js/about/preferences.js
index 8b6564fe109..00f15f4519f 100644
--- a/js/about/preferences.js
+++ b/js/about/preferences.js
@@ -803,6 +803,14 @@ class SecurityTab extends ImmutableComponent {
: null
}
+
+
+
+
+
diff --git a/js/actions/appActions.js b/js/actions/appActions.js
index 2d8569a94d5..ffb04dde0e2 100644
--- a/js/actions/appActions.js
+++ b/js/actions/appActions.js
@@ -367,6 +367,36 @@ const appActions = {
actionType: AppConstants.APP_CLEAR_DATA,
clearDataDetail
})
+ },
+
+ addAutofillAddress: function (detail, originalDetail) {
+ AppDispatcher.dispatch({
+ actionType: AppConstants.APP_ADD_AUTOFILL_ADDRESS,
+ detail,
+ originalDetail
+ })
+ },
+
+ removeAutofillAddress: function (detail) {
+ AppDispatcher.dispatch({
+ actionType: AppConstants.APP_REMOVE_AUTOFILL_ADDRESS,
+ detail
+ })
+ },
+
+ addAutofillCreditCard: function (detail, originalDetail) {
+ AppDispatcher.dispatch({
+ actionType: AppConstants.APP_ADD_AUTOFILL_CREDIT_CARD,
+ detail,
+ originalDetail
+ })
+ },
+
+ removeAutofillCreditCard: function (detail) {
+ AppDispatcher.dispatch({
+ actionType: AppConstants.APP_REMOVE_AUTOFILL_CREDIT_CARD,
+ detail
+ })
}
}
diff --git a/js/actions/windowActions.js b/js/actions/windowActions.js
index 0656d734a39..64501a1f3b0 100644
--- a/js/actions/windowActions.js
+++ b/js/actions/windowActions.js
@@ -951,6 +951,28 @@ const windowActions = {
actionType: WindowConstants.WINDOW_SET_CLEAR_BROWSING_DATA_DETAIL,
clearBrowsingDataDetail
})
+ },
+
+ /**
+ * Sets the manage autofill address popup detail
+ */
+ setAutofillAddressDetail: function (currentDetail, originalDetail) {
+ dispatch({
+ actionType: WindowConstants.WINDOW_SET_AUTOFILL_ADDRESS_DETAIL,
+ currentDetail,
+ originalDetail
+ })
+ },
+
+ /**
+ * Sets the manage autofill credit cards popup detail
+ */
+ setAutofillCreditCardDetail: function (currentDetail, originalDetail) {
+ dispatch({
+ actionType: WindowConstants.WINDOW_SET_AUTOFILL_CREDIT_CARD_DETAIL,
+ currentDetail,
+ originalDetail
+ })
}
}
diff --git a/js/components/autofillAddressPanel.js b/js/components/autofillAddressPanel.js
new file mode 100644
index 00000000000..bb0c16cab9b
--- /dev/null
+++ b/js/components/autofillAddressPanel.js
@@ -0,0 +1,151 @@
+/* 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 React = require('react')
+const ImmutableComponent = require('./immutableComponent')
+const Dialog = require('./dialog')
+const Button = require('./button')
+const windowActions = require('../actions/windowActions')
+const appActions = require('../actions/appActions')
+const KeyCodes = require('../constants/keyCodes')
+
+class AutofillAddressPanel extends ImmutableComponent {
+ constructor () {
+ super()
+ this.onNameChange = this.onNameChange.bind(this)
+ this.onOrganizationChange = this.onOrganizationChange.bind(this)
+ this.onStreetAddressChange = this.onStreetAddressChange.bind(this)
+ this.onCityChange = this.onCityChange.bind(this)
+ this.onStateChange = this.onStateChange.bind(this)
+ this.onPostalCodeChange = this.onPostalCodeChange.bind(this)
+ this.onCountryChange = this.onCountryChange.bind(this)
+ this.onPhoneChange = this.onPhoneChange.bind(this)
+ this.onEmailChange = this.onEmailChange.bind(this)
+ this.onKeyDown = this.onKeyDown.bind(this)
+ this.onSave = this.onSave.bind(this)
+ this.onClick = this.onClick.bind(this)
+ }
+ onNameChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('name', e.target.value)
+ windowActions.setAutofillAddressDetail(currentDetail, this.props.originalDetail)
+ }
+ onOrganizationChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('organization', e.target.value)
+ windowActions.setAutofillAddressDetail(currentDetail, this.props.originalDetail)
+ }
+ onStreetAddressChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('streetAddress', e.target.value)
+ windowActions.setAutofillAddressDetail(currentDetail, this.props.originalDetail)
+ }
+ onCityChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('city', e.target.value)
+ windowActions.setAutofillAddressDetail(currentDetail, this.props.originalDetail)
+ }
+ onStateChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('state', e.target.value)
+ windowActions.setAutofillAddressDetail(currentDetail, this.props.originalDetail)
+ }
+ onPostalCodeChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('postalCode', e.target.value)
+ windowActions.setAutofillAddressDetail(currentDetail, this.props.originalDetail)
+ }
+ onCountryChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('country', e.target.value)
+ windowActions.setAutofillAddressDetail(currentDetail, this.props.originalDetail)
+ }
+ onPhoneChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('phone', e.target.value)
+ windowActions.setAutofillAddressDetail(currentDetail, this.props.originalDetail)
+ }
+ onEmailChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('email', e.target.value)
+ windowActions.setAutofillAddressDetail(currentDetail, this.props.originalDetail)
+ }
+ onKeyDown (e) {
+ switch (e.keyCode) {
+ case KeyCodes.ENTER:
+ this.onSave()
+ break
+ case KeyCodes.ESC:
+ this.props.onHide()
+ break
+ }
+ }
+ onSave () {
+ appActions.addAutofillAddress(this.props.currentDetail, this.props.originalDetail)
+ this.props.onHide()
+ }
+ onClick (e) {
+ e.stopPropagation()
+ }
+ render () {
+ return
+ }
+}
+
+module.exports = AutofillAddressPanel
diff --git a/js/components/autofillCreditCardPanel.js b/js/components/autofillCreditCardPanel.js
new file mode 100644
index 00000000000..0867dc3cdff
--- /dev/null
+++ b/js/components/autofillCreditCardPanel.js
@@ -0,0 +1,112 @@
+/* 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 React = require('react')
+const ImmutableComponent = require('./immutableComponent')
+const Dialog = require('./dialog')
+const Button = require('./button')
+const windowActions = require('../actions/windowActions')
+const appActions = require('../actions/appActions')
+const KeyCodes = require('../constants/keyCodes')
+
+class AutofillCreditCardPanel extends ImmutableComponent {
+ constructor () {
+ super()
+ this.onNameChange = this.onNameChange.bind(this)
+ this.onCardChange = this.onCardChange.bind(this)
+ this.onExpMonthChange = this.onExpMonthChange.bind(this)
+ this.onExpYearChange = this.onExpYearChange.bind(this)
+ this.onKeyDown = this.onKeyDown.bind(this)
+ this.onSave = this.onSave.bind(this)
+ this.onClick = this.onClick.bind(this)
+ }
+ onNameChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('name', e.target.value)
+ windowActions.setAutofillCreditCardDetail(currentDetail, this.props.originalDetail)
+ }
+ onCardChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('card', e.target.value)
+ windowActions.setAutofillCreditCardDetail(currentDetail, this.props.originalDetail)
+ }
+ onExpMonthChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('month', e.target.value)
+ windowActions.setAutofillCreditCardDetail(currentDetail, this.props.originalDetail)
+ }
+ onExpYearChange (e) {
+ let currentDetail = this.props.currentDetail
+ currentDetail = currentDetail.set('year', e.target.value)
+ windowActions.setAutofillCreditCardDetail(currentDetail, this.props.originalDetail)
+ }
+ onKeyDown (e) {
+ switch (e.keyCode) {
+ case KeyCodes.ENTER:
+ this.onSave()
+ break
+ case KeyCodes.ESC:
+ this.props.onHide()
+ break
+ }
+ }
+ onSave () {
+ appActions.addAutofillCreditCard(this.props.currentDetail, this.props.originalDetail)
+ this.props.onHide()
+ }
+ onClick (e) {
+ e.stopPropagation()
+ }
+ get displayNameOnCard () {
+ return this.props.currentDetail.get('name')
+ }
+ get displayCreditCardNumber () {
+ return this.props.currentDetail.get('card')
+ }
+ render () {
+ var ExpMonth = []
+ for (let i = 1; i <= 12; ++i) {
+ ExpMonth.push()
+ }
+ var ExpYear = []
+ var today = new Date()
+ var year = today.getFullYear()
+ for (let i = year; i <= year + 9; ++i) {
+ ExpYear.push()
+ }
+
+ return
+ }
+}
+
+module.exports = AutofillCreditCardPanel
diff --git a/js/components/frame.js b/js/components/frame.js
index 9b8c09b097b..74a700a9b6a 100644
--- a/js/components/frame.js
+++ b/js/components/frame.js
@@ -105,6 +105,9 @@ class Frame extends ImmutableComponent {
}
} else if (location === 'about:flash') {
this.webview.send(messages.BRAVERY_DEFAULTS_UPDATED, this.braveryDefaults)
+ } else if (location === 'about:autofill') {
+ this.webview.send(messages.AUTOFILL_ADDRESSES_UPDATED, this.props.autofillAddresses.toJS())
+ this.webview.send(messages.AUTOFILL_CREDIT_CARDS_UPDATED, this.props.autofillCreditCards.toJS())
}
// send state to about pages
@@ -593,6 +596,19 @@ class Frame extends ImmutableComponent {
this.webview.addEventListener('page-title-updated', ({title}) => {
windowActions.setFrameTitle(this.frame, title)
})
+ this.webview.addEventListener('show-autofill-settings', (e) => {
+ windowActions.newFrame({ location: 'about:autofill' }, true)
+ })
+ this.webview.addEventListener('update-autofill-popup-data-list-values', (e) => {
+ console.log(e)
+ })
+ this.webview.addEventListener('show-autofill-popup', (e) => {
+ contextMenus.onShowAutofillMenu(e.suggestions, e.rect, this.frame)
+ })
+ this.webview.addEventListener('hide-autofill-popup', (e) => {
+ // TODO(Anthony): conflict with contextmenu
+ // windowActions.setContextMenuDetail()
+ })
this.webview.addEventListener('ipc-message', (e) => {
let method = () => {}
switch (e.channel) {
@@ -651,6 +667,18 @@ class Frame extends ImmutableComponent {
case messages.CLEAR_BROWSING_DATA_NOW:
windowActions.setClearBrowsingDataDetail({})
break
+ case messages.ADD_AUTOFILL_ADDRESS:
+ windowActions.setAutofillAddressDetail({}, {})
+ break
+ case messages.EDIT_AUTOFILL_ADDRESS:
+ windowActions.setAutofillAddressDetail(e.args[0], e.args[0])
+ break
+ case messages.ADD_AUTOFILL_CREDIT_CARD:
+ windowActions.setAutofillCreditCardDetail({month: '1', year: new Date().getFullYear()}, {})
+ break
+ case messages.EDIT_AUTOFILL_CREDIT_CARD:
+ windowActions.setAutofillCreditCardDetail(e.args[0], e.args[0])
+ break
}
method.apply(this, e.args)
})
diff --git a/js/components/main.js b/js/components/main.js
index 2776a67c908..19a17786686 100644
--- a/js/components/main.js
+++ b/js/components/main.js
@@ -28,6 +28,8 @@ const Button = require('./button')
const SiteInfo = require('./siteInfo')
const BraveryPanel = require('./braveryPanel')
const ClearBrowsingDataPanel = require('./clearBrowsingDataPanel')
+const AutofillAddressPanel = require('./autofillAddressPanel')
+const AutofillCreditCardPanel = require('./autofillCreditCardPanel')
const AddEditBookmark = require('./addEditBookmark')
const LoginRequired = require('./loginRequired')
const ReleaseNotes = require('./releaseNotes')
@@ -79,6 +81,8 @@ class Main extends ImmutableComponent {
this.onHideSiteInfo = this.onHideSiteInfo.bind(this)
this.onHideBraveryPanel = this.onHideBraveryPanel.bind(this)
this.onHideClearBrowsingDataPanel = this.onHideClearBrowsingDataPanel.bind(this)
+ this.onHideAutofillAddressPanel = this.onHideAutofillAddressPanel.bind(this)
+ this.onHideAutofillCreditCardPanel = this.onHideAutofillCreditCardPanel.bind(this)
this.onHideNoScript = this.onHideNoScript.bind(this)
this.onHideReleaseNotes = this.onHideReleaseNotes.bind(this)
this.onBraveMenu = this.onBraveMenu.bind(this)
@@ -541,6 +545,14 @@ class Main extends ImmutableComponent {
windowActions.setClearBrowsingDataDetail()
}
+ onHideAutofillAddressPanel () {
+ windowActions.setAutofillAddressDetail()
+ }
+
+ onHideAutofillCreditCardPanel () {
+ windowActions.setAutofillCreditCardDetail()
+ }
+
onHideNoScript () {
windowActions.setNoScriptVisible(false)
}
@@ -687,6 +699,8 @@ class Main extends ImmutableComponent {
const braveShieldsDisabled = this.braveShieldsDisabled
const braveryPanelIsVisible = !braveShieldsDisabled && this.props.windowState.get('braveryPanelDetail')
const clearBrowsingDataPanelIsVisible = this.props.windowState.get('clearBrowsingDataDetail')
+ const autofillAddressPanelIsVisible = this.props.windowState.get('autofillAddressDetail')
+ const autofillCreditCardPanelIsVisible = this.props.windowState.get('autofillCreditCardDetail')
const activeRequestedLocation = this.activeRequestedLocation
const noScriptIsVisible = this.props.windowState.getIn(['ui', 'noScriptInfo', 'isVisible'])
const releaseNotesIsVisible = this.props.windowState.getIn(['ui', 'releaseNotes', 'isVisible'])
@@ -697,6 +711,8 @@ class Main extends ImmutableComponent {
!siteInfoIsVisible &&
!braveryPanelIsVisible &&
!clearBrowsingDataPanelIsVisible &&
+ !autofillAddressPanelIsVisible &&
+ !autofillCreditCardPanelIsVisible &&
!releaseNotesIsVisible &&
!noScriptIsVisible &&
activeFrame && !activeFrame.getIn(['security', 'loginRequiredDetail'])
@@ -788,6 +804,22 @@ class Main extends ImmutableComponent {
onHide={this.onHideClearBrowsingDataPanel} />
: null
}
+ {
+ autofillAddressPanelIsVisible
+ ?
+ : null
+ }
+ {
+ autofillCreditCardPanelIsVisible
+ ?
+ : null
+ }
{
activeFrame && activeFrame.getIn(['security', 'loginRequiredDetail'])
?
@@ -939,6 +971,8 @@ class Main extends ImmutableComponent {
enableNoScript={this.enableNoScript(this.frameSiteSettings(frame.get('location')))}
isPreview={frame.get('key') === this.props.windowState.get('previewFrameKey')}
isActive={FrameStateUtil.isFrameKeyActive(this.props.windowState, frame.get('key'))}
+ autofillCreditCards={this.props.appState.getIn(['autofill', 'creditCards'])}
+ autofillAddresses={this.props.appState.getIn(['autofill', 'addresses'])}
/>)
}
diff --git a/js/constants/appConfig.js b/js/constants/appConfig.js
index 5168aa55a44..a60fcd50a17 100644
--- a/js/constants/appConfig.js
+++ b/js/constants/appConfig.js
@@ -96,6 +96,7 @@ module.exports = {
'bookmarks.toolbar.showOnlyFavicon': false,
'payments.enabled': false,
'payments.contribution-amount': 5, // USD
+ 'privacy.privacy.autofill-enable': false,
'privacy.do-not-track': false,
'security.passwords.active-password-manager': null, // Set in settings.js by passwordManagerDefault (defaults to built in)
'security.passwords.manager-enabled': true,
diff --git a/js/constants/appConstants.js b/js/constants/appConstants.js
index 907cc7c2869..da69d31ab5a 100644
--- a/js/constants/appConstants.js
+++ b/js/constants/appConstants.js
@@ -34,7 +34,11 @@ const AppConstants = {
APP_HIDE_MESSAGE_BOX: _, /** @param {string} message */
APP_CLEAR_MESSAGE_BOXES: _, /** @param {string} origin */
APP_ADD_WORD: _, /** @param {string} word, @param {boolean} learn */
- APP_SET_DICTIONARY: _ /** @param {string} locale */
+ APP_SET_DICTIONARY: _, /** @param {string} locale */
+ APP_ADD_AUTOFILL_ADDRESS: _,
+ APP_REMOVE_AUTOFILL_ADDRESS: _,
+ APP_ADD_AUTOFILL_CREDIT_CARD: _,
+ APP_REMOVE_AUTOFILL_CREDIT_CARD: _
}
module.exports = mapValuesByKeys(AppConstants)
diff --git a/js/constants/messages.js b/js/constants/messages.js
index b67b6724484..a161482724b 100644
--- a/js/constants/messages.js
+++ b/js/constants/messages.js
@@ -136,6 +136,14 @@ const messages = {
CHECK_FLASH_INSTALLED: _,
ABOUT_COMPONENT_INITIALIZED: _,
CLEAR_BROWSING_DATA_NOW: _,
+ ADD_AUTOFILL_ADDRESS: _,
+ REMOVE_AUTOFILL_ADDRESS: _,
+ EDIT_AUTOFILL_ADDRESS: _,
+ ADD_AUTOFILL_CREDIT_CARD: _,
+ REMOVE_AUTOFILL_CREDIT_CARD: _,
+ EDIT_AUTOFILL_CREDIT_CARD: _,
+ AUTOFILL_ADDRESSES_UPDATED: _,
+ AUTOFILL_CREDIT_CARDS_UPDATED: _,
// HTTPS
CERT_ERROR_ACCEPTED: _, /** @arg {string} url where a cert error was accepted */
CHECK_CERT_ERROR_ACCEPTED: _, /** @arg {string} url to check cert error, @arg {number} key of frame */
diff --git a/js/constants/settings.js b/js/constants/settings.js
index 2f4f2d459d0..b9f6422812e 100644
--- a/js/constants/settings.js
+++ b/js/constants/settings.js
@@ -32,6 +32,8 @@ const settings = {
SHUTDOWN_CLEAR_DOWNLOADS: 'shutdown.clear-downloads',
SHUTDOWN_CLEAR_CACHE: 'shutdown.clear-cache',
SHUTDOWN_CLEAR_ALL_SITE_COOKIES: 'shutdown.clear-all-site-cookies',
+ // Autofill
+ AUTOFILL_ENABLED: 'privacy.autofill-enabled',
// Security Tab: DEPRECATED but still required (for now)
PASSWORD_MANAGER_ENABLED: 'security.passwords.manager-enabled',
ONE_PASSWORD_ENABLED: 'security.passwords.one-password-enabled',
diff --git a/js/constants/windowConstants.js b/js/constants/windowConstants.js
index 9085a0e3718..295165007c1 100644
--- a/js/constants/windowConstants.js
+++ b/js/constants/windowConstants.js
@@ -64,7 +64,9 @@ const windowConstants = {
WINDOW_SET_LOGIN_REQUIRED_DETAIL: _,
WINDOW_SET_STATE: _,
WINDOW_SET_LAST_ZOOM_PERCENTAGE: _,
- WINDOW_SET_CLEAR_BROWSING_DATA_DETAIL: _
+ WINDOW_SET_CLEAR_BROWSING_DATA_DETAIL: _,
+ WINDOW_SET_AUTOFILL_ADDRESS_DETAIL: _,
+ WINDOW_SET_AUTOFILL_CREDIT_CARD_DETAIL: _
}
module.exports = mapValuesByKeys(windowConstants)
diff --git a/js/contextMenus.js b/js/contextMenus.js
index 5c635ace847..7988ae47c4b 100644
--- a/js/contextMenus.js
+++ b/js/contextMenus.js
@@ -353,6 +353,35 @@ function usernameTemplateInit (usernames, origin, action) {
return items
}
+function autofillTemplateInit (suggestions, frame) {
+ let items = []
+ for (let i = 0; i < suggestions.length; ++i) {
+ let value
+ let frontendId = suggestions[i].frontend_id
+ if (frontendId >= 0) { // POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY and Autofill Entry
+ value = suggestions[i].value
+ } else if (frontendId === -1) { // POPUP_ITEM_ID_WARNING_MESSAGE
+ value = 'Disabled due to unsecure connection.'
+ } else if (frontendId === -4) { // POPUP_ITEM_ID_CLEAR_FORM
+ value = 'Clear Form'
+ } else if (frontendId === -5) { // POPUP_ITEM_ID_AUTOFILL_OPTIONS
+ value = 'Autofill Settings'
+ }
+ if (frontendId === -3) { // POPUP_ITEM_ID_SEPARATOR
+ items.push(CommonMenu.separatorMenuItem)
+ } else {
+ items.push({
+ label: value,
+ click: (item, focusedWindow) => {
+ ipc.send('autofill-selection-clicked', frame.get('tabId'), value, frontendId, i)
+ windowActions.setContextMenuDetail()
+ }
+ })
+ }
+ }
+ return items
+}
+
function tabTemplateInit (frameProps) {
const frameKey = frameProps.get('key')
const items = []
@@ -1037,6 +1066,15 @@ function onShowUsernameMenu (usernames, origin, action, boundingRect,
}))
}
+function onShowAutofillMenu (suggestions, boundingRect, frame) {
+ const menuTemplate = autofillTemplateInit(suggestions, frame)
+ windowActions.setContextMenuDetail(Immutable.fromJS({
+ left: boundingRect.x,
+ top: boundingRect.y,
+ template: menuTemplate
+ }))
+}
+
function onMoreBookmarksMenu (activeFrame, allBookmarkItems, overflowItems, e) {
const menuTemplate = moreBookmarksTemplateInit(allBookmarkItems, overflowItems, activeFrame)
const rect = e.target.getBoundingClientRect()
@@ -1144,6 +1182,7 @@ module.exports = {
onBookmarkContextMenu,
onShowBookmarkFolderMenu,
onShowUsernameMenu,
+ onShowAutofillMenu,
onMoreBookmarksMenu,
onBackButtonHistoryMenu,
onForwardButtonHistoryMenu
diff --git a/js/lib/appUrlUtil.js b/js/lib/appUrlUtil.js
index da24c34e1ba..285660cbce6 100644
--- a/js/lib/appUrlUtil.js
+++ b/js/lib/appUrlUtil.js
@@ -68,7 +68,8 @@ module.exports.aboutUrls = new Immutable.Map({
'about:safebrowsing': module.exports.getAppUrl('about-safebrowsing.html'),
'about:passwords': module.exports.getAppUrl('about-passwords.html'),
'about:flash': module.exports.getAppUrl('about-flash.html'),
- 'about:error': module.exports.getAppUrl('about-error.html')
+ 'about:error': module.exports.getAppUrl('about-error.html'),
+ 'about:autofill': module.exports.getAppUrl('about-autofill.html')
})
module.exports.isIntermediateAboutPage = (location) =>
diff --git a/js/state/privacy.js b/js/state/privacy.js
new file mode 100644
index 00000000000..89abe7d4fa7
--- /dev/null
+++ b/js/state/privacy.js
@@ -0,0 +1,34 @@
+/* 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 AppDispatcher = require('../dispatcher/appDispatcher')
+const AppStore = require('../stores/appStore')
+const AppConstants = require('../constants/appConstants')
+const settings = require('../constants/settings')
+const { registerUserPrefs } = require('./userPrefs')
+
+const getAutofillEnabled = (appState) => {
+ let appSettings = appState.get('settings')
+ return appSettings.get(settings.AUTOFILL_ENABLED)
+}
+
+const getPrivacySettings = (appState) => {
+ return { 'autofill.enabled': getAutofillEnabled(appState) }
+}
+
+let updateTrigger
+
+// Register callback to handle all updates
+const doAction = (action) => {
+ if (action.actionType === AppConstants.APP_CHANGE_SETTING) {
+ AppDispatcher.waitFor([AppStore.dispatchToken], () => {
+ updateTrigger()
+ })
+ }
+}
+
+module.exports.init = () => {
+ updateTrigger = registerUserPrefs(() => getPrivacySettings(AppStore.getState()))
+ AppDispatcher.register(doAction)
+}
diff --git a/js/stores/appStore.js b/js/stores/appStore.js
index dff54de3e1b..ca6befc3e59 100644
--- a/js/stores/appStore.js
+++ b/js/stores/appStore.js
@@ -540,6 +540,68 @@ const handleAppAction = (action) => {
Filtering.clearStorageData()
}
break
+ case AppConstants.APP_ADD_AUTOFILL_ADDRESS:
+ {
+ const Filtering = require('../../app/filtering')
+ if (appState.getIn(['autofill', 'addresses']) === undefined) {
+ appState = appState.setIn(['autofill', 'addresses'], new Immutable.List())
+ }
+ appState = appState.setIn(['autofill', 'addresses'],
+ appState.getIn(['autofill', 'addresses']).filterNot((address) => {
+ return Immutable.is(address, action.originalDetail)
+ }))
+ if (action.originalDetail.toJS().guid !== undefined) {
+ Filtering.removeAutofillAddress(action.originalDetail.toJS().guid)
+ }
+
+ let addresses = appState.getIn(['autofill', 'addresses'])
+ const guid = Filtering.addAutofillAddress(action.detail.toJS())
+ let detail = action.detail
+ detail = detail.set('guid', Immutable.fromJS(guid))
+ appState = appState.setIn(['autofill', 'addresses'], addresses.push(Immutable.fromJS(detail)))
+ break
+ }
+ case AppConstants.APP_REMOVE_AUTOFILL_ADDRESS:
+ {
+ const Filtering = require('../../app/filtering')
+ appState = appState.setIn(['autofill', 'addresses'],
+ appState.getIn(['autofill', 'addresses']).filterNot((address) => {
+ return Immutable.is(address, Immutable.fromJS(action.detail))
+ }))
+ Filtering.removeAutofillAddress(action.detail.guid)
+ break
+ }
+ case AppConstants.APP_ADD_AUTOFILL_CREDIT_CARD:
+ {
+ const Filtering = require('../../app/filtering')
+ if (appState.getIn(['autofill', 'creditCards']) === undefined) {
+ appState = appState.setIn(['autofill', 'creditCards'], new Immutable.List())
+ }
+ appState = appState.setIn(['autofill', 'creditCards'],
+ appState.getIn(['autofill', 'creditCards']).filterNot((card) => {
+ return Immutable.is(card, action.originalDetail)
+ }))
+ if (action.originalDetail.toJS().guid !== undefined) {
+ Filtering.removeAutofillCreditCard(action.originalDetail.toJS().guid)
+ }
+
+ let creditCards = appState.getIn(['autofill', 'creditCards'])
+ const guid = Filtering.addAutofillCreditCard(action.detail.toJS())
+ let detail = action.detail
+ detail = detail.set('guid', Immutable.fromJS(guid))
+ appState = appState.setIn(['autofill', 'creditCards'], creditCards.push(Immutable.fromJS(detail)))
+ break
+ }
+ case AppConstants.APP_REMOVE_AUTOFILL_CREDIT_CARD:
+ {
+ const Filtering = require('../../app/filtering')
+ appState = appState.setIn(['autofill', 'creditCards'],
+ appState.getIn(['autofill', 'creditCards']).filterNot((card) => {
+ return Immutable.is(card, Immutable.fromJS(action.detail))
+ }))
+ Filtering.removeAutofillCreditCard(action.detail.guid)
+ break
+ }
default:
}
diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js
index a34c0bbb739..741d6702282 100644
--- a/js/stores/windowStore.js
+++ b/js/stores/windowStore.js
@@ -698,6 +698,30 @@ const doAction = (action) => {
windowState = windowState.set('clearBrowsingDataDetail', Immutable.fromJS(action.clearBrowsingDataDetail))
}
break
+ case WindowConstants.WINDOW_SET_AUTOFILL_ADDRESS_DETAIL:
+ if (!action.currentDetail && !action.originalDetail) {
+ windowState = windowState.delete('autofillAddressDetail')
+ } else {
+ windowState = windowState.mergeIn(['autofillAddressDetail'], {
+ currentDetail: action.currentDetail,
+ originalDetail: action.originalDetail
+ })
+ }
+ // Since the input values of addresses are bound, we need to notify the controls sync.
+ windowStore.emitChanges()
+ break
+ case WindowConstants.WINDOW_SET_AUTOFILL_CREDIT_CARD_DETAIL:
+ if (!action.currentDetail && !action.originalDetail) {
+ windowState = windowState.delete('autofillCreditCardDetail')
+ } else {
+ windowState = windowState.mergeIn(['autofillCreditCardDetail'], {
+ currentDetail: action.currentDetail,
+ originalDetail: action.originalDetail
+ })
+ }
+ // Since the input values of credit cards are bound, we need to notify the controls sync.
+ windowStore.emitChanges()
+ break
case WindowConstants.WINDOW_SET_DOWNLOADS_TOOLBAR_VISIBLE:
windowState = windowState.setIn(['ui', 'downloadsToolbar', 'isVisible'], action.isVisible)
break
diff --git a/less/about/autofill.less b/less/about/autofill.less
new file mode 100644
index 00000000000..65f47015f92
--- /dev/null
+++ b/less/about/autofill.less
@@ -0,0 +1,59 @@
+@import "./common.less";
+
+.autofillPage {
+ margin: 20px;
+
+ .autofillPageContent {
+ border-top: 1px solid @chromeBorderColor;
+
+ .autofillList {
+ padding-top: 10px;
+ overflow: hidden;
+ }
+ }
+}
+
+th {
+ padding: 8px;
+ text-align: left;
+}
+
+tr {
+ cursor: default;
+ overflow: hidden;
+ white-space: nowrap;
+
+ padding: 12px;
+ -webkit-user-select: none;
+
+ .autofillItem {
+ display: flex;
+ }
+
+ &:hover :not(th) {
+ background-color: lighten(@highlightBlue, 30%);
+ }
+}
+
+td:not(.autofillActions) {
+ padding-right: 8px;
+ padding-left: 8px;
+}
+
+.autofillAction {
+ cursor: pointer;
+ padding: 8px;
+ &:hover {
+ background-color: lighten(@highlightBlue, 20%);
+ }
+}
+
+.autofillPageFooter {
+ padding: 10px;
+ margin-bottom: 20px;
+ span {
+ color: grey;
+ cursor: pointer;
+ text-decoration: underline;
+ }
+}
diff --git a/less/about/preferences.less b/less/about/preferences.less
index 91aa5c774a8..70019c98ed7 100644
--- a/less/about/preferences.less
+++ b/less/about/preferences.less
@@ -292,6 +292,12 @@ span.browserButton.primaryButton.clearBrowsingDataButton {
margin-top: 20px;
}
+span.browserButton.primaryButton.manageAutofillDataButton {
+ font-size: 0.9em;
+ padding: 5px 20px;
+ margin-top: 20px;
+}
+
.settingsList {
.settingItem {
diff --git a/less/forms.less b/less/forms.less
index b1ffc72421e..324098a195b 100644
--- a/less/forms.less
+++ b/less/forms.less
@@ -99,6 +99,34 @@
}
}
+.manageAutofillDataPanel {
+ .manageAutofillData {
+ .flyoutDialog;
+ background-color: #f7f7f7;
+ border-radius: @borderRadius;
+ max-width: 450px;
+ padding: 0;
+ text-align: left;
+ width: 473px;
+ -webkit-user-select: none;
+ cursor: default;
+ color: #3B3B3B;
+ overflow-y: auto;
+ max-height: 100%;
+
+ .clickable {
+ color: #5B5B5B;
+ &:hover {
+ color: #000;
+ }
+ }
+
+ .formSelect {
+ width: 5.5em
+ }
+ }
+}
+
.braveryPanelContainer {
.braveryPanel {