diff --git a/app/common/state/tabState.js b/app/common/state/tabState.js
index 8e93e80226b..face69325c7 100644
--- a/app/common/state/tabState.js
+++ b/app/common/state/tabState.js
@@ -10,6 +10,12 @@ const windowState = require('./windowState')
// this file should eventually replace frameStateUtil
const frameStateUtil = require('../../../js/state/frameStateUtil')
const {isLocationBookmarked} = require('../../../js/state/siteUtil')
+const locale = require('../../../js/l10n')
+const getSetting = require('../../../js/settings').getSetting
+const settings = require('../../../js/constants/settings.js')
+const styles = require('../../renderer/components/styles/global')
+const {hasBreakpoint} = require('../../renderer/lib/tabUtil')
+const {getTextColorForBackground} = require('../../../js/lib/color')
const validateId = function (propName, id) {
assert.ok(id, `${propName} cannot be null`)
@@ -429,6 +435,145 @@ const tabState = {
state = tabState.removeTabField(state, 'frame')
state = state.delete('tabsInternal')
return state.delete('tabs')
+ },
+
+ getPageIndex: (windowState) => {
+ const tabPageIndex = windowState.getIn(['ui', 'tabs', 'tabPageIndex'])
+ const previewTabPageIndex = windowState.getIn(['ui', 'tabs', 'previewTabPageIndex'])
+
+ return previewTabPageIndex !== undefined
+ ? previewTabPageIndex : tabPageIndex
+ },
+
+ getTabWindowProps: (windowState, frameKey) => {
+ return windowState.get('tabs').find((tab) => tab.get('frameKey') === frameKey) || makeImmutable({})
+ },
+
+ getThemeColor: (windowState, frameKey) => {
+ const tab = tabState.getTabWindowProps(windowState, frameKey)
+ return getSetting(settings.PAINT_TABS) && (tab.get('themeColor') || tab.get('computedThemeColor'))
+ },
+
+ canPlayAudio: (windowState, frameKey) => {
+ const tab = tabState.getTabWindowProps(windowState, frameKey)
+ return tab.get('audioPlaybackActive') || tab.get('audioMuted')
+ },
+
+ isTabLoading (windowState, frameKey) {
+ const tab = tabState.getTabWindowProps(windowState, frameKey)
+ return tab.size > 0 &&
+ (tab.get('loading') ||
+ tab.get('location') === 'about:blank') &&
+ (!tab.get('provisionalLocation') ||
+ !tab.get('provisionalLocation').startsWith('chrome-extension://mnojpmjdmbbfmejpflffifhffcmidifd/'))
+ },
+
+ isMediumView (windowState, frameKey) {
+ const tab = tabState.getTabWindowProps(windowState, frameKey)
+ const sizes = ['large', 'largeMedium']
+
+ return sizes.includes(tab.get('breakpoint'))
+ },
+
+ isNarrowView (windowState, frameKey) {
+ const tab = tabState.getTabWindowProps(windowState, frameKey)
+ const sizes = ['medium', 'mediumSmall', 'small', 'extraSmall', 'smallest']
+
+ return sizes.includes(tab.get('breakpoint'))
+ },
+
+ isNarrowestView (windowState, frameKey) {
+ const tab = tabState.getTabWindowProps(windowState, frameKey)
+ const sizes = ['extraSmall', 'smallest']
+
+ return sizes.includes(tab.get('breakpoint'))
+ },
+
+ getDisplayTitle (windowState, frameKey) {
+ const tab = tabState.getTabWindowProps(windowState, frameKey)
+
+ if (tab.size === 0) {
+ return ''
+ }
+
+ // For renderer initiated navigations, make sure we show Untitled
+ // until we know what we're loading. We should probably do this for
+ // all about: pages that we already know the title for so we don't have
+ // to wait for the title to be parsed.
+ if (tab.get('location') === 'about:blank') {
+ return locale.translation('aboutBlankTitle')
+ } else if (tab.get('location') === 'about:newtab') {
+ return locale.translation('newTab')
+ }
+
+ // YouTube tries to change the title to add a play icon when
+ // there is audio. Since we have our own audio indicator we get
+ // rid of it.
+ return (tab.get('title') || tab.get('location') || '').replace('▶ ', '')
+ },
+
+ getTabIconColor (windowState, frameKey) {
+ const tab = tabState.getTabWindowProps(windowState, frameKey)
+ const isActive = frameStateUtil.isFrameKeyActive(windowState, frameKey)
+
+ if (tab.size === 0) {
+ return ''
+ }
+
+ const themeColor = tab.get('themeColor') || tab.get('computedThemeColor')
+ const activeNonPrivateTab = !tab.get('isPrivate') && isActive
+ const isPrivateTab = tab.get('isPrivate') && (isActive || tab.get('hoverState'))
+ const defaultColor = isPrivateTab ? styles.color.white100 : styles.color.black100
+ const isPaintTabs = getSetting(settings.PAINT_TABS)
+
+ return activeNonPrivateTab && isPaintTabs && !!themeColor
+ ? getTextColorForBackground(themeColor)
+ : defaultColor
+ },
+
+ /**
+ * Check whether or not closeTab icon is always visible (fixed) in tab
+ */
+ hasFixedCloseIcon (windowState, frameKey) {
+ const tab = tabState.getTabWindowProps(windowState, frameKey)
+ const isActive = frameStateUtil.isFrameKeyActive(windowState, frameKey)
+
+ if (tab.size === 0) {
+ return false
+ }
+
+ return (
+ isActive &&
+ // larger sizes still have a relative closeIcon
+ !hasBreakpoint(tab.get('breakpoint'), ['default', 'large']) &&
+ // We don't resize closeIcon as we do with favicon so don't show it
+ !hasBreakpoint(tab.get('breakpoint'), 'smallest')
+ )
+ },
+
+ /**
+ * Check whether or not closeTab icon is relative to hover state
+ */
+ hasRelativeCloseIcon (windowState, frameKey) {
+ const tab = tabState.getTabWindowProps(windowState, frameKey)
+
+ return tab.get('hoverState') && hasBreakpoint(tab.get('breakpoint'), ['default', 'large'])
+ },
+
+ /**
+ * Check whether or not private or newSession icon should be visible
+ */
+ hasVisibleSecondaryIcon (windowState, frameKey) {
+ const tab = tabState.getTabWindowProps(windowState, frameKey)
+
+ return (
+ // Hide icon on hover
+ !tabState.hasRelativeCloseIcon(windowState, frameKey) &&
+ // If closeIcon is fixed then there's no room for another icon
+ !tabState.hasFixedCloseIcon(windowState, frameKey) &&
+ // completely hide it for small sizes
+ !hasBreakpoint(tab.get('breakpoint'), ['mediumSmall', 'small', 'extraSmall', 'smallest'])
+ )
}
}
diff --git a/app/renderer/components/main/main.js b/app/renderer/components/main/main.js
index 270795cdacf..14ed081e658 100644
--- a/app/renderer/components/main/main.js
+++ b/app/renderer/components/main/main.js
@@ -59,6 +59,7 @@ const shieldState = require('../../../common/state/shieldState')
const siteSettingsState = require('../../../common/state/siteSettingsState')
const menuBarState = require('../../../common/state/menuBarState')
const windowState = require('../../../common/state/windowState.js')
+const windowStore = require('../stores/windowStore')
// Util
const _ = require('underscore')
@@ -84,7 +85,6 @@ class Main extends ImmutableComponent {
this.onHideNoScript = this.onHideNoScript.bind(this)
this.onHideReleaseNotes = this.onHideReleaseNotes.bind(this)
this.onHideCheckDefaultBrowserDialog = this.onHideCheckDefaultBrowserDialog.bind(this)
- this.onHamburgerMenu = this.onHamburgerMenu.bind(this)
this.onTabContextMenu = this.onTabContextMenu.bind(this)
this.onFind = this.onFind.bind(this)
this.onFindHide = this.onFindHide.bind(this)
@@ -503,6 +503,22 @@ class Main extends ImmutableComponent {
self.resetAltMenuProcessing()
windowActions.onBlur(getCurrentWindowId())
}
+
+ windowStore.addChangeListener(function () {
+ const paymentsEnabled = getSetting(settings.PAYMENTS_ENABLED)
+ if (paymentsEnabled) {
+ const windowState = self.props.windowState
+ const tabs = windowState && windowState.get('tabs')
+ if (tabs) {
+ try {
+ const presentP = tabs.some((tab) => {
+ return tab.get('location') === 'about:preferences#payments'
+ })
+ ipc.send(messages.LEDGER_PAYMENTS_PRESENT, presentP)
+ } catch (ex) { }
+ }
+ }
+ })
}
checkForTitleMode () {
@@ -527,11 +543,6 @@ class Main extends ImmutableComponent {
}
}
- onHamburgerMenu (e) {
- const activeFrame = frameStateUtil.getActiveFrame(this.props.windowState)
- contextMenus.onHamburgerMenu((activeFrame && activeFrame.get('location')) || '', e)
- }
-
onHideSiteInfo () {
windowActions.setSiteInfoVisible(false)
}
@@ -695,7 +706,6 @@ class Main extends ImmutableComponent {
const notifications = this.props.appState.get('notifications')
const hasNotifications = notifications && notifications.size
- const notificationBarOrigin = notifications.map(bar => bar.get('frameOrigin'))
return
frame.get('isFullScreen'))
- .some(fullScreenMode => fullScreenMode === true)
- }
+ shouldAllowWindowDrag={shouldAllowWindowDrag}
/>
{
hasNotifications && activeFrame
diff --git a/app/renderer/components/tabs/content/audioTabIcon.js b/app/renderer/components/tabs/content/audioTabIcon.js
index bde0765c55d..47d1aa6237c 100644
--- a/app/renderer/components/tabs/content/audioTabIcon.js
+++ b/app/renderer/components/tabs/content/audioTabIcon.js
@@ -6,44 +6,66 @@ const React = require('react')
const {StyleSheet, css} = require('aphrodite/no-important')
// Components
-const ImmutableComponent = require('../../immutableComponent')
+const ReduxComponent = require('../../reduxComponent')
const TabIcon = require('./tabIcon')
+// State
+const tabState = require('../../../../common/state/tabState.js')
+
+// Actions
+const windowActions = require('../../../../../js/actions/windowActions.js')
+
+// Utils
+const frameStateUtil = require('../../../../../js/state/frameStateUtil.js')
+
// Styles
const globalStyles = require('../../styles/global')
const tabStyles = require('../../styles/tab')
-class AudioTabIcon extends ImmutableComponent {
- get pageCanPlayAudio () {
- return !!this.props.frame.get('audioPlaybackActive')
+class AudioTabIcon extends React.Component {
+ constructor () {
+ super()
+ this.toggleMute = this.toggleMute.bind(this)
}
- get shouldShowAudioIcon () {
- // We switch to blue top bar for all breakpoints but default
- return this.props.frame.get('breakpoint') === 'default'
+ get audioIcon () {
+ const isMuted = this.props.pageCanPlayAudio && !this.props.audioMuted
+
+ return isMuted
+ ? globalStyles.appIcons.volumeOn
+ : globalStyles.appIcons.volumeOff
}
- get mutedState () {
- return this.pageCanPlayAudio && !!this.props.frame.get('audioMuted')
+ toggleMute (event) {
+ event.stopPropagation()
+ windowActions.setAudioMuted(this.props.frameKey, this.props.tabId, !this.props.audioMuted)
}
- get audioIcon () {
- return !this.mutedState
- ? globalStyles.appIcons.volumeOn
- : globalStyles.appIcons.volumeOff
+ mergeProps (state, dispatchProps, ownProps) {
+ const currentWindow = state.get('currentWindow')
+ const tab = tabState.getTabWindowProps(currentWindow, ownProps.frameKey)
+ const frame = frameStateUtil.getFrameByKey(currentWindow, ownProps.frameKey)
+
+ const props = {}
+ // used in renderer
+
+ // used in other functions
+ props.pageCanPlayAudio = !!tab.get('audioPlaybackActive')
+ props.tabId = frame ? frame.get('tabId') : tabState.TAB_ID_NONE
+ props.audioMuted = tab.get('audioMuted')
+
+ return Object.assign({}, ownProps, props)
}
render () {
- return this.pageCanPlayAudio && this.shouldShowAudioIcon
- ?
- : null
+ return
}
}
-module.exports = AudioTabIcon
+module.exports = ReduxComponent.connect(AudioTabIcon)
const styles = StyleSheet.create({
audioIcon: {
diff --git a/app/renderer/components/tabs/content/closeTabIcon.js b/app/renderer/components/tabs/content/closeTabIcon.js
index 33d3afc3ce7..1707edc1599 100644
--- a/app/renderer/components/tabs/content/closeTabIcon.js
+++ b/app/renderer/components/tabs/content/closeTabIcon.js
@@ -6,34 +6,68 @@ const React = require('react')
const {StyleSheet, css} = require('aphrodite/no-important')
// Components
-const ImmutableComponent = require('../../immutableComponent')
+const ReduxComponent = require('../../reduxComponent')
const TabIcon = require('./tabIcon')
-// Utils
-const {hasRelativeCloseIcon, hasFixedCloseIcon} = require('../../../lib/tabUtil')
+// State
+const tabState = require('../../../../common/state/tabState.js')
+
+// Store
+const windowStore = require('../../../../../js/stores/windowStore.js')
+
+// Actions
+const windowActions = require('../../../../../js/actions/windowActions.js')
// Styles
const globalStyles = require('../../styles/global')
const closeTabHoverSvg = require('../../../../extensions/brave/img/tabs/close_btn_hover.svg')
const closeTabSvg = require('../../../../extensions/brave/img/tabs/close_btn_normal.svg')
-class CloseTabIcon extends ImmutableComponent {
- get isPinned () {
- return !!this.props.frame.get('pinnedLocation')
+class CloseTabIcon extends React.Component {
+ constructor () {
+ super()
+ this.onClick = this.onClick.bind(this)
+ }
+ get frame () {
+ return windowStore.getFrame(this.props.frameKey)
+ }
+
+ onClick (event) {
+ event.stopPropagation()
+ if (this.frame && !this.frame.isEmpty()) {
+ // const rect = this.tabNode.parentNode.getBoundingClientRect() TODO FIX IT
+ windowActions.onTabClosedWithMouse({
+ fixTabWidth: 200 // rect.width
+ })
+ windowActions.closeFrame(this.frame)
+ }
+ }
+
+ mergeProps (state, dispatchProps, ownProps) {
+ const currentWindow = state.get('currentWindow')
+ const isPinnedTab = tabState.isPinned(currentWindow, ownProps.frameKey)
+
+ const props = {}
+
+ props.showCloseIcon = !isPinnedTab &&
+ (
+ tabState.hasRelativeCloseIcon(currentWindow, ownProps.frameKey) ||
+ tabState.hasFixedCloseIcon(currentWindow, ownProps.frameKey)
+ )
+ return Object.assign({}, ownProps, props)
}
render () {
- return !this.isPinned &&
- (hasRelativeCloseIcon(this.props) || hasFixedCloseIcon(this.props))
- ?
- : null
+ return
}
}
-module.exports = CloseTabIcon
+module.exports = ReduxComponent.connect(CloseTabIcon)
const styles = StyleSheet.create({
closeTab: {
diff --git a/app/renderer/components/tabs/content/favIcon.js b/app/renderer/components/tabs/content/favIcon.js
index b04f886c446..c539e9919ec 100644
--- a/app/renderer/components/tabs/content/favIcon.js
+++ b/app/renderer/components/tabs/content/favIcon.js
@@ -6,11 +6,11 @@ const React = require('react')
const {StyleSheet, css} = require('aphrodite/no-important')
// Components
-const ImmutableComponent = require('../../immutableComponent')
+const ReduxComponent = require('../../reduxComponent')
const TabIcon = require('./tabIcon')
-// Utils
-const {hasBreakpoint, getTabIconColor} = require('../../../lib/tabUtil')
+// State
+const tabState = require('../../../../common/state/tabState.js')
// Styles
const globalStyles = require('../../styles/global')
@@ -18,63 +18,65 @@ const tabStyles = require('../../styles/tab')
const {spinKeyframes} = require('../../styles/animations')
const loadingIconSvg = require('../../../../extensions/brave/img/tabs/loading.svg')
-class Favicon extends ImmutableComponent {
- get favicon () {
- return !this.props.isLoading && this.props.frame.get('icon')
- }
-
+class Favicon extends React.Component {
get defaultIcon () {
- return (!this.props.isLoading && !this.favicon)
+ return (!this.props.isTabLoading && !this.props.favicon)
? globalStyles.appIcons.defaultIcon
: null
}
- get narrowView () {
- return this.props.frame.get('breakpoint') === 'smallest'
- }
+ mergeProps (state, dispatchProps, ownProps) {
+ const currentWindow = state.get('currentWindow')
+ const tab = tabState.getTabWindowProps(currentWindow, ownProps.frameKey)
+ const isTabLoading = tabState.isTabLoading(currentWindow, ownProps.frameKey)
- get shouldHideFavicon () {
- return (hasBreakpoint(this.props, 'extraSmall') && this.props.isActive) ||
- this.props.frame.get('location') === 'about:newtab'
+ const props = {}
+
+ // used in renderer
+ props.isTabLoading = isTabLoading
+ props.favicon = !isTabLoading && tab.get('icon')
+ props.isPinnedTab = tabState.isPinned(currentWindow, ownProps.frameKey)
+ props.tabIconColor = tabState.getTabIconColor(currentWindow, ownProps.frameKey)
+ props.isNarrowestView = tabState.isNarrowestView(currentWindow, ownProps.frameKey)
+
+ return Object.assign({}, ownProps, props)
}
render () {
const iconStyles = StyleSheet.create({
favicon: {
- backgroundImage: `url(${this.favicon})`,
- filter: getTabIconColor(this.props) === 'white' ? globalStyles.filter.whiteShadow : 'none'
+ backgroundImage: `url(${this.props.favicon})`,
+ filter: this.props.tabIconColor === 'white' ? globalStyles.filter.whiteShadow : 'none'
},
loadingIconColor: {
// Don't change icon color unless when it should be white
- filter: getTabIconColor(this.props) === 'white' ? globalStyles.filter.makeWhite : 'none'
+ filter: this.props.tabIconColor === 'white' ? globalStyles.filter.makeWhite : 'none'
}
})
- return !this.shouldHideFavicon
- ?
- : null
+ return
}
}
-module.exports = Favicon
+module.exports = ReduxComponent.connect(Favicon)
const styles = StyleSheet.create({
faviconNarrowView: {
minWidth: 'auto',
width: globalStyles.spacing.narrowIconSize,
backgroundSize: 'contain',
- padding: '0',
+ padding: 0,
fontSize: '10px',
backgroundPosition: 'center center'
},
diff --git a/app/renderer/components/tabs/content/newSessionIcon.js b/app/renderer/components/tabs/content/newSessionIcon.js
index 3ecd100fca4..cd90c3920ca 100644
--- a/app/renderer/components/tabs/content/newSessionIcon.js
+++ b/app/renderer/components/tabs/content/newSessionIcon.js
@@ -6,61 +6,62 @@ const React = require('react')
const {StyleSheet, css} = require('aphrodite/no-important')
// Components
-const ImmutableComponent = require('../../immutableComponent')
+const ReduxComponent = require('../../reduxComponent')
const TabIcon = require('./tabIcon')
-// Utils
-const {hasVisibleSecondaryIcon, getTabIconColor} = require('../../../lib/tabUtil')
+// State
+const tabState = require('../../../../common/state/tabState.js')
// Constants
const {tabs} = require('../../../../../js/constants/config')
+// Utils
+const frameStateUtil = require('../../../../../js/state/frameStateUtil.js')
+
// Styles
const tabStyles = require('../../styles/tab')
const newSessionSvg = require('../../../../extensions/brave/img/tabs/new_session.svg')
-class NewSessionIcon extends ImmutableComponent {
- get partitionNumber () {
- let partition = this.props.frame.get('partitionNumber')
- // Persistent partitions opened by `target="_blank"` will have
- // *partition-* string first, which causes bad UI. We don't need it for tabs
- if (typeof partition === 'string') {
- partition = partition.replace(/^partition-/i, '')
- }
- return partition
- }
+class NewSessionIcon extends React.Component {
+ mergeProps (state, dispatchProps, ownProps) {
+ const currentWindow = state.get('currentWindow')
+ const tab = tabState.getTabWindowProps(currentWindow, ownProps.frameKey)
+ const partition = tab.get('partitionNumber')
- get partitionIndicator () {
- // For now due to UI limitations set session up to 9 visually
- return this.partitionNumber > tabs.maxAllowedNewSessions
+ const props = {}
+ // used in renderer
+ props.isActive = frameStateUtil.isFrameKeyActive(currentWindow, ownProps.frameKey)
+ props.iconColor = tabState.getTabIconColor(currentWindow, ownProps.frameKey)
+ props.partitionNumber = typeof partition === 'string'
+ ? partition.replace(/^partition-/i, '')
+ : partition
+ props.partitionIndicator = props.partitionNumber > tabs.maxAllowedNewSessions
? tabs.maxAllowedNewSessions
- : this.partitionNumber
- }
+ : props.partitionNumber
+ props.partition = partition
- get iconColor () {
- return getTabIconColor(this.props)
+ return Object.assign({}, ownProps, props)
}
render () {
const newSession = StyleSheet.create({
indicator: {
// Based on getTextColorForBackground() icons can be only black or white.
- filter: this.props.isActive && this.iconColor === 'white' ? 'invert(100%)' : 'none'
+ filter: this.props.isActive && this.props.iconColor === 'white' ? 'invert(100%)' : 'none'
}
})
- return this.partitionNumber && hasVisibleSecondaryIcon(this.props)
- ?
- : null
+ return
}
}
-module.exports = NewSessionIcon
+module.exports = ReduxComponent.connect(NewSessionIcon)
const styles = StyleSheet.create({
newSession: {
diff --git a/app/renderer/components/tabs/content/privateIcon.js b/app/renderer/components/tabs/content/privateIcon.js
index 74ace2624a1..40d33994829 100644
--- a/app/renderer/components/tabs/content/privateIcon.js
+++ b/app/renderer/components/tabs/content/privateIcon.js
@@ -6,18 +6,28 @@ const React = require('react')
const {StyleSheet, css} = require('aphrodite/no-important')
// Components
-const ImmutableComponent = require('../../immutableComponent')
+const ReduxComponent = require('../../reduxComponent')
const TabIcon = require('./tabIcon')
// Utils
-const {hasVisibleSecondaryIcon} = require('../../../lib/tabUtil')
+const frameStateUtil = require('../../../../../js/state/frameStateUtil.js')
// Styles
const globalStyles = require('../../styles/global')
const tabStyles = require('../../styles/tab')
const privateSvg = require('../../../../extensions/brave/img/tabs/private.svg')
-class PrivateIcon extends ImmutableComponent {
+class PrivateIcon extends React.Component {
+ mergeProps (state, dispatchProps, ownProps) {
+ const currentWindow = state.get('currentWindow')
+
+ const props = {}
+ // used in renderer
+ props.isActive = frameStateUtil.isFrameKeyActive(currentWindow, ownProps.frameKey)
+
+ return Object.assign({}, ownProps, props)
+ }
+
render () {
const privateStyles = StyleSheet.create({
icon: {
@@ -25,15 +35,14 @@ class PrivateIcon extends ImmutableComponent {
}
})
- return this.props.frame.get('isPrivate') && hasVisibleSecondaryIcon(this.props)
- ?
- : null
+ return
}
}
-module.exports = PrivateIcon
+module.exports = ReduxComponent.connect(PrivateIcon)
const styles = StyleSheet.create({
secondaryIcon: {
diff --git a/app/renderer/components/tabs/content/tabTitle.js b/app/renderer/components/tabs/content/tabTitle.js
index 8fdac918cfa..e6b3fb36c5d 100644
--- a/app/renderer/components/tabs/content/tabTitle.js
+++ b/app/renderer/components/tabs/content/tabTitle.js
@@ -6,56 +6,53 @@ const React = require('react')
const {StyleSheet, css} = require('aphrodite/no-important')
// Components
-const ImmutableComponent = require('../../immutableComponent')
+const ReduxComponent = require('../../reduxComponent')
+
+// State
+const tabState = require('../../../../common/state/tabState')
// Utils
-const {hasBreakpoint, getTabIconColor} = require('../../../lib/tabUtil')
const {isWindows, isDarwin} = require('../../../../common/lib/platformUtil')
// Styles
const globalStyles = require('../../styles/global')
-class TabTitle extends ImmutableComponent {
- get isActiveOrHasSecondaryIcon () {
- return this.props.isActive ||
- (!!this.props.frame.get('isPrivate') || !!this.props.frame.get('partitionNumber'))
- }
+class TabTitle extends React.Component {
+ mergeProps (state, dispatchProps, ownProps) {
+ const currentWindow = state.get('currentWindow')
+ const tabIconColor = tabState.getTabIconColor(currentWindow, ownProps.frameKey)
- get isPinned () {
- return !!this.props.frame.get('pinnedLocation')
- }
+ const props = {}
+ // used in renderer
+ props.enforceFontVisibilty = isDarwin() && tabIconColor === 'white'
+ props.tabIconColor = tabIconColor
+ props.displayTitle = tabState.getDisplayTitle(currentWindow, ownProps.frameKey)
- get shouldHideTitle () {
- return (hasBreakpoint(this.props, 'small') && this.props.isActive) ||
- hasBreakpoint(this.props, ['extraSmall', 'smallest'])
+ return Object.assign({}, ownProps, props)
}
render () {
- // Brad said that tabs with white title on macOS look too thin
- const enforceFontVisibilty = isDarwin() && getTabIconColor(this.props) === 'white'
const titleStyles = StyleSheet.create({
gradientText: {
backgroundImage: `-webkit-linear-gradient(left,
- ${getTabIconColor(this.props)} 90%, ${globalStyles.color.almostInvisible} 100%)`
+ ${this.props.tabIconColor} 90%, ${globalStyles.color.almostInvisible} 100%)`
}
})
- return !this.isPinned && !this.shouldHideTitle
- ?
- {this.props.pageTitle}
-
- : null
+ return
+ {this.props.displayTitle}
+
}
}
-module.exports = TabTitle
+module.exports = ReduxComponent.connect(TabTitle)
const styles = StyleSheet.create({
tabTitle: {
diff --git a/app/renderer/components/tabs/pinnedTabs.js b/app/renderer/components/tabs/pinnedTabs.js
index bc921f28e79..542730b113a 100644
--- a/app/renderer/components/tabs/pinnedTabs.js
+++ b/app/renderer/components/tabs/pinnedTabs.js
@@ -6,7 +6,7 @@ const React = require('react')
const ReactDOM = require('react-dom')
// Components
-const ImmutableComponent = require('../immutableComponent')
+const ReduxComponent = require('../reduxComponent')
const Tab = require('./tab')
// Actions
@@ -23,7 +23,7 @@ const dnd = require('../../../../js/dnd')
const dndData = require('../../../../js/dndData')
const {isIntermediateAboutPage} = require('../../../../js/lib/appUrlUtil')
-class PinnedTabs extends ImmutableComponent {
+class PinnedTabs extends React.Component {
constructor () {
super()
this.onDragOver = this.onDragOver.bind(this)
@@ -42,7 +42,7 @@ class PinnedTabs extends ImmutableComponent {
// will cause the onDragEnd to never run
setTimeout(() => {
const key = sourceDragData.get('key')
- let droppedOnTab = dnd.closestFromXOffset(this.tabRefs.filter((node) => node && node.props.frame.get('key') !== key), clientX).selectedRef
+ let droppedOnTab = dnd.closestFromXOffset(this.tabRefs.filter((node) => node && node.props.frameKey !== key), clientX).selectedRef
if (droppedOnTab) {
const isLeftSide = dnd.isLeftSide(ReactDOM.findDOMNode(droppedOnTab), clientX)
windowActions.moveTab(key, droppedOnTab.props.frame.get('key'), isLeftSide)
@@ -64,26 +64,37 @@ class PinnedTabs extends ImmutableComponent {
e.preventDefault()
}
+ mergeProps (state, dispatchProps, ownProps) {
+ const currentWindow = state.get('currentWindow')
+ const tabs = currentWindow.get('tabs')
+
+ const props = {}
+ // used in renderer
+ props.pinnedTabs = tabs
+ .filter((tab) => tab.get('pinnedLocation'))
+ .map((tab) => tab.get('frameKey'))
+
+ return Object.assign({}, ownProps, props)
+ }
+
render () {
this.tabRefs = []
- return
{
this.props.pinnedTabs
- .map((frame) =>
- this.tabRefs.push(node)}
- dragData={this.props.dragData}
- frame={frame}
- key={'tab-' + frame.get('key')}
- paintTabs={this.props.paintTabs}
- previewTabs={this.props.previewTabs}
- isActive={this.props.activeFrameKey === frame.get('key')}
- notificationBarActive={this.props.notificationBarActive}
- partOfFullPageSet={this.props.partOfFullPageSet} />)
+ .map((frameKey) =>
+ this.tabRefs.push(node)}
+ frameKey={frameKey}
+ />
+ )
}
}
}
-module.exports = PinnedTabs
+module.exports = ReduxComponent.connect(PinnedTabs)
diff --git a/app/renderer/components/tabs/tab.js b/app/renderer/components/tabs/tab.js
index 96b83beb183..6c39b14b10a 100644
--- a/app/renderer/components/tabs/tab.js
+++ b/app/renderer/components/tabs/tab.js
@@ -4,10 +4,9 @@
const React = require('react')
const {StyleSheet, css} = require('aphrodite')
-const ipc = require('electron').ipcRenderer
// Components
-const ImmutableComponent = require('../immutableComponent')
+const ReduxComponent = require('../reduxComponent')
const Favicon = require('./content/favIcon')
const AudioTabIcon = require('./content/audioTabIcon')
const NewSessionIcon = require('./content/newSessionIcon')
@@ -23,44 +22,51 @@ const windowActions = require('../../../../js/actions/windowActions')
// Store
const windowStore = require('../../../../js/stores/windowStore')
+// State
+const tabState = require('../../../common/state/tabState')
+
// Constants
const dragTypes = require('../../../../js/constants/dragTypes')
-const messages = require('../../../../js/constants/messages')
+const settings = require('../../../../js/constants/settings.js')
// Styles
const styles = require('../styles/tab')
// Utils
-const locale = require('../../../../js/l10n')
const cx = require('../../../../js/lib/classSet')
const {getTextColorForBackground} = require('../../../../js/lib/color')
const {isIntermediateAboutPage} = require('../../../../js/lib/appUrlUtil')
const contextMenus = require('../../../../js/contextMenus')
const dnd = require('../../../../js/dnd')
const throttle = require('../../../../js/lib/throttle')
+const frameStateUtil = require('../../../../js/state/frameStateUtil.js')
const {getTabBreakpoint, tabUpdateFrameRate} = require('../../lib/tabUtil')
const {isWindows} = require('../../../common/lib/platformUtil')
const {getCurrentWindowId} = require('../../currentWindow')
+const getSetting = require('../../../../js/settings').getSetting
const UrlUtil = require('../../../../js/lib/urlutil')
+const {hasBreakpoint} = require('../../lib/tabUtil')
-class Tab extends ImmutableComponent {
+class Tab extends React.Component {
constructor () {
super()
this.onMouseEnter = this.onMouseEnter.bind(this)
this.onMouseLeave = this.onMouseLeave.bind(this)
this.onUpdateTabSize = this.onUpdateTabSize.bind(this)
+ this.onDragStart = this.onDragStart.bind(this)
+ this.onDragEnd = this.onDragEnd.bind(this)
+ this.onDragOver = this.onDragOver.bind(this)
+ this.onClickTab = this.onClickTab.bind(this)
}
+
get frame () {
- return windowStore.getFrame(this.props.frame.get('key'))
- }
- get isPinned () {
- return !!this.props.frame.get('pinnedLocation')
+ return windowStore.getFrame(this.props.frameKey)
}
get draggingOverData () {
const draggingOverData = this.props.dragData && this.props.dragData.get('dragOverData')
if (!draggingOverData ||
- draggingOverData.get('draggingOverKey') !== this.props.frame.get('key') ||
+ draggingOverData.get('draggingOverKey') !== this.props.frameKey ||
draggingOverData.get('draggingOverWindowId') !== getCurrentWindowId()) {
return
}
@@ -83,7 +89,7 @@ class Tab extends ImmutableComponent {
get isDragging () {
const sourceDragData = dnd.getInterBraveDragData()
return sourceDragData &&
- sourceDragData.get('key') === this.props.frame.get('key') &&
+ sourceDragData.get('key') === this.props.frameKey &&
sourceDragData.get('draggingOverWindowId') === getCurrentWindowId()
}
@@ -110,25 +116,6 @@ class Tab extends ImmutableComponent {
return this.draggingOverData.get('draggingOverRightHalf')
}
- get displayValue () {
- // For renderer initiated navigations, make sure we show Untitled
- // until we know what we're loading. We should probably do this for
- // all about: pages that we already know the title for so we don't have
- // to wait for the title to be parsed.
- if (this.props.frame.get('location') === 'about:blank') {
- return locale.translation('aboutBlankTitle')
- } else if (this.props.frame.get('location') === 'about:newtab') {
- return locale.translation('newTab')
- }
-
- // YouTube tries to change the title to add a play icon when
- // there is audio. Since we have our own audio indicator we get
- // rid of it.
- return (this.props.frame.get('title') ||
- this.props.frame.get('location') ||
- '').replace('▶ ', '')
- }
-
onDragStart (e) {
dnd.onDragStart(dragTypes.TAB, this.frame, e)
}
@@ -138,29 +125,12 @@ class Tab extends ImmutableComponent {
}
onDragOver (e) {
- dnd.onDragOver(dragTypes.TAB, this.tabNode.getBoundingClientRect(), this.props.frame.get('key'), this.draggingOverData, e)
- }
-
- onTabClosedWithMouse (event) {
- event.stopPropagation()
- if (this.props.onTabClosedWithMouse && this.frame && !this.frame.isEmpty()) {
- this.props.onTabClosedWithMouse(this.tabNode.parentNode.getBoundingClientRect())
- appActions.tabCloseRequested(this.frame.get('tabId'))
- }
+ dnd.onDragOver(dragTypes.TAB, this.tabNode.getBoundingClientRect(), this.props.frameKey, this.draggingOverData, e)
}
- onMuteFrame (muted, event) {
+ setActiveFrame (event) {
event.stopPropagation()
- const frame = this.frame
- windowActions.setAudioMuted(frame.get('key'), frame.get('tabId'), muted)
- }
-
- get loading () {
- return this.frame &&
- (this.props.frame.get('loading') ||
- this.props.frame.get('location') === 'about:blank') &&
- (!this.props.frame.get('provisionalLocation') ||
- !this.props.frame.get('provisionalLocation').startsWith('chrome-extension://mnojpmjdmbbfmejpflffifhffcmidifd/'))
+ windowActions.setActiveFrame(this.frame)
}
onMouseLeave () {
@@ -190,6 +160,17 @@ class Tab extends ImmutableComponent {
this.onClickTab(e)
}
+ onTabClosedWithMouse (event) {
+ event.stopPropagation()
+ if (this.frame && !this.frame.isEmpty()) {
+ const rect = this.tabNode.parentNode.getBoundingClientRect()
+ windowActions.onTabClosedWithMouse({
+ fixTabWidth: rect.width
+ })
+ windowActions.closeFrame(this.frame)
+ }
+ }
+
onClickTab (e) {
if (e.button === 1) {
this.onTabClosedWithMouse(e)
@@ -199,34 +180,10 @@ class Tab extends ImmutableComponent {
}
}
- get themeColor () {
- return this.props.paintTabs &&
- (this.props.frame.get('themeColor') || this.props.frame.get('computedThemeColor'))
- }
-
get tabSize () {
const tab = this.tabNode
// Avoid TypeError keeping it null until component is mounted
- return tab && !this.isPinned ? tab.getBoundingClientRect().width : null
- }
-
- get mediumView () {
- const sizes = ['large', 'largeMedium']
- return sizes.includes(this.props.frame.get('breakpoint'))
- }
-
- get narrowView () {
- const sizes = ['medium', 'mediumSmall', 'small', 'extraSmall', 'smallest']
- return sizes.includes(this.props.frame.get('breakpoint'))
- }
-
- get narrowestView () {
- const sizes = ['extraSmall', 'smallest']
- return sizes.includes(this.props.frame.get('breakpoint'))
- }
-
- get canPlayAudio () {
- return this.props.frame.get('audioPlaybackActive') || this.props.frame.get('audioMuted')
+ return tab && !this.props.isPinnedTab ? tab.getBoundingClientRect().width : null
}
onUpdateTabSize () {
@@ -263,18 +220,64 @@ class Tab extends ImmutableComponent {
}
}
+ mergeProps (state, dispatchProps, ownProps) {
+ const currentWindow = state.get('currentWindow')
+ const tab = tabState.getTabWindowProps(currentWindow, ownProps.frameKey)
+ const notifications = state.get('notifications')
+ const notificationOrigins = notifications ? notifications.map(bar => bar.get('frameOrigin')) : false
+ const notificationBarActive = tab.get('location') && notificationOrigins &&
+ notificationOrigins.includes(UrlUtil.getUrlOrigin(tab.get('location')))
+ const hasSeconardImage = tabState.hasVisibleSecondaryIcon(currentWindow, ownProps.frameKey)
+ const breakpoint = tab.get('breakpoint')
+ const partition = typeof tab.get('partitionNumber') === 'string'
+ ? tab.get('partitionNumber').replace(/^partition-/i, '')
+ : tab.get('partitionNumber')
+
+ const props = {}
+ // used in renderer
+ props.isPrivateTab = tab.get('isPrivate')
+ props.breakpoint = tab.get('breakpoint')
+ props.notificationBarActive = notificationBarActive
+ props.isActive = frameStateUtil.isFrameKeyActive(currentWindow, ownProps.frameKey)
+ props.paintTabs = getSetting(settings.PAINT_TABS)
+ props.tabWidth = currentWindow.getIn(['ui', 'tabs', 'fixTabWidth'])
+ props.isPinnedTab = tabState.isPinned(currentWindow, ownProps.frameKey)
+ props.canPlayAudio = tabState.canPlayAudio(currentWindow, ownProps.frameKey)
+ props.themeColor = tabState.getThemeColor(currentWindow, ownProps.frameKey)
+ props.isTabLoading = tabState.isTabLoading(currentWindow, ownProps.frameKey)
+ props.isNarrowView = tabState.isNarrowView(currentWindow, ownProps.frameKey)
+ props.isNarrowestView = tabState.isNarrowestView(currentWindow, ownProps.frameKey)
+ props.isPlayIndicatorBreakpoint = tabState.isMediumView(currentWindow, ownProps.frameKey) || props.isNarrowView
+ props.title = tab.get('title')
+ props.displayTitle = tabState.getDisplayTitle(currentWindow, ownProps.frameKey)
+ props.showSessionIcon = partition && hasSeconardImage
+ props.showPrivateIcon = props.isPrivateTab && hasSeconardImage
+ props.showFavIcon = !((hasBreakpoint(breakpoint, 'extraSmall') && props.isActive) || tab.get('location') === 'about:newtab')
+ props.showAudioIcon = breakpoint === 'default' && !!tab.get('audioPlaybackActive')
+ props.showTitle = !props.isPinnedTab &&
+ !(
+ (hasBreakpoint(breakpoint, 'small') && props.isActive) ||
+ hasBreakpoint(breakpoint, ['extraSmall', 'smallest'])
+ )
+
+ // used in other functions
+ props.totalTabs = state.get('tabs').size
+ props.previewTabs = getSetting(settings.SHOW_TAB_PREVIEWS)
+ props.dragData = state.getIn(['dragData', 'type']) === dragTypes.TAB && state.get('dragData')
+ props.hasTabInFullScreen = frameStateUtil.hasTabInFullScreen(currentWindow)
+
+ return Object.assign({}, ownProps, props)
+ }
+
render () {
- const notificationBarActive = !!this.props.notificationBarActive &&
- this.props.notificationBarActive.includes(UrlUtil.getUrlOrigin(this.props.frame.get('location')))
- const playIndicatorBreakpoint = this.mediumView || this.narrowView
// we don't want themeColor if tab is private
- const perPageStyles = !this.props.frame.get('isPrivate') && StyleSheet.create({
+ const perPageStyles = !this.props.isPrivateTab && StyleSheet.create({
themeColor: {
- color: this.themeColor ? getTextColorForBackground(this.themeColor) : 'inherit',
- background: this.themeColor ? this.themeColor : 'inherit',
+ color: this.props.themeColor ? getTextColorForBackground(this.props.themeColor) : 'inherit',
+ background: this.props.themeColor ? this.props.themeColor : 'inherit',
':hover': {
- color: this.themeColor ? getTextColorForBackground(this.themeColor) : 'inherit',
- background: this.themeColor ? this.themeColor : 'inherit'
+ color: this.props.themeColor ? getTextColorForBackground(this.props.themeColor) : 'inherit',
+ background: this.props.themeColor ? this.props.themeColor : 'inherit'
}
}
})
@@ -284,108 +287,82 @@ class Tab extends ImmutableComponent {
draggingOverLeft: this.isDraggingOverLeft && !this.isDraggingOverSelf,
draggingOverRight: this.isDraggingOverRight && !this.isDraggingOverSelf,
isDragging: this.isDragging,
- isPinned: this.isPinned,
+ isPinned: this.props.isPinnedTab,
partOfFullPageSet: this.props.partOfFullPageSet || !!this.props.tabWidth
})}
style={this.props.tabWidth ? { flex: `0 0 ${this.props.tabWidth}px` } : {}}
onMouseEnter={this.onMouseEnter}
onMouseLeave={this.onMouseLeave}>
{
- this.props.isActive && notificationBarActive
+ this.props.isActive && this.props.notificationBarActive
?
: null
}
- { this.tabNode = node }}
+ className={css(
+ styles.tab,
+ // Windows specific style
+ isWindows() && styles.tabForWindows,
+ this.props.isPinnedTab && styles.isPinned,
+ this.props.isActive && styles.active,
+ this.props.isPlayIndicatorBreakpoint && this.props.canPlayAudio && styles.narrowViewPlayIndicator,
+ this.props.isActive && this.props.themeColor && perPageStyles.themeColor,
+ // Private color should override themeColor
+ this.props.isPrivateTab && styles.private,
+ this.props.isActive && this.props.isPrivateTab && styles.activePrivateTab,
+ !this.props.isPinnedTab && this.props.isNarrowView && styles.tabNarrowView,
+ !this.props.isPinnedTab && this.props.isNarrowestView && styles.tabNarrowestView,
+ !this.props.isPinnedTab && this.props.breakpoint === 'smallest' && styles.tabMinAllowedSize
)}
- data-test-active-tab={this.props.isActive}
- data-test-pinned-tab={this.isPinned}
- data-test-private-tab={this.props.frame.get('isPrivate')}
data-test-id='tab'
- data-frame-key={this.props.frame.get('key')}
- ref={(node) => { this.tabNode = node }}
+ data-test-active-tab={this.props.isActive}
+ data-test-pinned-tab={this.props.isPinnedTab}
+ data-test-private-tab={this.props.isPrivateTab}
+ data-frame-key={this.props.frameKey}
draggable
- title={this.props.frame.get('title')}
- onDragStart={this.onDragStart.bind(this)}
- onDragEnd={this.onDragEnd.bind(this)}
- onDragOver={this.onDragOver.bind(this)}
- onClick={this.onClickTab.bind(this)}
- onContextMenu={contextMenus.onTabContextMenu.bind(this, this.frame)}>
+ title={this.props.title}
+ onDragStart={this.onDragStart}
+ onDragEnd={this.onDragEnd}
+ onDragOver={this.onDragOver}
+ onClick={this.onClickTab}
+ onContextMenu={contextMenus.onTabContextMenu.bind(this, this.frame)}
+ >
-
-
-
+ {
+ this.props.showFavIcon
+ ?
+ : null
+ }
+ {
+ this.props.showAudioIcon
+ ?
+ : null
+ }
+ {
+ this.props.showTitle
+ ?
+ : null
+ }
-
-
-
+ {
+ this.props.showPrivateIcon
+ ?
+ : null
+ }
+ {
+ this.props.showSessionIcon
+ ?
+ : null
+ }
+
}
}
-const paymentsEnabled = () => {
- const getSetting = require('../../../../js/settings').getSetting
- const settings = require('../../../../js/constants/settings')
- return getSetting(settings.PAYMENTS_ENABLED)
-}
-
-windowStore.addChangeListener(() => {
- if (paymentsEnabled()) {
- const windowState = windowStore.getState()
- const frames = windowState && windowState.get('frames')
- if (frames) {
- try {
- const presentP = frames.some((frame) => {
- return frame.get('location') === 'about:preferences#payments'
- })
- ipc.send(messages.LEDGER_PAYMENTS_PRESENT, presentP)
- } catch (ex) { }
- }
- }
-})
-module.exports = Tab
+module.exports = ReduxComponent.connect(Tab)
diff --git a/app/renderer/components/tabs/tabs.js b/app/renderer/components/tabs/tabs.js
index cff471fe51c..c4f8361b5e2 100644
--- a/app/renderer/components/tabs/tabs.js
+++ b/app/renderer/components/tabs/tabs.js
@@ -6,7 +6,7 @@ const React = require('react')
const ReactDOM = require('react-dom')
// Components
-const ImmutableComponent = require('../immutableComponent')
+const ReduxComponent = require('../reduxComponent')
const LongPressButton = require('../common/longPressButton')
const Tab = require('./tab')
@@ -14,8 +14,15 @@ const Tab = require('./tab')
const appActions = require('../../../../js/actions/appActions')
const windowActions = require('../../../../js/actions/windowActions')
+// Store
+const windowStore = require('../../../../js/stores/windowStore')
+
+// State
+const tabState = require('../../../common/state/tabState.js')
+
// Constants
const dragTypes = require('../../../../js/constants/dragTypes')
+const settings = require('../../../../js/constants/settings.js')
// Utils
const cx = require('../../../../js/lib/classSet')
@@ -23,8 +30,9 @@ const contextMenus = require('../../../../js/contextMenus')
const {getCurrentWindowId} = require('../../currentWindow')
const dnd = require('../../../../js/dnd')
const dndData = require('../../../../js/dndData')
+const getSetting = require('../../../../js/settings').getSetting
-class Tabs extends ImmutableComponent {
+class Tabs extends React.Component {
constructor () {
super()
this.onDragOver = this.onDragOver.bind(this)
@@ -32,9 +40,7 @@ class Tabs extends ImmutableComponent {
this.onPrevPage = this.onPrevPage.bind(this)
this.onNextPage = this.onNextPage.bind(this)
this.onNewTabLongPress = this.onNewTabLongPress.bind(this)
- this.wasNewTabClicked = this.wasNewTabClicked.bind(this)
this.onMouseLeave = this.onMouseLeave.bind(this)
- this.onTabClosedWithMouse = this.onTabClosedWithMouse.bind(this)
}
onMouseLeave () {
@@ -43,12 +49,6 @@ class Tabs extends ImmutableComponent {
})
}
- onTabClosedWithMouse (rect) {
- windowActions.onTabClosedWithMouse({
- fixTabWidth: rect.width
- })
- }
-
onPrevPage () {
if (this.props.tabPageIndex === 0) {
return
@@ -57,16 +57,12 @@ class Tabs extends ImmutableComponent {
}
onNextPage () {
- if (this.props.tabPageIndex + 1 === this.totalPages) {
+ if (this.props.tabPageIndex + 1 === this.props.totalPages) {
return
}
windowActions.setTabPageIndex(this.props.tabPageIndex + 1)
}
- get totalPages () {
- return Math.ceil(this.props.tabs.size / this.props.tabsPerTabPage)
- }
-
onDrop (e) {
appActions.dataDropped(getCurrentWindowId())
const clientX = e.clientX
@@ -82,11 +78,12 @@ class Tabs extends ImmutableComponent {
// will cause the onDragEnd to never run
setTimeout(() => {
const key = sourceDragData.get('key')
- let droppedOnTab = dnd.closestFromXOffset(this.tabRefs.filter((node) => node && node.props.frame.get('key') !== key), clientX).selectedRef
+ let droppedOnTab = dnd.closestFromXOffset(this.tabRefs.filter((node) => node && node.props.frameKey !== key), clientX).selectedRef
if (droppedOnTab) {
const isLeftSide = dnd.isLeftSide(ReactDOM.findDOMNode(droppedOnTab), clientX)
+ const droppedOnFrameProps = windowStore.getFrame(droppedOnTab.props.frameKey)
- windowActions.moveTab(key, droppedOnTab.props.frame.get('key'), isLeftSide)
+ windowActions.moveTab(droppedOnTab.props.frame.get('key'), droppedOnFrameProps, isLeftSide)
if (sourceDragData.get('pinnedLocation')) {
appActions.tabPinned(sourceDragData.get('tabId'), false)
}
@@ -115,19 +112,44 @@ class Tabs extends ImmutableComponent {
e.preventDefault()
}
}
- wasNewTabClicked (target) {
- return target.className === this.refs.newTabButton.props.className
- }
+
newTab () {
appActions.createTabRequested({})
}
+
onNewTabLongPress (target) {
contextMenus.onNewTabContextMenu(target)
}
+
+ mergeProps (state, dispatchProps, ownProps) {
+ const currentWindow = state.get('currentWindow')
+ const pageIndex = tabState.getPageIndex(currentWindow)
+ const tabsPerTabPage = Number(getSetting(settings.TABS_PER_PAGE))
+ const startingFrameIndex = pageIndex * tabsPerTabPage
+ const unpinnedTabs = currentWindow.get('tabs').filter((tab) => !tab.get('pinnedLocation'))
+ const currentTabs = unpinnedTabs
+ .slice(startingFrameIndex, startingFrameIndex + tabsPerTabPage)
+ .map((tab) => tab.get('frameKey'))
+ const totalPages = Math.ceil(unpinnedTabs.size / tabsPerTabPage)
+
+ const props = {}
+ // used in renderer
+ props.fixTabWidth = currentWindow.getIn(['ui', 'tabs', 'fixTabWidth'])
+ props.previewTabPageIndex = currentWindow.getIn(['ui', 'tabs', 'previewTabPageIndex'])
+ props.pageIndex = tabState.getPageIndex(currentWindow)
+ props.currentTabs = currentTabs
+ props.partOfFullPageSet = currentTabs.size === tabsPerTabPage
+ props.onNextPage = currentTabs.size >= tabsPerTabPage && totalPages > pageIndex + 1
+
+ // used in other functions
+ props.tabPageIndex = currentWindow.getIn(['ui', 'tabs', 'tabPageIndex'])
+ props.totalPages = totalPages
+
+ return Object.assign({}, ownProps, props)
+ }
+
render () {
this.tabRefs = []
- const index = this.props.previewTabPageIndex !== undefined
- ? this.props.previewTabPageIndex : this.props.tabPageIndex
return
- {(() => {
- if (index > 0) {
- return 0
+ ?
- }
- })()}
+ : null
+ }
{
this.props.currentTabs
- .map((frame) =>
- this.tabRefs.push(node)}
- dragData={this.props.dragData}
- frame={frame}
- key={'tab-' + frame.get('key')}
- paintTabs={this.props.paintTabs}
- previewTabs={this.props.previewTabs}
- isActive={this.props.activeFrameKey === frame.get('key')}
- onTabClosedWithMouse={this.onTabClosedWithMouse}
- tabWidth={this.props.fixTabWidth}
- hasTabInFullScreen={this.props.hasTabInFullScreen}
- notificationBarActive={this.props.notificationBarActive}
- totalTabs={this.props.tabs.size}
- partOfFullPageSet={this.props.partOfFullPageSet} />)
+ .map((frameKey) =>
+ this.tabRefs.push(node)}
+ frameKey={frameKey}
+ partOfFullPageSet={this.props.partOfFullPageSet} />
+ )
}
- {(() => {
- if (this.props.currentTabs.size >= this.props.tabsPerTabPage && this.totalPages > index + 1) {
- return
- }
- })()}
-
+ : null
+ }
tab.get('pinnedLocation'))
+
+ const props = {}
+ // used in renderer
+ props.hasPinnedTabs = pinnedTabs.size > 0
+
+ // used in other functions
+ props.activeFrame = activeFrame
+ props.activeFrameLocation = (activeFrame && activeFrame.get('location')) || ''
+
+ return Object.assign({}, ownProps, props)
}
render () {
- const index = this.props.previewTabPageIndex !== undefined
- ? this.props.previewTabPageIndex : this.props.tabPageIndex
- const startingFrameIndex = index * this.props.tabsPerTabPage
- const pinnedTabs = this.props.frames.filter((tab) => tab.get('pinnedLocation'))
- const unpinnedTabs = this.props.frames.filter((tab) => !tab.get('pinnedLocation'))
- const currentTabs = unpinnedTabs
- .slice(startingFrameIndex, startingFrameIndex + this.props.tabsPerTabPage)
- return
{
- pinnedTabs.size > 0
- ?
+ this.props.hasPinnedTabs
+ ?
: null
}
}
}
-module.exports = TabsToolbar
+module.exports = ReduxComponent.connect(TabsToolbar)
diff --git a/app/renderer/lib/tabUtil.js b/app/renderer/lib/tabUtil.js
index b32191c1508..4f3c07256b0 100644
--- a/app/renderer/lib/tabUtil.js
+++ b/app/renderer/lib/tabUtil.js
@@ -5,7 +5,7 @@
const styles = require('../components/styles/global')
const frameStateUtil = require('../../../js/state/frameStateUtil')
const settings = require('../../../js/constants/settings')
-const getSetting = require('../../../js/settings').getSetting
+const {getSetting} = require('../../../js/settings')
const {getTextColorForBackground} = require('../../../js/lib/color')
/**
@@ -36,9 +36,9 @@ module.exports.tabUpdateFrameRate = 66
* @param {Array} arr - Array of Strings including breakpoint names to check against
* @returns {Boolean} Whether or not the sizing criteria was match
*/
-module.exports.hasBreakpoint = (props, arr) => {
+module.exports.hasBreakpoint = (breakpoint, arr) => {
arr = Array.isArray(arr) ? arr : [arr]
- return arr.includes(props.frame.get('breakpoint'))
+ return arr.includes(breakpoint)
}
/**
diff --git a/js/state/frameStateUtil.js b/js/state/frameStateUtil.js
index 4da67820670..05854974f52 100644
--- a/js/state/frameStateUtil.js
+++ b/js/state/frameStateUtil.js
@@ -498,6 +498,12 @@ function getTotalBlocks (frame) {
: ((blocked > 99) ? '99+' : blocked)
}
+function hasTabInFullScreen (windowState) {
+ return windowState.get('frames')
+ .map((frame) => frame.get('isFullScreen'))
+ .some(fullScreenMode => fullScreenMode === true)
+}
+
const frameStatePath = (state, frameKey) =>
['frames', getFrameIndex(state, frameKey)]
@@ -602,5 +608,6 @@ module.exports = {
getLastCommittedURL,
getFrameByLastAccessedTime,
onFindBarHide,
- getTotalBlocks
+ getTotalBlocks,
+ hasTabInFullScreen
}