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

Commit

Permalink
make tab preview based on idle mouse time
Browse files Browse the repository at this point in the history
- Fix #8860
- Auditors: @bsclifton
  • Loading branch information
cezaraugusto committed Jun 3, 2017
1 parent 1a2dcf3 commit 3d87b1e
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 14 deletions.
8 changes: 8 additions & 0 deletions app/common/constants/settingsEnums.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ const tabCloseAction = {
PARENT: 'parent'
}

// timing in milliseconds
const tabPreviewTiming = {
LONG: 2000,
NORMAL: 1000,
SHORT: 500
}

const fullscreenOption = {
ALWAYS_ASK: 'alwaysAsk',
ALWAYS_ALLOW: 'alwaysAllow'
Expand All @@ -42,6 +49,7 @@ module.exports = {
newTabMode,
bookmarksToolbarMode,
tabCloseAction,
tabPreviewTiming,
fullscreenOption,
autoplayOption
}
4 changes: 4 additions & 0 deletions app/extensions/brave/locales/en-US/preferences.properties
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ tabsPerTabPage=Number of tabs per tab set:
tabCloseAction=When closing an active tab:
showTabPreviews=Show tab previews on hover
showOpenedTabMatches=Show tab matches
tabPreviewTiming=Time to wait before previewing a tab
long=Long
normal=Normal
short=Short
showHistoryMatches=Show history matches
showBookmarkMatches=Show bookmark matches
showTopsiteSuggestions=Show top site suggestions
Expand Down
47 changes: 35 additions & 12 deletions app/renderer/components/tabs/tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const {hasBreakpoint} = require('../../lib/tabUtil')
class Tab extends React.Component {
constructor (props) {
super(props)
this.onMouseMove = this.onMouseMove.bind(this)
this.onMouseEnter = this.onMouseEnter.bind(this)
this.onMouseLeave = this.onMouseLeave.bind(this)
this.onUpdateTabSize = this.onUpdateTabSize.bind(this)
Expand Down Expand Up @@ -129,27 +130,47 @@ class Tab extends React.Component {
dnd.onDragOver(dragTypes.TAB, this.tabNode.getBoundingClientRect(), this.props.frameKey, this.draggingOverData, e)
}

onMouseLeave () {
onMouseLeave (e) {
windowActions.setTabHoverState(this.props.frameKey, false)

if (this.props.previewTabs) {
window.clearTimeout(this.hoverTimeout)
windowActions.setPreviewFrame(null)
clearTimeout(this.mouseTimeout)
// Matches tab_, tabArea, tabTitle, tabId, closeTab and
// all tab icons such as favicon, private and new session
const tabComponents = /tab(?=_|area|title|id)|closetab|icon/i
const tabAsRelatedTarget = tabComponents.test(e.relatedTarget.classList)

// We are taking for granted that user hovering over another tab
// means that he wants to sequentially preview a set of tabs,
// so if previewMode was set by defined mouse idle time,
// only cancel previewMode if the next event doesn't happen in another tab.
if (!tabAsRelatedTarget) {
windowActions.setPreviewFrame(null)
windowActions.setPreviewMode(false)
}
}
windowActions.setTabHoverState(this.props.frameKey, false)
}

onMouseEnter (e) {
// relatedTarget inside mouseenter checks which element before this event was the pointer on
// if this element has a tab-like class, then it's likely that the user was previewing
// a sequency of tabs. Called here as previewMode.
const previewMode = /tab(?!pages)/i.test(e.relatedTarget.classList)
windowActions.setTabHoverState(this.props.frameKey, true)

// If user isn't in previewMode, we add a bit of delay to avoid tab from flashing out
// as reported here: https://github.com/brave/browser-laptop/issues/1434
this.mouseTimeout = null
if (this.props.previewTabs && this.props.previewMode) {
windowActions.setPreviewFrame(this.props.frameKey)
}
}

onMouseMove (e) {
// previewMode is only triggered if mouse is idle over a tab
// for a given amount of time based on timing defined in prefs->tabs
if (this.props.previewTabs) {
this.hoverTimeout =
window.setTimeout(windowActions.setPreviewFrame.bind(null, this.props.frameKey), previewMode ? 0 : 200)
clearTimeout(this.mouseTimeout)
this.mouseTimeout = setTimeout(() => {
windowActions.setPreviewFrame(this.props.frameKey)
windowActions.setPreviewMode(true)
}, getSetting(settings.TAB_PREVIEW_TIMING))
}
windowActions.setTabHoverState(this.props.frameKey, true)
}

onAuxClick (e) {
Expand Down Expand Up @@ -272,6 +293,7 @@ class Tab extends React.Component {
props.dragData = state.getIn(['dragData', 'type']) === dragTypes.TAB && state.get('dragData')
props.hasTabInFullScreen = tabContentState.hasTabInFullScreen(currentWindow)
props.tabId = frame.get('tabId')
props.previewMode = currentWindow.getIn(['ui', 'tabs', 'previewMode'])

return props
}
Expand All @@ -298,6 +320,7 @@ class Tab extends React.Component {
partOfFullPageSet: this.props.partOfFullPageSet || !!this.props.tabWidth
})}
style={this.props.tabWidth ? { flex: `0 0 ${this.props.tabWidth}px` } : {}}
onMouseMove={this.onMouseMove}
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}>
{
Expand Down
4 changes: 3 additions & 1 deletion docs/state.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ AppStore
'tabs.close-action': string, // one of: parent, lastActive, next
'tabs.paint-tabs': boolean, // true if the page theme color and favicon color should be used for tabs
'tabs.show-tab-previews': boolean, // true to show tab previews
'tabs.preview-timing': boolean, // how much in milliseconds user should wait before tab preview is fired
'tabs.switch-to-new-tabs': boolean, // true if newly opened tabs should be focused immediately
'tabs.tabs-per-page': number // number of tabs per tab page
},
Expand Down Expand Up @@ -665,8 +666,9 @@ WindowStore
},
size: array, // last known window size [x, y]
tabs: {
tabPageIndex: number, // index of the current tab page
previewMode: boolean, // whether or not tab preview should be fired based on mouse idle time
previewTabPageIndex: number // index of the tab being previewed
tabPageIndex: number, // index of the current tab page
},
},
widevinePanelDetail: {
Expand Down
11 changes: 11 additions & 0 deletions docs/windowActions.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,17 @@ This is done when hovering over a tab.



### setPreviewMode(shouldEnablePreview)

Dispatches a message to the store to set preview mode.
This will check whether setPreviewFrame should be fired or not.

**Parameters**

**shouldEnablePreview**: `Boolean`, true if user enters in previewMode state



### setTabPageIndex(index)

Dispatches a message to the store to set the tab page index.
Expand Down
23 changes: 22 additions & 1 deletion js/about/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,15 @@ const messages = require('../constants/messages')
const settings = require('../constants/settings')
const {changeSetting} = require('../../app/renderer/lib/settingsUtil')
const {passwordManagers, extensionIds} = require('../constants/passwordManagers')
const {startsWithOption, newTabMode, bookmarksToolbarMode, tabCloseAction, fullscreenOption, autoplayOption} = require('../../app/common/constants/settingsEnums')
const {
startsWithOption,
newTabMode,
bookmarksToolbarMode,
tabCloseAction,
fullscreenOption,
autoplayOption,
tabPreviewTiming
} = require('../../app/common/constants/settingsEnums')

const aboutActions = require('./aboutActions')
const appActions = require('../actions/appActions')
Expand Down Expand Up @@ -359,6 +367,19 @@ class TabsTab extends ImmutableComponent {
<SettingCheckbox dataL10nId='switchToNewTabs' prefKey={settings.SWITCH_TO_NEW_TABS} settings={this.props.settings} onChangeSetting={this.props.onChangeSetting} />
<SettingCheckbox dataL10nId='paintTabs' prefKey={settings.PAINT_TABS} settings={this.props.settings} onChangeSetting={this.props.onChangeSetting} />
<SettingCheckbox dataL10nId='showTabPreviews' prefKey={settings.SHOW_TAB_PREVIEWS} settings={this.props.settings} onChangeSetting={this.props.onChangeSetting} />
{
getSetting(settings.SHOW_TAB_PREVIEWS, this.props.settings)
? <SettingItem dataL10nId='tabPreviewTiming'>
<SettingDropdown
value={getSetting(settings.TAB_PREVIEW_TIMING, this.props.settings)}
onChange={changeSetting.bind(null, this.props.onChangeSetting, settings.TAB_PREVIEW_TIMING)}>
<option data-l10n-id='long' value={tabPreviewTiming.LONG} />
<option data-l10n-id='normal' value={tabPreviewTiming.NORMAL} />
<option data-l10n-id='short' value={tabPreviewTiming.SHORT} />
</SettingDropdown>
</SettingItem>
: null
}
<SettingItem dataL10nId='dashboardSettingsTitle'>
<SettingCheckbox dataL10nId='dashboardShowImages' prefKey={settings.SHOW_DASHBOARD_IMAGES} settings={this.props.settings} onChangeSetting={this.props.onChangeSetting} />
</SettingItem>
Expand Down
13 changes: 13 additions & 0 deletions js/actions/windowActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,19 @@ const windowActions = {
})
},

