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

Commit

Permalink
Converts urlBarSuggestions into redux
Browse files Browse the repository at this point in the history
Resolves #9052

Auditors: @bsclifton @bridiver @bbondy

Test Plan:
- test if suggestion list is displayed
- test if hover and click is working on suggestion list
  • Loading branch information
NejcZdovc committed May 26, 2017
1 parent 7fb2bf7 commit aa06e4a
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 89 deletions.
49 changes: 48 additions & 1 deletion app/common/lib/suggestion.js
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,52 @@ const generateNewSearchXHRResults = debounce((state, windowId, tabId, input) =>
}
}, 10)

const filterSuggestionListByType = (suggestionList) => {
const bookmarkSuggestions = []
const historySuggestions = []
const aboutPagesSuggestions = []
const tabSuggestions = []
const searchSuggestions = []
const topSiteSuggestions = []

suggestionList.forEach(item => {
switch (item.get('type')) {
case suggestionTypes.BOOKMARK:
bookmarkSuggestions.push(item)
break

case suggestionTypes.HISTORY:
historySuggestions.push(item)
break

case suggestionTypes.ABOUT_PAGES:
aboutPagesSuggestions.push(item)
break

case suggestionTypes.TAB:
tabSuggestions.push(item)
break

case suggestionTypes.SEARCH:
searchSuggestions.push(item)
break

case suggestionTypes.TOP_SITE:
topSiteSuggestions.push(item)
break
}
})

return {
bookmarkSuggestions,
historySuggestions,
aboutPagesSuggestions,
tabSuggestions,
searchSuggestions,
topSiteSuggestions
}
}

