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

Commit 42c94a8

Browse files
committed
Merge pull request #9542 from brave/issue-9306-related
* This sets the ground for the *new* tab preview behavior * making component dumb and letting the reducer to * decide what actually needs to be done in response
1 parent abf03e2 commit 42c94a8

File tree

10 files changed

+175
-69
lines changed

10 files changed

+175
-69
lines changed

app/common/state/tabContentState.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ const tabContentState = {
8787
const tabPageIndex = state.getIn(['ui', 'tabs', 'tabPageIndex'], 0)
8888
const previewTabPageIndex = state.getIn(['ui', 'tabs', 'previewTabPageIndex'])
8989

90-
return previewTabPageIndex !== undefined ? previewTabPageIndex : tabPageIndex
90+
return previewTabPageIndex != null ? previewTabPageIndex : tabPageIndex
9191
},
9292

9393
isMediumView: (state, frameKey) => {

app/renderer/components/tabs/tab.js

-18
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ const tabContentState = require('../../../common/state/tabContentState')
2828

2929
// Constants
3030
const dragTypes = require('../../../../js/constants/dragTypes')
31-
const settings = require('../../../../js/constants/settings')
3231

3332
// Styles
3433
const styles = require('../styles/tab')
@@ -44,7 +43,6 @@ const frameStateUtil = require('../../../../js/state/frameStateUtil')
4443
const {getTabBreakpoint, tabUpdateFrameRate} = require('../../lib/tabUtil')
4544
const {isWindows} = require('../../../common/lib/platformUtil')
4645
const {getCurrentWindowId} = require('../../currentWindow')
47-
const {getSetting} = require('../../../../js/settings')
4846
const UrlUtil = require('../../../../js/lib/urlutil')
4947
const {hasBreakpoint} = require('../../lib/tabUtil')
5048

@@ -131,25 +129,10 @@ class Tab extends React.Component {
131129
}
132130

133131
onMouseLeave () {
134-
if (this.props.previewTabs) {
135-
window.clearTimeout(this.hoverTimeout)
136-
windowActions.setPreviewFrame(null)
137-
}
138132
windowActions.setTabHoverState(this.props.frameKey, false)
139133
}
140134

141135
onMouseEnter (e) {
142-
// relatedTarget inside mouseenter checks which element before this event was the pointer on
143-
// if this element has a tab-like class, then it's likely that the user was previewing
144-
// a sequency of tabs. Called here as previewMode.
145-
const previewMode = /tab(?!pages)/i.test(e.relatedTarget.classList)
146-
147-
// If user isn't in previewMode, we add a bit of delay to avoid tab from flashing out
148-
// as reported here: https://github.com/brave/browser-laptop/issues/1434
149-
if (this.props.previewTabs) {
150-
this.hoverTimeout =
151-
window.setTimeout(windowActions.setPreviewFrame.bind(null, this.props.frameKey), previewMode ? 0 : 200)
152-
}
153136
windowActions.setTabHoverState(this.props.frameKey, true)
154137
}
155138

@@ -270,7 +253,6 @@ class Tab extends React.Component {
270253

271254
// used in other functions
272255
props.totalTabs = state.get('tabs').size
273-
props.previewTabs = getSetting(settings.SHOW_TAB_PREVIEWS)
274256
props.dragData = state.getIn(['dragData', 'type']) === dragTypes.TAB && state.get('dragData')
275257
props.hasTabInFullScreen = tabContentState.hasTabInFullScreen(currentWindow)
276258
props.tabId = frame.get('tabId')

app/renderer/components/tabs/tabPage.js

+2-11
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,11 @@ class TabPage extends ImmutableComponent {
2727
this.onMouseLeave = this.onMouseLeave.bind(this)
2828
}
2929
onMouseLeave () {
30-
window.clearTimeout(this.hoverTimeout)
31-
windowActions.setPreviewTabPageIndex()
30+
windowActions.setTabPageHoverState(this.props.index, false)
3231
}
3332

3433
onMouseEnter (e) {
35-
// relatedTarget inside mouseenter checks which element before this event was the pointer on
36-
// if this element has a tab-like class, then it's likely that the user was previewing
37-
// a sequency of tabs. Called here as previewMode.
38-
const previewMode = /tab(?!pages)/i.test(e.relatedTarget.classList)
39-
40-
// If user isn't in previewMode, we add a bit of delay to avoid tab from flashing out
41-
// as reported here: https://github.com/brave/browser-laptop/issues/1434
42-
this.hoverTimeout =
43-
window.setTimeout(windowActions.setPreviewTabPageIndex.bind(null, this.props.index), previewMode ? 0 : 200)
34+
windowActions.setTabPageHoverState(this.props.index, true)
4435
}
4536

4637
onDrop (e) {

app/renderer/components/tabs/tabs.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ class Tabs extends React.Component {
164164
onMouseLeave={this.onMouseLeave}>
165165
<span className={cx({
166166
tabStripContainer: true,
167-
isPreview: this.props.previewTabPageIndex !== undefined,
167+
isPreview: this.props.previewTabPageIndex != null,
168168
allowDragging: this.props.shouldAllowWindowDrag
169169
})}
170170
onDragOver={this.onDragOver}

app/renderer/reducers/frameReducer.js

+13-15
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,12 @@ const config = require('../../../js/constants/config')
1313

1414
// Actions
1515
const appActions = require('../../../js/actions/appActions')
16-
const windowActions = require('../../../js/actions/windowActions')
1716

1817
// Utils
1918
const frameStateUtil = require('../../../js/state/frameStateUtil')
2019
const {getCurrentWindowId} = require('../currentWindow')
2120
const {getSourceAboutUrl, getSourceMagnetUrl} = require('../../../js/lib/appUrlUtil')
2221
const {isURL, isPotentialPhishingUrl, getUrlFromInput} = require('../../../js/lib/urlutil')
23-
const settings = require('../../../js/constants/settings')
24-
const {getSetting} = require('../../../js/settings')
2522

2623
const setFullScreen = (state, action) => {
2724
const index = frameStateUtil.getFrameIndex(state, action.frameProps.get('key'))
@@ -32,15 +29,13 @@ const setFullScreen = (state, action) => {
3229
}
3330

3431
const closeFrame = (state, action) => {
35-
const activeFrameIndex = frameStateUtil.getActiveFrameIndex(state)
3632
const index = frameStateUtil.getFrameIndex(state, action.frameKey)
3733
if (index === -1) {
3834
return state
3935
}
4036

4137
const frameProps = frameStateUtil.getFrameByKey(state, action.frameKey)
4238
const hoverState = state.getIn(['frames', index, 'hoverState'])
43-
const framePreviewEnabled = getSetting(settings.SHOW_TAB_PREVIEWS)
4439

4540
state = state.merge(frameStateUtil.removeFrame(
4641
state,
@@ -56,15 +51,15 @@ const closeFrame = (state, action) => {
5651

5752
const nextFrame = frameStateUtil.getFrameByIndex(state, index)
5853

59-
if (nextFrame && hoverState) {
54+
if (nextFrame) {
6055
// Copy the hover state if tab closed with mouse as long as we have a next frame
6156
// This allow us to have closeTab button visible for sequential frames closing,
6257
// until onMouseLeave event happens.
63-
windowActions.setTabHoverState(nextFrame.get('key'), hoverState)
64-
if (framePreviewEnabled && index !== activeFrameIndex) {
65-
// After closing a tab, preview the next frame as long as there is one
66-
windowActions.setPreviewFrame(nextFrame.get('key'))
58+
if (hoverState) {
59+
state = frameStateUtil.setTabHoverState(state, nextFrame.get('key'), hoverState)
6760
}
61+
} else if (hoverState && frameStateUtil.getPreviewFrameKey(state) === action.frameKey) {
62+
state = frameStateUtil.setPreviewFrameKey(state, null)
6863
}
6964

7065
return state
@@ -124,12 +119,15 @@ const frameReducer = (state, action, immutableAction) => {
124119
const active = immutableAction.getIn(['tabValue', 'active'])
125120
if (active != null) {
126121
if (active) {
127-
state = state.merge({
128-
activeFrameKey: frame.get('key'),
129-
previewFrameKey: null
130-
})
122+
state = state.set('activeFrameKey', frame.get('key'))
123+
if (frame.get('hoverState')) {
124+
state = state.set('previewFrameKey', null)
125+
}
126+
if (frame.getIn(['ui', 'tabs', 'hoverTabPageIndex']) == null) {
127+
state = state.deleteIn(['ui', 'tabs', 'previewTabPageIndex'])
128+
}
131129
state = state.setIn(['frames', index, 'lastAccessedTime'], new Date().getTime())
132-
state = state.deleteIn(['ui', 'tabs', 'previewTabPageIndex'])
130+
133131
state = frameStateUtil.updateTabPageIndex(state, frame)
134132
}
135133
}

docs/windowActions.md

+14-1
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,8 @@ Dispatches a message to the store when the frame is active and the window is foc
192192
### setPreviewFrame(frameKey)
193193

194194
Dispatches a message to the store to set a preview frame.
195-
This is done when hovering over a tab.
195+
This should only be called internally by `WINDOW_SET_TAB_HOVER_STATE`
196+
when we need to delay updating the preview frame value
196197

197198
**Parameters**
198199

@@ -234,6 +235,18 @@ Dispatches a message to the store to set the current tab hover state.
234235

235236

236237

238+
### setTabPageHoverState(tabPageIndex, hoverState)
239+
240+
Dispatches a message to the store to set the current tab hover state.
241+
242+
**Parameters**
243+
244+
**tabPageIndex**: `Object`, the frame key for the webview in question.
245+
246+
**hoverState**: `boolean`, whether or not mouse is over tabPage
247+
248+
249+
237250
### setPreviewTabPageIndex(previewTabPageIndex)
238251

239252
Dispatches a message to the store to set the tab page index being previewed.

js/actions/windowActions.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,8 @@ const windowActions = {
229229

230230
/**
231231
* Dispatches a message to the store to set a preview frame.
232-
* This is done when hovering over a tab.
232+
* This should only be called internally by `WINDOW_SET_TAB_HOVER_STATE`
233+
* when we need to delay updating the preview frame value
233234
*
234235
* @param {Object} frameKey - the frame key for the webview in question.
235236
*/
@@ -280,6 +281,20 @@ const windowActions = {
280281
})
281282
},
282283

284+
/**
285+
* Dispatches a message to the store to set the current tab hover state.
286+
*
287+
* @param {Object} tabPageIndex - the frame key for the webview in question.
288+
* @param {boolean} hoverState - whether or not mouse is over tabPage
289+
*/
290+
setTabPageHoverState: function (tabPageIndex, hoverState) {
291+
dispatch({
292+
actionType: windowConstants.WINDOW_SET_TAB_PAGE_HOVER_STATE,
293+
tabPageIndex,
294+
hoverState
295+
})
296+
},
297+
283298
/**
284299
* Dispatches a message to the store to set the tab page index being previewed.
285300
*

js/constants/windowConstants.js

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const windowConstants = {
1515
WINDOW_SET_TAB_PAGE_INDEX: _,
1616
WINDOW_SET_TAB_BREAKPOINT: _,
1717
WINDOW_SET_TAB_HOVER_STATE: _,
18+
WINDOW_SET_TAB_PAGE_HOVER_STATE: _,
1819
WINDOW_TAB_MOVE: _,
1920
WINDOW_SET_THEME_COLOR: _,
2021
WINDOW_WEBVIEW_LOAD_END: _,

js/state/frameStateUtil.js

+118-5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ const {getSetting} = require('../settings')
2121
const {isIntermediateAboutPage} = require('../lib/appUrlUtil')
2222
const urlParse = require('../../app/common/urlParse')
2323

24+
let tabPageHoverTimeout
25+
let tabHoverTimeout = null
26+
2427
const comparatorByKeyAsc = (a, b) => a.get('key') > b.get('key')
2528
? 1 : b.get('key') > a.get('key') ? -1 : 0
2629

@@ -391,15 +394,13 @@ function removeFrame (state, frameProps, framePropsIndex) {
391394
}
392395

393396
return {
394-
previewFrameKey: null,
395397
closedFrames,
396398
frames: newFrames
397399
}
398400
}
399401

400-
function getFrameTabPageIndex (state, frameProps, tabsPerTabPage) {
401-
frameProps = makeImmutable(frameProps)
402-
const index = findNonPinnedDisplayIndexForFrameKey(state, frameProps.get('key'))
402+
function getFrameTabPageIndex (state, frameKey, tabsPerTabPage = getSetting(settings.TABS_PER_PAGE)) {
403+
const index = findNonPinnedDisplayIndexForFrameKey(state, frameKey)
403404
if (index === -1) {
404405
return -1
405406
}
@@ -451,7 +452,8 @@ function isPinned (state, frameKey) {
451452
* @param frameProps Any frame belonging to the page
452453
*/
453454
function updateTabPageIndex (state, frameProps) {
454-
const index = getFrameTabPageIndex(state, frameProps, getSetting(settings.TABS_PER_PAGE))
455+
frameProps = makeImmutable(frameProps)
456+
const index = getFrameTabPageIndex(state, frameProps.get('key'))
455457

456458
if (index === -1) {
457459
return state
@@ -525,7 +527,118 @@ const isValidClosedFrame = (frame) => {
525527
return !frame.get('isPrivate')
526528
}
527529

530+
const getTabPageCount = (state) => {
531+
const frames = getNonPinnedFrames(state) || Immutable.List()
532+
const tabsPerPage = Number(getSetting(settings.TABS_PER_PAGE))
533+
534+
return Math.ceil(frames.size / tabsPerPage)
535+
}
536+
537+
const getPreviewFrameKey = (state) => {
538+
return state.get('previewFrameKey')
539+
}
540+
541+
const setPreviewTabPageIndex = (state, index, immediate = false) => {
542+
clearTimeout(tabPageHoverTimeout)
543+
const previewTabs = getSetting(settings.SHOW_TAB_PREVIEWS)
544+
const isActive = state.getIn(['ui', 'tabs', 'tabPageIndex']) === index
545+
let newTabPageIndex = index
546+
547+
if (!previewTabs || state.getIn(['ui', 'tabs', 'hoverTabPageIndex']) !== index || isActive) {
548+
newTabPageIndex = null
549+
}
550+
551+
if (!immediate) {
552+
// if there is an existing preview tab page index then we're already in preview mode
553+
// we use actions here because that is the only way to delay updating the state
554+
const previewMode = state.getIn(['ui', 'tabs', 'previewTabPageIndex']) != null
555+
if (previewMode && newTabPageIndex == null) {
556+
// add a small delay when we are clearing the preview frame key so we don't lose
557+
// previewMode if the user mouses over another tab - see below
558+
tabPageHoverTimeout = setTimeout(windowActions.setPreviewTabPageIndex.bind(null, null), 200)
559+
return state
560+
}
561+
562+
if (!previewMode) {
563+
// If user isn't in previewMode so we add a bit of delay to avoid tab from flashing out
564+
// as reported here: https://github.com/brave/browser-laptop/issues/1434
565+
// using an action here because that is the only way we can do a delayed state update
566+
tabPageHoverTimeout = setTimeout(windowActions.setPreviewTabPageIndex.bind(null, newTabPageIndex), 200)
567+
return state
568+
}
569+
}
570+
571+
return state.setIn(['ui', 'tabs', 'previewTabPageIndex'], newTabPageIndex)
572+
}
573+
574+
const setPreviewFrameKey = (state, frameKey, immediate = false) => {
575+
clearTimeout(tabHoverTimeout)
576+
const frame = getFrameByKey(state, frameKey)
577+
const isActive = isFrameKeyActive(state, frameKey)
578+
const previewTabs = getSetting(settings.SHOW_TAB_PREVIEWS)
579+
let newPreviewFrameKey = frameKey
580+
581+
if (!previewTabs || frame == null || !frame.get('hoverState') || isActive) {
582+
newPreviewFrameKey = null
583+
}
584+
585+
if (!immediate) {
586+
// if there is an existing preview frame key then we're already in preview mode
587+
// we use actions here because that is the only way to delay updating the state
588+
const previewMode = getPreviewFrameKey(state) != null
589+
if (previewMode && newPreviewFrameKey == null) {
590+
// add a small delay when we are clearing the preview frame key so we don't lose
591+
// previewMode if the user mouses over another tab - see below
592+
tabHoverTimeout = setTimeout(windowActions.setPreviewFrame.bind(null, null), 200)
593+
return state
594+
}
595+
596+
if (!previewMode) {
597+
// If user isn't in previewMode so we add a bit of delay to avoid tab from flashing out
598+
// as reported here: https://github.com/brave/browser-laptop/issues/1434
599+
// using an action here because that is the only way we can do a delayed state update
600+
tabHoverTimeout = setTimeout(windowActions.setPreviewFrame.bind(null, newPreviewFrameKey), 200)
601+
return state
602+
}
603+
}
604+
605+
const index = getFrameTabPageIndex(state, frame)
606+
if (index !== -1) {
607+
if (index !== state.getIn(['ui', 'tabs', 'tabPageIndex'])) {
608+
state = state.setIn(['ui', 'tabs', 'previewTabPageIndex'], index)
609+
} else {
610+
state = state.deleteIn(['ui', 'tabs', 'previewTabPageIndex'])
611+
}
612+
}
613+
return state.set('previewFrameKey', newPreviewFrameKey)
614+
}
615+
616+
const setTabPageHoverState = (state, tabPageIndex, hoverState) => {
617+
const currentHoverIndex = state.getIn(['ui', 'tabs', 'hoverTabPageIndex'])
618+
if (!hoverState && currentHoverIndex === tabPageIndex) {
619+
state = state.setIn(['ui', 'tabs', 'hoverTabPageIndex'], null)
620+
} else if (hoverState) {
621+
state = state.setIn(['ui', 'tabs', 'hoverTabPageIndex'], tabPageIndex)
622+
}
623+
state = setPreviewTabPageIndex(state, tabPageIndex)
624+
return state
625+
}
626+
627+
const setTabHoverState = (state, frameKey, hoverState) => {
628+
const frameIndex = getFrameIndex(state, frameKey)
629+
if (frameIndex !== -1) {
630+
state = state.setIn(['frames', frameIndex, 'hoverState'], hoverState)
631+
state = setPreviewFrameKey(state, frameKey)
632+
}
633+
return state
634+
}
635+
528636
module.exports = {
637+
setTabPageHoverState,
638+
setPreviewTabPageIndex,
639+
setTabHoverState,
640+
setPreviewFrameKey,
641+
getPreviewFrameKey,
529642
deleteTabInternalIndex,
530643
deleteFrameInternalIndex,
531644
updateFramesInternalIndex,

0 commit comments

Comments
 (0)