From b3ce57725a79536f0dd03d575ae89b9cbc182d91 Mon Sep 17 00:00:00 2001 From: NejcZdovc Date: Wed, 7 Jun 2017 16:13:51 -0700 Subject: [PATCH] Refactors PublisherToggle into redux component Resolves #9323 Auditors: @bridiver @bscfliton Test Plan: --- app/common/lib/publisherUtil.js | 71 +++++++++ app/common/state/siteSettingsState.js | 19 +++ .../components/navigation/navigationBar.js | 77 ++++------ .../components/navigation/publisherToggle.js | 137 +++++++---------- app/renderer/components/navigation/urlBar.js | 18 +-- test/unit/app/common/lib/publisherUtilTest.js | 138 ++++++++++++++++++ .../navigation/publisherToggleTest.js | 35 +---- 7 files changed, 316 insertions(+), 179 deletions(-) create mode 100644 app/common/lib/publisherUtil.js create mode 100644 test/unit/app/common/lib/publisherUtilTest.js diff --git a/app/common/lib/publisherUtil.js b/app/common/lib/publisherUtil.js new file mode 100644 index 00000000000..82990456c7e --- /dev/null +++ b/app/common/lib/publisherUtil.js @@ -0,0 +1,71 @@ +/* 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 Immutable = require('immutable') + +// Constants +const settings = require('../../../js/constants/settings') +const siteSettingsState = require('../state/siteSettingsState') + +// Utils +const {getSetting} = require('../../../js/settings') +const {isHttpOrHttps} = require('../../../js/lib/urlutil') +const {isSourceAboutUrl} = require('../../../js/lib/appUrlUtil') + +const visiblePublisher = (state, publisherId) => { + if (publisherId == null) { + return true + } + + // ledgerPaymentsShown is undefined by default until + // user decide to permanently hide the publisher, + // so for icon to be shown it can be everything but false + const hostSettings = siteSettingsState.getSettingsByHost(state, publisherId) + const ledgerPaymentsShown = hostSettings && hostSettings.get('ledgerPaymentsShown') + + return typeof ledgerPaymentsShown === 'boolean' + ? ledgerPaymentsShown + : true +} + +const publisherState = { + enabledForPaymentsPublisher: (state, locationId) => { + const locationInfo = state.get('locationInfo', Immutable.Map()) + const publisherId = locationInfo.getIn([locationId, 'publisher']) + + if (!publisherId) { + return false + } + + const synopsis = state.getIn(['publisherInfo', 'synopsis'], Immutable.Map()) + const hostSettings = siteSettingsState.getSettingsByHost(state, publisherId) + + // All publishers will be enabled by default if AUTO_SUGGEST is ON, + // excluding publishers defined on ledger's exclusion list + const excluded = locationInfo.getIn([locationId, 'exclude']) + const autoSuggestSites = getSetting(settings.AUTO_SUGGEST_SITES) + + // If session is clear then siteSettings is undefined and icon + // will never be shown, but synopsis may not be empty. + // In such cases let's check if synopsis matches current publisherId + const isValidPublisherSynopsis = !!synopsis.map(entry => entry.get('site')) + .includes(publisherId) + + // hostSettings is undefined until user hit addFunds button. + // For such cases check autoSuggestSites for eligibility. + return hostSettings + ? hostSettings.get('ledgerPayments') !== false + : isValidPublisherSynopsis || (autoSuggestSites && !excluded) + }, + + shouldShowAddPublisherButton: (state, location, publisherId) => { + return location && + !isSourceAboutUrl(location) && + getSetting(settings.PAYMENTS_ENABLED) && + isHttpOrHttps(location) && + visiblePublisher(state, publisherId) + } +} + +module.exports = publisherState diff --git a/app/common/state/siteSettingsState.js b/app/common/state/siteSettingsState.js index 6effa414577..f650684bdda 100644 --- a/app/common/state/siteSettingsState.js +++ b/app/common/state/siteSettingsState.js @@ -1,6 +1,18 @@ +/* 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 Immutable = require('immutable') + +// Constants const appConfig = require('../../../js/constants/appConfig') + +// State const siteSettings = require('../../../js/state/siteSettings') +// Utils +const {getHostPattern} = require('../../../js/lib/urlutil') + const api = { getAllSiteSettings: (state, isPrivate) => { if (isPrivate) { @@ -9,6 +21,13 @@ const api = { return state.get('siteSettings') }, + getSettingsByHost: (state, url) => { + const siteSettings = state.get('siteSettings') + const hostPattern = getHostPattern(url) + + return (!siteSettings) ? Immutable.Map() : siteSettings.get(hostPattern) + }, + isNoScriptEnabled (state, settings) { return siteSettings.activeSettings(settings, state, appConfig).noScript === true } diff --git a/app/renderer/components/navigation/navigationBar.js b/app/renderer/components/navigation/navigationBar.js index 32f45623646..00b746bc0ad 100644 --- a/app/renderer/components/navigation/navigationBar.js +++ b/app/renderer/components/navigation/navigationBar.js @@ -24,6 +24,7 @@ const settings = require('../../../../js/constants/settings') // State const tabState = require('../../../common/state/tabState') +const publisherState = require('../../../common/lib/publisherUtil') const frameStateUtil = require('../../../../js/state/frameStateUtil') // Store @@ -31,7 +32,7 @@ const windowStore = require('../../../../js/stores/windowStore') // Utils const cx = require('../../../../js/lib/classSet') -const {isSourceAboutUrl} = require('../../../../js/lib/appUrlUtil') +const {getBaseUrl} = require('../../../../js/lib/appUrlUtil') const siteUtil = require('../../../../js/state/siteUtil') const eventUtil = require('../../../../js/lib/eventUtil') const UrlUtil = require('../../../../js/lib/urlutil') @@ -55,7 +56,7 @@ class NavigationBar extends React.Component { } onToggleBookmark () { - const editing = this.bookmarked + const editing = this.props.isBookmarked // show the AddEditBookmarkHanger control; saving/deleting takes place there let siteDetail = siteUtil.getDetailFromFrame(this.activeFrame, siteTags.BOOKMARK) const key = siteUtil.getSiteKey(siteDetail) @@ -109,11 +110,6 @@ class NavigationBar extends React.Component { } } - get bookmarked () { - return this.props.activeFrameKey !== undefined && - this.props.bookmarked - } - componentDidMount () { ipc.on(messages.SHORTCUT_ACTIVE_FRAME_BOOKMARK, () => this.onToggleBookmark()) ipc.on(messages.SHORTCUT_ACTIVE_FRAME_REMOVE_BOOKMARK, () => this.onToggleBookmark()) @@ -129,10 +125,12 @@ class NavigationBar extends React.Component { const activeTabShowingMessageBox = tabState.isShowingMessageBox(state, activeTabId) const bookmarkDetail = currentWindow.get('bookmarkDetail') const mouseInTitlebar = currentWindow.getIn(['ui', 'mouseInTitlebar']) - const title = activeFrame.get('title') || '' + const title = activeFrame.get('title', '') const loading = activeFrame.get('loading') - const location = activeFrame.get('location') || '' - const navbar = activeFrame.get('navbar') || Immutable.Map() + const location = activeFrame.get('location', '') + const locationId = getBaseUrl(location) + const publisherId = state.getIn(['locationInfo', locationId, 'publisher']) + const navbar = activeFrame.get('navbar', Immutable.Map()) const hasTitle = title && location && title !== location.replace(/^https?:\/\//, '') const titleMode = activeTabShowingMessageBox || @@ -148,33 +146,29 @@ class NavigationBar extends React.Component { ) const props = {} - - props.navbar = navbar - props.sites = state.get('sites') // TODO(nejc) remove, primitives only + // used in renderer props.activeFrameKey = activeFrameKey - props.location = location - props.title = title - props.bookmarked = activeTab && activeTab.get('bookmarked') - props.partitionNumber = activeFrame.get('partitionNumber') || 0 - props.isSecure = activeFrame.getIn(['security', 'isSecure']) - props.loading = loading - props.showBookmarkHanger = bookmarkDetail && bookmarkDetail.get('isBookmarkHanger') - props.mouseInTitlebar = mouseInTitlebar - props.settings = state.get('settings') - props.siteSettings = state.get('siteSettings') - props.synopsis = state.getIn(['publisherInfo', 'synopsis']) || new Immutable.Map() - props.activeTabShowingMessageBox = activeTabShowingMessageBox - props.locationInfo = state.get('locationInfo') props.titleMode = titleMode - props.isWideURLbarEnabled = getSetting(settings.WIDE_URL_BAR) + props.dontRender = activeFrameKey === undefined || + state.get('siteSettings') === undefined + props.isBookmarked = props.activeFrameKey !== undefined && + activeTab && activeTab.get('bookmarked') + props.isWideUrlBarEnabled = getSetting(settings.WIDE_URL_BAR) + props.showBookmarkHanger = bookmarkDetail && bookmarkDetail.get('isBookmarkHanger') + props.isLoading = loading + props.showPublisherToggle = publisherState.shouldShowAddPublisherButton(state, location, publisherId) + props.showHomeButton = !props.titleMode && getSetting(settings.SHOW_HOME_BUTTON) + + // used in other functions + props.navbar = navbar // TODO(nejc) remove, primitives only + props.sites = state.get('sites') // TODO(nejc) remove, primitives only props.activeTabId = activeTabId return props } render () { - if (this.props.activeFrameKey === undefined || - this.props.siteSettings === undefined) { + if (this.props.dontRender) { return null } @@ -183,7 +177,7 @@ class NavigationBar extends React.Component { data-frame-key={this.props.activeFrameKey} className={cx({ titleMode: this.props.titleMode, - [css(styles.navigator_wide)]: this.props.isWideURLbarEnabled + [css(styles.navigator_wide)]: this.props.isWideUrlBarEnabled })}> { this.props.showBookmarkHanger @@ -193,7 +187,7 @@ class NavigationBar extends React.Component { { this.props.titleMode ? null - : this.props.loading + : this.props.isLoading ?