Skip to content

Commit

Permalink
Refactors UrlBarIcon into redux
Browse files Browse the repository at this point in the history
Resolves brave#9340

Auditors: @bsclifton @bridiver

Test Plan:
  • Loading branch information
NejcZdovc committed Jun 13, 2017
1 parent 7ce06ee commit 0783843
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 72 deletions.
26 changes: 4 additions & 22 deletions app/renderer/components/navigation/urlBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,17 +428,16 @@ class UrlBar extends React.Component {
mergeProps (state, ownProps) {
const currentWindow = state.get('currentWindow')
const activeFrame = frameStateUtil.getActiveFrame(currentWindow) || Immutable.Map()
const activeTabId = activeFrame.get('tabId') || tabState.TAB_ID_NONE
const activeTabId = activeFrame.get('tabId', tabState.TAB_ID_NONE)

const location = tabState.getVisibleURL(state, activeTabId)
const frameLocation = activeFrame.get('location') || ''
const displayEntry = tabState.getVisibleEntry(state, activeTabId) || Immutable.Map()
const displayURL = tabState.getVisibleVirtualURL(state, activeTabId) || ''
const hostValue = displayEntry.get('host', '')
const protocol = displayEntry.get('protocol', '')

const baseUrl = getBaseUrl(location)
const urlbar = activeFrame.getIn(['navbar', 'urlbar']) || Immutable.Map()
const urlbar = activeFrame.getIn(['navbar', 'urlbar'], Immutable.Map())
const urlbarLocation = urlbar.get('location')
const selectedIndex = urlbar.getIn(['suggestions', 'selectedIndex'])
const allSiteSettings = siteSettingsState.getAllSiteSettings(state, activeFrame.get('isPrivate'))
Expand All @@ -464,27 +463,23 @@ class UrlBar extends React.Component {
searchURL = provider.get('search')
}

const isHTTPPage = protocol === 'http' || protocol === 'https'

const props = {}

props.activeTabId = activeTabId
props.activeFrameKey = activeFrame.get('key')
props.frameLocation = frameLocation
props.displayURL = displayURL
props.hostValue = hostValue
props.title = activeFrame.get('title') || ''
props.title = activeFrame.get('title', '')
props.scriptsBlocked = activeFrame.getIn(['noScript', 'blocked'])
props.enableNoScript = siteSettingsState.isNoScriptEnabled(state, braverySettings)
props.showNoScriptInfo = props.enableNoScript && props.scriptsBlocked && props.scriptsBlocked.size
props.isSecure = activeFrame.getIn(['security', 'isSecure'])
props.hasSuggestionMatch = urlbar.getIn(['suggestions', 'hasSuggestionMatch'])
props.startLoadTime = activeFrame.get('startLoadTime')
props.endLoadTime = activeFrame.get('endLoadTime')
props.loading = activeFrame.get('loading')
props.noScriptIsVisible = currentWindow.getIn(['ui', 'noScriptInfo', 'isVisible']) || false
props.menubarVisible = ownProps.menubarVisible
props.activeTabShowingMessageBox = tabState.isShowingMessageBox(state, activeTabId)
props.noBorderRadius = isPublisherButtonEnabled
props.onStop = ownProps.onStop
props.titleMode = ownProps.titleMode
Expand All @@ -498,9 +493,7 @@ class UrlBar extends React.Component {
props.isActive = urlbar.get('active')
props.isSelected = urlbar.get('selected')
props.isFocused = urlbar.get('focused')
props.isHTTPPage = isHTTPPage
props.isWideURLbarEnabled = getSetting(settings.WIDE_URL_BAR)
props.activateSearchEngine = activateSearchEngine
props.searchSelectEntry = urlbarSearchDetail
props.autocompleteEnabled = urlbar.getIn(['suggestions', 'autocompleteEnabled'])
props.searchURL = searchURL
Expand All @@ -519,21 +512,10 @@ class UrlBar extends React.Component {
noBorderRadius: this.props.noBorderRadius
})}
action='#'
id='urlbar'
ref='urlbar'>
id='urlbar'>
<div className='urlbarIconContainer'>
<UrlBarIcon
activateSearchEngine={this.props.activateSearchEngine}
active={this.props.isActive}
isSecure={this.props.isSecure}
isHTTPPage={this.props.isHTTPPage}
loading={this.props.loading}
location={this.props.displayURL}
searchSelectEntry={this.props.searchSelectEntry}
title={this.props.title}
titleMode={this.props.titleMode}
isSearching={this.props.displayURL !== this.props.urlbarLocation}
activeTabShowingMessageBox={this.props.activeTabShowingMessageBox}
/>
</div>
{
Expand Down
91 changes: 71 additions & 20 deletions app/renderer/components/navigation/urlBarIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,45 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')
const ImmutableComponent = require('../immutableComponent')
const Immutable = require('immutable')

// Components
const ReduxComponent = require('../reduxComponent')

// Actions
const windowActions = require('../../../../js/actions/windowActions')
const cx = require('../../../../js/lib/classSet')

// Constants
const dragTypes = require('../../../../js/constants/dragTypes')

// State
const tabState = require('../../../common/state/tabState')

// Utils
const cx = require('../../../../js/lib/classSet')
const dndData = require('../../../../js/dndData')
const UrlUtil = require('../../../../js/lib/urlutil')
const frameStateUtil = require('../../../../js/state/frameStateUtil')
const {isSourceAboutUrl} = require('../../../../js/lib/appUrlUtil')
const {isPotentialPhishingUrl} = require('../../../../js/lib/urlutil')
const windowStore = require('../../../../js/stores/windowStore')
const {getActiveFrame} = require('../../../../js/state/frameStateUtil')

const searchIconSize = 16

class UrlBarIcon extends ImmutableComponent {
constructor () {
super()
class UrlBarIcon extends React.Component {
constructor (props) {
super(props)
this.onClick = this.onClick.bind(this)
this.onDragStart = this.onDragStart.bind(this)
}

get iconCssClasses () {
if (isPotentialPhishingUrl(this.props.location)) {
if (this.props.isPotentialPhishingUrl) {
return ['fa-exclamation-triangle', 'insecure-color']
} else if (this.isSearch) {
return ['fa-search']
} else if (this.isAboutPage && !this.props.titleMode) {
} else if (this.props.isAboutPage && !this.props.titleMode) {
return ['fa-list']
} else if (this.props.isHTTPPage && !this.props.active) {
// NOTE: EV style not approved yet; see discussion at https://github.com/brave/browser-laptop/issues/791
if (this.props.isSecure === true) {
return ['fa-lock']
} else if (this.props.isSecure === false || this.props.isSecure === 2) {
Expand All @@ -37,8 +50,10 @@ class UrlBarIcon extends ImmutableComponent {
return ['fa-unlock']
}
}

return []
}

/**
* search icon:
* - does not show when in title mode
Expand All @@ -50,50 +65,85 @@ class UrlBarIcon extends ImmutableComponent {

const defaultToSearch = (!this.props.isHTTPPage || this.props.active) &&
!this.props.titleMode &&
!this.isAboutPage
!this.props.isAboutPage

return showSearch || defaultToSearch
}
get isAboutPage () {
return isSourceAboutUrl(this.props.location) &&
this.props.location !== 'about:newtab'
}

get iconClasses () {
if (this.props.activateSearchEngine) {
return cx({urlbarIcon: true})
return cx({
urlbarIcon: true
})
}

const iconClasses = {
urlbarIcon: true,
fa: true
}

this.iconCssClasses.forEach((iconClass) => {
iconClasses[iconClass] = true
})
return cx(iconClasses)
}

get iconStyles () {
if (!this.props.activateSearchEngine) {
return {}
}

return {
backgroundImage: `url(${this.props.searchSelectEntry.get('image')})`,
backgroundImage: `url(${this.props.searchSelectImage})`,
backgroundSize: searchIconSize,
width: searchIconSize,
height: searchIconSize
}
}

onClick () {
if (isSourceAboutUrl(this.props.location) || this.isSearch) {
return
}

windowActions.setSiteInfoVisible(true)
}

onDragStart (e) {
dndData.setupDataTransferURL(e.dataTransfer, this.props.location, this.props.title)
const activeFrame = getActiveFrame(windowStore.state)
dndData.setupDataTransferBraveData(e.dataTransfer, dragTypes.TAB, activeFrame)
dndData.setupDataTransferBraveData(e.dataTransfer, dragTypes.TAB, this.props.activeFrame)
}

mergeProps (state, ownProps) {
const currentWindow = state.get('currentWindow')
const activeFrame = frameStateUtil.getActiveFrame(currentWindow) || Immutable.Map()
const urlBar = activeFrame.getIn(['navbar', 'urlbar'], Immutable.Map())
const activeTabId = activeFrame.get('tabId', tabState.TAB_ID_NONE)
const location = tabState.getVisibleURL(state, activeTabId)
const displayURL = tabState.getVisibleVirtualURL(state, activeTabId) || ''
const urlBarLocation = urlBar.get('location')

const props = {}
// used in renderer
props.activateSearchEngine = urlBar.getIn(['searchDetail', 'activateSearchEngine'])
props.active = urlBar.get('active')
props.isSecure = activeFrame.getIn(['security', 'isSecure'])
props.isHTTPPage = UrlUtil.isHttpOrHttps(location)
props.location = displayURL
props.searchSelectImage = urlBar.getIn(['searchDetail', 'image'], '')
props.titleMode = ownProps.titleMode
props.isSearching = displayURL !== urlBarLocation
props.activeTabShowingMessageBox = tabState.isShowingMessageBox(state, activeTabId)
props.isAboutPage = isSourceAboutUrl(props.location) && props.location !== 'about:newtab'
props.isPotentialPhishingUrl = isPotentialPhishingUrl(props.location)

// used in other functions
props.title = activeFrame.get('title', '')
props.activeFrame = activeFrame // TODO (nejc) only primitives

return props
}

render () {
// allow click and drag (unless tab is showing a message box)
const props = {}
Expand All @@ -102,6 +152,7 @@ class UrlBarIcon extends ImmutableComponent {
props.onClick = this.onClick
props.onDragStart = this.onDragStart
}

return <span
data-test-id='urlBarIcon'
{...props}
Expand All @@ -110,4 +161,4 @@ class UrlBarIcon extends ImmutableComponent {
}
}

module.exports = UrlBarIcon
module.exports = ReduxComponent.connect(UrlBarIcon)
92 changes: 62 additions & 30 deletions test/unit/app/renderer/components/navigation/urlBarIconTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,54 +4,91 @@
/* global describe, before, after, it */

const React = require('react')
const Immutable = require('immutable')
const mockery = require('mockery')
const {mount} = require('enzyme')
const sinon = require('sinon')
const assert = require('assert')
let UrlBarIcon, windowActions
const fakeElectron = require('../../../../lib/fakeElectron')
require('../../../../braveUnit')

const tabId = 1
const frameKey = 0

const fakeAppStoreRenderer = Immutable.fromJS({
windows: [{
windowId: 1,
windowUUID: 'uuid'
}],
tabs: [{
tabId: tabId,
windowId: 1,
windowUUID: 'uuid',
url: 'https://brave.com',
messageBoxDetail: false
}],
tabsInternal: {
index: {
1: 0
}
}
})

const defaultWindowStore = Immutable.fromJS({
activeFrameKey: frameKey,
frames: [{
key: frameKey,
tabId: tabId,
location: 'https://brave.com',
security: {
isSecure: true
},
navbar: {
urlbar: {
location: 'https://brave.com',
active: false,
searchDetail: {
activateSearchEngine: true
}
}
},
title: 'Brave Software'
}],
tabs: [{
key: frameKey
}]
})

describe('UrlBarIcon component unit tests', function () {
let UrlBarIcon, windowActions, windowStore, appStore

before(function () {
mockery.enable({
warnOnReplace: false,
warnOnUnregistered: false,
useCleanCache: true
})
mockery.registerMock('electron', require('../../../../lib/fakeElectron'))
mockery.registerMock('electron', fakeElectron)
UrlBarIcon = require('../../../../../../app/renderer/components/navigation/urlBarIcon')
windowActions = require('../../../../../../js/actions/windowActions')
windowStore = require('../../../../../../js/stores/windowStore')
appStore = require('../../../../../../js/stores/appStoreRenderer')
})

after(function () {
mockery.disable()
})

const props = {
activateSearchEngine: false,
active: false,
isSecure: true,
isHTTPPage: true,
loading: false,
location: 'https://brave.com/',
title: 'UrlBarIcon unit test',
titleMode: true,
isSearching: false,
activeTabShowingMessageBox: false
}

it('sets element as draggable', function () {
const wrapper = mount(
<UrlBarIcon {...props} />
)
appStore.state = fakeAppStoreRenderer
windowStore.state = defaultWindowStore
const wrapper = mount(<UrlBarIcon titleMode />)
assert.equal(wrapper.find('span[draggable]').length, 1)
})

it('shows site information when clicked', function () {
const spy = sinon.spy(windowActions, 'setSiteInfoVisible')
const wrapper = mount(
<UrlBarIcon {...props} />
)
const wrapper = mount(<UrlBarIcon titleMode />)
wrapper.find('[data-test-id="urlBarIcon"]').simulate('click')
assert.equal(spy.calledOnce, true)
windowActions.setSiteInfoVisible.restore()
Expand All @@ -77,24 +114,19 @@ describe('UrlBarIcon component unit tests', function () {
})

describe('when active tab is showing a message box', function () {
const props2 = Object.assign({}, props)

before(function () {
props2.activeTabShowingMessageBox = true
appStore.state = fakeAppStoreRenderer.setIn(['tabs', 0, 'messageBoxDetail'], true)
windowStore.state = defaultWindowStore
})

it('does not set element as draggable', function () {
const wrapper = mount(
<UrlBarIcon {...props2} />
)
const wrapper = mount(<UrlBarIcon titleMode />)
assert.equal(wrapper.find('span[draggable]').length, 0)
})

it('does not respond to clicks', function () {
const spy = sinon.spy(windowActions, 'setSiteInfoVisible')
const wrapper = mount(
<UrlBarIcon {...props2} />
)
const wrapper = mount(<UrlBarIcon titleMode />)
wrapper.find('[data-test-id="urlBarIcon"]').simulate('click')
assert.equal(spy.notCalled, true)
windowActions.setSiteInfoVisible.restore()
Expand Down

0 comments on commit 0783843

Please sign in to comment.