module.exports = {
sortingPriority,
sortByAccessCountWithAgeDecay,
Expand All @@ -621,5 +667,6 @@ module.exports = {
getSearchSuggestions,
getAlexaSuggestions,
generateNewSuggestionsList,
generateNewSearchXHRResults
generateNewSearchXHRResults,
filterSuggestionListByType
}
6 changes: 2 additions & 4 deletions app/renderer/components/navigation/urlBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -615,10 +615,8 @@ class UrlBar extends React.Component {
{
this.shouldRenderUrlBarSuggestions
? <UrlBarSuggestions
selectedIndex={this.props.selectedIndex}
suggestionList={this.props.suggestionList}
hasSuggestionMatch={this.props.hasSuggestionMatch}
menubarVisible={this.props.menubarVisible} />
menubarVisible={this.props.menubarVisible}
/>
: null
}
</form>
Expand Down
39 changes: 36 additions & 3 deletions app/renderer/components/navigation/urlBarSuggestionItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,57 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */

const React = require('react')

// Components
const ImmutableComponent = require('../immutableComponent')

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

// Actions
const appActions = require('../../../../js/actions/appActions')
const windowActions = require('../../../../js/actions/windowActions')

// utils
const cx = require('../../../../js/lib/classSet')
const {isForSecondaryAction} = require('../../../../js/lib/eventUtil')
const {getCurrentWindowId} = require('../../currentWindow')

class UrlBarSuggestionItem extends ImmutableComponent {
constructor () {
super()
this.onMouseOver = this.onMouseOver.bind(this)
}

onMouseOver (e) {
let newIndex = parseInt(e.target.getAttribute('data-index'), 10)

if (newIndex < 0) {
newIndex = null
}

appActions.urlBarSelectedIndexChanged(getCurrentWindowId(), newIndex)
}

onClick (e) {
windowActions.activeSuggestionClicked(isForSecondaryAction(e), e.shiftKey)
}

componentDidMount () {
this.node.addEventListener('auxclick', this.props.onClick)
this.node.addEventListener('auxclick', this.onClick)
}

componentWillUpdate (nextProps) {
if (!this.props.selected && nextProps.selected) {
this.node.scrollIntoView()
}
}

render () {
return <li data-test-id='list-item'
data-index={this.props.currentIndex}
onMouseOver={this.props.onMouseOver.bind(this)}
onClick={this.props.onClick}
onMouseOver={this.onMouseOver}
onClick={this.onClick}
key={`${this.props.suggestion.get('location')}|${this.props.currentIndex + this.props.i}`}
ref={(node) => { this.node = node }}
className={cx({
Expand Down
135 changes: 63 additions & 72 deletions app/renderer/components/navigation/urlBarSuggestions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,112 +3,103 @@
* 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')
const UrlBarSuggestionItem = require('./urlBarSuggestionItem')
const windowActions = require('../../../../js/actions/windowActions')

// Actions
const appActions = require('../../../../js/actions/appActions')
const suggestionTypes = require('../../../../js/constants/suggestionTypes')

// Utils
const cx = require('../../../../js/lib/classSet')
const locale = require('../../../../js/l10n')
const {isForSecondaryAction} = require('../../../../js/lib/eventUtil')
const suggestions = require('../../../common/lib/suggestion')
const frameStateUtil = require('../../../../js/state/frameStateUtil')
const {getCurrentWindowId} = require('../../currentWindow')

class UrlBarSuggestions extends ImmutableComponent {
constructor () {
super()
this.onSuggestionClicked = this.onSuggestionClicked.bind(this)
this.onMouseOver = this.onMouseOver.bind(this)
}

get activeIndex () {
if (this.props.suggestionList === null) {
return -1
}
return this.props.selectedIndex
}

class UrlBarSuggestions extends React.Component {
blur () {
appActions.urlBarSuggestionsChanged(getCurrentWindowId(), null, null)
}

onSuggestionClicked (e) {
windowActions.activeSuggestionClicked(isForSecondaryAction(e), e.shiftKey)
}

render () {
const suggestions = this.props.suggestionList
const bookmarkSuggestions = suggestions.filter((s) => s.get('type') === suggestionTypes.BOOKMARK)
const historySuggestions = suggestions.filter((s) => s.get('type') === suggestionTypes.HISTORY)
const aboutPagesSuggestions = suggestions.filter((s) => s.get('type') === suggestionTypes.ABOUT_PAGES)
const tabSuggestions = suggestions.filter((s) => s.get('type') === suggestionTypes.TAB)
const searchSuggestions = suggestions.filter((s) => s.get('type') === suggestionTypes.SEARCH)
const topSiteSuggestions = suggestions.filter((s) => s.get('type') === suggestionTypes.TOP_SITE)

generateAllItems () {
let items = []
let index = 0

const addToItems = (suggestions, sectionKey, title, icon) => {
if (suggestions.size > 0) {
if (suggestions.length > 0) {
items.push(<li className='suggestionSection'>
{
icon
? <span className={cx({
suggestionSectionIcon: true,
[sectionKey]: true,
fa: true,
[icon]: true
})} />
: null
? <span className={cx({
suggestionSectionIcon: true,
[sectionKey]: true,
fa: true,
[icon]: true
})} />
: null
}
<span className='suggestionSectionTitle'>{title}</span>
</li>)
}

items = items.concat(suggestions.map((suggestion, i) => {
const currentIndex = index + i
const selected = this.activeIndex === currentIndex || (!this.activeIndex && currentIndex === 0 && this.props.hasSuggestionMatch)
const selected = this.props.activeIndex === currentIndex || (this.props.activeIndex == null && currentIndex === 0 && this.props.hasSuggestionMatch)
return <UrlBarSuggestionItem
suggestion={suggestion}
selected={selected}
currentIndex={currentIndex}
i={i}
onMouseOver={this.onMouseOver}
onClick={this.onSuggestionClicked} />
i={i} />
}))
index += suggestions.size
index += suggestions.length
}
addToItems(historySuggestions, 'historyTitle', locale.translation('historySuggestionTitle'), 'fa-clock-o')
addToItems(bookmarkSuggestions, 'bookmarksTitle', locale.translation('bookmarksSuggestionTitle'), 'fa-star-o')
addToItems(aboutPagesSuggestions, 'aboutPagesTitle', locale.translation('aboutPagesSuggestionTitle'), null)
addToItems(tabSuggestions, 'tabsTitle', locale.translation('tabsSuggestionTitle'), 'fa-external-link')
addToItems(searchSuggestions, 'searchTitle', locale.translation('searchSuggestionTitle'), 'fa-search')
addToItems(topSiteSuggestions, 'topSiteTitle', locale.translation('topSiteSuggestionTitle'), 'fa-link')
const documentHeight = Number.parseInt(window.getComputedStyle(document.querySelector(':root')).getPropertyValue('--navbar-height'), 10)
const menuHeight = this.props.menubarVisible ? 30 : 0
return <ul className='urlBarSuggestions' style={{
maxHeight: document.documentElement.offsetHeight - documentHeight - 2 - menuHeight
}}>
{items}
</ul>
}

onMouseOver (e) {
this.updateSuggestions(parseInt(e.target.dataset.index, 10))
const list = suggestions.filterSuggestionListByType(this.props.suggestionList)

addToItems(list.historySuggestions, 'historyTitle', locale.translation('historySuggestionTitle'), 'fa-clock-o')
addToItems(list.bookmarkSuggestions, 'bookmarksTitle', locale.translation('bookmarksSuggestionTitle'), 'fa-star-o')
addToItems(list.aboutPagesSuggestions, 'aboutPagesTitle', locale.translation('aboutPagesSuggestionTitle'), null)
addToItems(list.tabSuggestions, 'tabsTitle', locale.translation('tabsSuggestionTitle'), 'fa-external-link')
addToItems(list.searchSuggestions, 'searchTitle', locale.translation('searchSuggestionTitle'), 'fa-search')
addToItems(list.topSiteSuggestions, 'topSiteTitle', locale.translation('topSiteSuggestionTitle'), 'fa-link')

return items
}

componentDidMount () {
mergeProps (state, dispatchProps, ownProps) {
const currentWindow = state.get('currentWindow')
const activeFrame = frameStateUtil.getActiveFrame(currentWindow) || Immutable.Map()
const urlBar = activeFrame.getIn(['navbar', 'urlbar']) || Immutable.Map()
const documentHeight = Number.parseInt(
window.getComputedStyle(document.querySelector(':root')).getPropertyValue('--navbar-height'), 10
)
const menuHeight = ownProps.menubarVisible ? 30 : 0

const props = {}
// used in renderer
props.maxHeight = document.documentElement.offsetHeight - documentHeight - 2 - menuHeight

// used in functions
props.menubarVisible = ownProps.menubarVisible
props.suggestionList = urlBar.getIn(['suggestions', 'suggestionList']) // TODO (nejc) improve, use primitives
props.hasSuggestionMatch = urlBar.getIn(['suggestions', 'hasSuggestionMatch'])
props.activeIndex = props.suggestionList === null
? -1
: urlBar.getIn(['suggestions', 'selectedIndex'])

return props
}

updateSuggestions (newIndex) {
const suggestions = this.suggestionList || this.props.suggestionList
if (!suggestions) {
return
}
// Update the urlbar preview content
if (newIndex > suggestions.size) {
newIndex = null
}
appActions.urlBarSuggestionsChanged(getCurrentWindowId(), suggestions, newIndex)
render () {
return <ul className='urlBarSuggestions' style={{
maxHeight: this.props.maxHeight
}}>
{this.generateAllItems()}
</ul>
}
}

module.exports = UrlBarSuggestions
module.exports = ReduxComponent.connect(UrlBarSuggestions)
7 changes: 7 additions & 0 deletions app/renderer/reducers/urlBarReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ const urlBarReducer = (state, action) => {
case appConstants.APP_URL_BAR_TEXT_CHANGED:
state = setNavBarUserInput(state, action.input)
break
case appConstants.APP_URL_BAR_SELECTED_INDEX_CHANGED:
{
const suggestionList = state.getIn(activeFrameStatePath(state).concat(['navbar', 'urlbar', 'suggestions', 'suggestionList']))
state = state.setIn(activeFrameStatePath(state).concat(['navbar', 'urlbar', 'suggestions', 'selectedIndex']), action.selectedIndex)
state = updateUrlSuffix(state, suggestionList)
break
}
case appConstants.APP_URL_BAR_SUGGESTIONS_CHANGED:
if (action.selectedIndex !== undefined) {
state = state.setIn(activeFrameStatePath(state).concat(['navbar', 'urlbar', 'suggestions', 'selectedIndex']), action.selectedIndex)
Expand Down
12 changes: 12 additions & 0 deletions docs/appActions.md
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,18 @@ Indicates URL bar suggestions and selected index.



### urlBarSelectedIndexChanged(windowId, selectedIndex)

Indicates URL bar selected index

**Parameters**

**windowId**: `number`, the window ID

**selectedIndex**: `number`, The index for the selected item (users can select items with down arrow on their keyboard)



### defaultSearchEngineLoaded(searchDetail)

Dispatches a message to set the search engine details.
Expand Down
17 changes: 17 additions & 0 deletions js/actions/appActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -1393,6 +1393,23 @@ const appActions = {
})
},

/**
* Indicates URL bar selected index
*
* @param {number} windowId - the window ID
* @param {number} selectedIndex - The index for the selected item (users can select items with down arrow on their keyboard)
*/
urlBarSelectedIndexChanged: function (windowId, selectedIndex) {
dispatch({
actionType: appConstants.APP_URL_BAR_SELECTED_INDEX_CHANGED,
selectedIndex,
windowId,
queryInfo: {
windowId
}
})
},

/**
* Dispatches a message to set the search engine details.
* @param {Object} searchDetail - the search details
Expand Down
3 changes: 2 additions & 1 deletion js/constants/appConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ const appConstants = {
APP_ADD_PASSWORD: _, /** @param {Object} passwordDetail */
APP_REMOVE_PASSWORD: _, /** @param {Object} passwordDetail */
APP_REMOVE_PASSWORD_SITE: _, /** @param {Object} passwordDetail */
APP_CLEAR_PASSWORDS: _
APP_CLEAR_PASSWORDS: _,
APP_URL_BAR_SELECTED_INDEX_CHANGED: _
}

module.exports = mapValuesByKeys(appConstants)
Loading

0 comments on commit aa06e4a

Please sign in to comment.