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

Commit a3307ef

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 9d191cb commit a3307ef

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,13 +13,10 @@ 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')
21-
const {getSetting} = require('../../../js/settings')
22-
const settings = require('../../../js/constants/settings')
2320

2421
const setFullScreen = (state, action) => {
2522
const index = frameStateUtil.getFrameIndex(state, action.frameProps.get('key'))
@@ -30,15 +27,13 @@ const setFullScreen = (state, action) => {
3027
}
3128

3229
const closeFrame = (state, action) => {
33-
const activeFrameIndex = frameStateUtil.getActiveFrameIndex(state)
3430
const index = frameStateUtil.getFrameIndex(state, action.frameKey)
3531
if (index === -1) {
3632
return state
3733
}
3834

3935
const frameProps = frameStateUtil.getFrameByKey(state, action.frameKey)
4036
const hoverState = state.getIn(['frames', index, 'hoverState'])
41-
const framePreviewEnabled = getSetting(settings.SHOW_TAB_PREVIEWS)
4237

4338
state = state.merge(frameStateUtil.removeFrame(
4439
state,
@@ -54,15 +49,15 @@ const closeFrame = (state, action) => {
5449

5550
const nextFrame = frameStateUtil.getFrameByIndex(state, index)
5651

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

6863
return state
@@ -109,12 +104,15 @@ const frameReducer = (state, action, immutableAction) => {
109104
const active = immutableAction.getIn(['tabValue', 'active'])
110105
if (active != null) {
111106
if (active) {
112-
state = state.merge({
113-
activeFrameKey: frame.get('key'),
114-
previewFrameKey: null
115-
})
107+
state = state.set('activeFrameKey', frame.get('key'))
108+
if (frame.get('hoverState')) {
109+
state = state.set('previewFrameKey', null)
110+
}
111+
if (frame.getIn(['ui', 'tabs', 'hoverTabPageIndex']) == null) {
112+
state = state.deleteIn(['ui', 'tabs', 'previewTabPageIndex'])
113+
}
116114
state = state.setIn(['frames', index, 'lastAccessedTime'], new Date().getTime())
117-
state = state.deleteIn(['ui', 'tabs', 'previewTabPageIndex'])
115+
118116
state = frameStateUtil.updateTabPageIndex(state, frame)
119117
}
120118
}

docs/windowActions.md

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

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

209210
**Parameters**
210211

@@ -246,6 +247,18 @@ Dispatches a message to the store to set the current tab hover state.
246247

247248

248249

250+
### setTabPageHoverState(tabPageIndex, hoverState)
251+
252+
Dispatches a message to the store to set the current tab hover state.
253+
254+
**Parameters**
255+
256+
**tabPageIndex**: `Object`, the frame key for the webview in question.
257+
258+
**hoverState**: `boolean`, whether or not mouse is over tabPage
259+
260+
261+
249262
### setPreviewTabPageIndex(previewTabPageIndex)
250263

251264
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
@@ -243,7 +243,8 @@ const windowActions = {
243243

244244
/**
245245
* Dispatches a message to the store to set a preview frame.
246-
* This is done when hovering over a tab.
246+
* This should only be called internally by `WINDOW_SET_TAB_HOVER_STATE`
247+
* when we need to delay updating the preview frame value
247248
*
248249
* @param {Object} frameKey - the frame key for the webview in question.
249250
*/
@@ -294,6 +295,20 @@ const windowActions = {
294295
})
295296
},
296297

298+
/**
299+
* Dispatches a message to the store to set the current tab hover state.
300+
*
301+
* @param {Object} tabPageIndex - the frame key for the webview in question.
302+
* @param {boolean} hoverState - whether or not mouse is over tabPage
303+
*/
304+
setTabPageHoverState: function (tabPageIndex, hoverState) {
305+
dispatch({
306+
actionType: windowConstants.WINDOW_SET_TAB_PAGE_HOVER_STATE,
307+
tabPageIndex,
308+
hoverState
309+
})
310+
},
311+
297312
/**
298313
* Dispatches a message to the store to set the tab page index being previewed.
299314
*

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

@@ -393,15 +396,13 @@ function removeFrame (state, frameProps, framePropsIndex) {
393396
}
394397

395398
return {
396-
previewFrameKey: null,
397399
closedFrames,
398400
frames: newFrames
399401
}
400402
}
401403

402-
function getFrameTabPageIndex (state, frameProps, tabsPerTabPage) {
403-
frameProps = makeImmutable(frameProps)
404-
const index = findNonPinnedDisplayIndexForFrameKey(state, frameProps.get('key'))
404+
function getFrameTabPageIndex (state, frameKey, tabsPerTabPage = getSetting(settings.TABS_PER_PAGE)) {
405+
const index = findNonPinnedDisplayIndexForFrameKey(state, frameKey)
405406
if (index === -1) {
406407
return -1
407408
}
@@ -453,7 +454,8 @@ function isPinned (state, frameKey) {
453454
* @param frameProps Any frame belonging to the page
454455
*/
455456
function updateTabPageIndex (state, frameProps) {
456-
const index = getFrameTabPageIndex(state, frameProps, getSetting(settings.TABS_PER_PAGE))
457+
frameProps = makeImmutable(frameProps)
458+
const index = getFrameTabPageIndex(state, frameProps.get('key'))
457459

458460
if (index === -1) {
459461
return state
@@ -522,7 +524,118 @@ const isValidClosedFrame = (frame) => {
522524
return !frame.get('isPrivate')
523525
}
524526

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

0 commit comments

Comments
 (0)