/**
* Dispatches a message to the store to set preview mode.
* This will check whether setPreviewFrame should be fired or not.
*
* @param {Boolean} shouldEnablePreview - true if user enters in previewMode state
*/
setPreviewMode: function (shouldEnablePreview) {
dispatch({
actionType: windowConstants.WINDOW_SET_PREVIEW_MODE,
shouldEnablePreview
})
},

/**
* Dispatches a message to the store to set the tab page index.
*
Expand Down
1 change: 1 addition & 0 deletions js/constants/appConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ module.exports = {
'tabs.tabs-per-page': 20,
'tabs.close-action': 'parent',
'tabs.show-tab-previews': true,
'tabs.preview-timing': 2000,
'tabs.show-dashboard-images': true,
'privacy.history-suggestions': true,
'privacy.bookmark-suggestions': true,
Expand Down
1 change: 1 addition & 0 deletions js/constants/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const settings = {
PAINT_TABS: 'tabs.paint-tabs',
TABS_PER_PAGE: 'tabs.tabs-per-page',
SHOW_TAB_PREVIEWS: 'tabs.show-tab-previews',
TAB_PREVIEW_TIMING: 'tabs.preview-timing',
SHOW_DASHBOARD_IMAGES: 'tabs.show-dashboard-images',
// Privacy Tab
HISTORY_SUGGESTIONS: 'privacy.history-suggestions',
Expand Down
1 change: 1 addition & 0 deletions js/constants/windowConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const windowConstants = {
WINDOW_CLOSE_FRAMES: _,
WINDOW_SET_FOCUSED_FRAME: _,
WINDOW_SET_PREVIEW_FRAME: _,
WINDOW_SET_PREVIEW_MODE: _,
WINDOW_SET_PREVIEW_TAB_PAGE_INDEX: _,
WINDOW_SET_TAB_PAGE_INDEX: _,
WINDOW_SET_TAB_BREAKPOINT: _,
Expand Down
3 changes: 3 additions & 0 deletions js/stores/windowStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@ const doAction = (action) => {
case windowConstants.WINDOW_CLEAR_CLOSED_FRAMES:
windowState = windowState.set('closedFrames', new Immutable.List())
break
case windowConstants.WINDOW_SET_PREVIEW_MODE:
windowState = windowState.setIn(['ui', 'tabs', 'previewMode'], action.shouldEnablePreview)
break
case windowConstants.WINDOW_SET_PREVIEW_FRAME:
windowState = windowState.merge({
previewFrameKey:
Expand Down

0 comments on commit 3d87b1e

Please sign in to comment.