From 1ecede5d670454edfc8a41d02e38c54dbc6d276d Mon Sep 17 00:00:00 2001 From: NejcZdovc Date: Wed, 19 Apr 2017 17:32:58 +0200 Subject: [PATCH] Converts Tabs related components into redux Resolves #8690 Fixes tab overrendering --- app/common/state/tabState.js | 150 +++++++++ .../components/tabs/content/audioTabIcon.js | 61 ++-- .../components/tabs/content/closeTabIcon.js | 62 +++- .../components/tabs/content/favIcon.js | 70 ++-- .../components/tabs/content/newSessionIcon.js | 61 ++-- .../components/tabs/content/privateIcon.js | 27 +- .../components/tabs/content/tabTitle.js | 55 ++- app/renderer/components/tabs/pinnedTabs.js | 42 ++- app/renderer/components/tabs/tab.js | 312 ++++++++---------- app/renderer/components/tabs/tabs.js | 107 +++--- app/renderer/components/tabs/tabsToolbar.js | 76 ++--- app/renderer/lib/tabUtil.js | 62 +--- js/components/main.js | 43 +-- js/state/frameStateUtil.js | 9 +- 14 files changed, 639 insertions(+), 498 deletions(-) diff --git a/app/common/state/tabState.js b/app/common/state/tabState.js index 52d0683b333..889675fb222 100644 --- a/app/common/state/tabState.js +++ b/app/common/state/tabState.js @@ -8,6 +8,12 @@ const frameState = require('./frameState') const windowState = require('./windowState') // this file should eventually replace frameStateUtil const frameStateUtil = require('../../../js/state/frameStateUtil') +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`) @@ -363,6 +369,150 @@ const tabState = { state = tabState.removeTabField(state, 'messageBoxDetail') state = tabState.removeTabField(state, 'frame') 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')) + }, + + isPinned (windowState, frameKey) { + const tab = tabState.getTabWindowProps(windowState, frameKey) + return tab && !!tab.get('pinnedLocation') + }, + + 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/tabs/content/audioTabIcon.js b/app/renderer/components/tabs/content/audioTabIcon.js index 644562adb6e..47d1aa6237c 100644 --- a/app/renderer/components/tabs/content/audioTabIcon.js +++ b/app/renderer/components/tabs/content/audioTabIcon.js @@ -6,43 +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.tab.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.tab.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.tab.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 5875492a977..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.tab.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 f996c372a84..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.tab.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.tab.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.tab.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 90142337dfb..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.tab.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 94e390f3123..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.tab.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 4af91b649bb..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.tab.get('isPrivate') || !!this.props.tab.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.tab.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 13a2a0cfd6b..5650a94b16e 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 @@ -26,7 +26,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) @@ -45,10 +45,10 @@ 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.tab.get('frameKey') !== 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.tab.get('frameKey')) + const droppedOnFrameProps = windowStore.getFrame(droppedOnTab.props.frameKey) windowActions.moveTab(sourceDragData, droppedOnFrameProps, isLeftSide) if (!sourceDragData.get('pinnedLocation')) { appActions.tabPinned(sourceDragData.get('tabId'), true) @@ -66,25 +66,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((tab) => - this.tabRefs.push(node)} - dragData={this.props.dragData} - tab={tab} - key={'tab-' + tab.get('frameKey')} - paintTabs={this.props.paintTabs} - previewTabs={this.props.previewTabs} - isActive={this.props.activeFrameKey === tab.get('frameKey')} - 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 27494ccac99..22be8f615b0 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') @@ -22,44 +21,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.tab.get('frameKey')) - } - get isPinned () { - return !!this.props.tab.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.tab.get('frameKey') || + draggingOverData.get('draggingOverKey') !== this.props.frameKey || draggingOverData.get('draggingOverWindowId') !== getCurrentWindowId()) { return } @@ -82,7 +88,7 @@ class Tab extends ImmutableComponent { get isDragging () { const sourceDragData = dnd.getInterBraveDragData() return sourceDragData && - sourceDragData.get('key') === this.props.tab.get('frameKey') && + sourceDragData.get('key') === this.props.frameKey && sourceDragData.get('draggingOverWindowId') === getCurrentWindowId() } @@ -109,25 +115,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.tab.get('location') === 'about:blank') { - return locale.translation('aboutBlankTitle') - } else if (this.props.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 (this.props.tab.get('title') || - this.props.tab.get('location') || - '').replace('▶ ', '') - } - onDragStart (e) { dnd.onDragStart(dragTypes.TAB, this.frame, e) } @@ -137,7 +124,7 @@ class Tab extends ImmutableComponent { } onDragOver (e) { - dnd.onDragOver(dragTypes.TAB, this.tabNode.getBoundingClientRect(), this.props.tab.get('frameKey'), this.draggingOverData, e) + dnd.onDragOver(dragTypes.TAB, this.tabNode.getBoundingClientRect(), this.props.frameKey, this.draggingOverData, e) } setActiveFrame (event) { @@ -145,28 +132,6 @@ class Tab extends ImmutableComponent { windowActions.setActiveFrame(this.frame) } - onTabClosedWithMouse (event) { - event.stopPropagation() - if (this.props.onTabClosedWithMouse && this.frame && !this.frame.isEmpty()) { - this.props.onTabClosedWithMouse(this.tabNode.parentNode.getBoundingClientRect()) - windowActions.closeFrame(this.frame) - } - } - - onMuteFrame (muted, event) { - event.stopPropagation() - const frame = this.frame - windowActions.setAudioMuted(frame.get('key'), frame.get('tabId'), muted) - } - - get loading () { - return this.frame && - (this.props.tab.get('loading') || - this.props.tab.get('location') === 'about:blank') && - (!this.props.tab.get('provisionalLocation') || - !this.props.tab.get('provisionalLocation').startsWith('chrome-extension://mnojpmjdmbbfmejpflffifhffcmidifd/')) - } - onMouseLeave () { if (this.props.previewTabs) { window.clearTimeout(this.hoverTimeout) @@ -194,6 +159,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) @@ -202,34 +178,10 @@ class Tab extends ImmutableComponent { } } - get themeColor () { - return this.props.paintTabs && - (this.props.tab.get('themeColor') || this.props.tab.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.tab.get('breakpoint')) - } - - get narrowView () { - const sizes = ['medium', 'mediumSmall', 'small', 'extraSmall', 'smallest'] - return sizes.includes(this.props.tab.get('breakpoint')) - } - - get narrowestView () { - const sizes = ['extraSmall', 'smallest'] - return sizes.includes(this.props.tab.get('breakpoint')) - } - - get canPlayAudio () { - return this.props.tab.get('audioPlaybackActive') || this.props.tab.get('audioMuted') + return tab && !this.props.isPinnedTab ? tab.getBoundingClientRect().width : null } onUpdateTabSize () { @@ -264,18 +216,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.tab.get('location'))) - const playIndicatorBreakpoint = this.mediumView || this.narrowView // we don't want themeColor if tab is private - const perPageStyles = !this.props.tab.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' } } }) @@ -285,108 +283,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.tab.get('isPrivate')} data-test-id='tab' - data-frame-key={this.props.tab.get('frameKey')} - 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.tab.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 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) { } - } - } -}) -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 9b9db2532a9..4f19c2d06e4 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('../../../../js/components/longPressButton') const Tab = require('./tab') @@ -17,8 +17,12 @@ 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') @@ -26,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) @@ -35,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 () { @@ -46,12 +49,6 @@ class Tabs extends ImmutableComponent { }) } - onTabClosedWithMouse (rect) { - windowActions.onTabClosedWithMouse({ - fixTabWidth: rect.width - }) - } - onPrevPage () { if (this.props.tabPageIndex === 0) { return @@ -60,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 @@ -79,10 +72,10 @@ 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.tab.get('frameKey') !== 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.tab.get('frameKey')) + const droppedOnFrameProps = windowStore.getFrame(droppedOnTab.props.frameKey) // If this is a different window ID than where the drag started, then // the tear off will be done by tab.js @@ -118,19 +111,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
@@ -141,40 +159,31 @@ class Tabs extends ImmutableComponent { })} onDragOver={this.onDragOver} onDrop={this.onDrop}> - {(() => { - if (index > 0) { - return 0 + ? - } - })()} + : null + } { this.props.currentTabs - .map((tab) => - this.tabRefs.push(node)} - dragData={this.props.dragData} - tab={tab} - key={'tab-' + tab.get('frameKey')} - paintTabs={this.props.paintTabs} - previewTabs={this.props.previewTabs} - isActive={this.props.activeFrameKey === tab.get('frameKey')} - 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.tabs.filter((tab) => tab.get('pinnedLocation')) - const unpinnedTabs = this.props.tabs.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 e8198301e47..648711fc2a9 100644 --- a/app/renderer/lib/tabUtil.js +++ b/app/renderer/lib/tabUtil.js @@ -6,7 +6,6 @@ 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 {getTextColorForBackground} = require('../../../js/lib/color') /** * Get tab's breakpoint name for current tab size. @@ -36,66 +35,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.tab.get('breakpoint')) -} - -/** - * Check whether or not closeTab icon is relative to hover state - * @param {Object} props - Object that hosts the tab props - * @returns {Boolean} Whether or not the tab has a relative closeTab icon - */ -module.exports.hasRelativeCloseIcon = (props) => { - return props.tab.get('hoverState') && - module.exports.hasBreakpoint(props, ['default', 'large']) -} - -/** - * Check whether or not private or newSession icon should be visible - * @param {Object} props - Object that hosts the tab props - * @returns {Boolean} Whether or not private or newSession icon should be visible - */ -module.exports.hasVisibleSecondaryIcon = (props) => { - return ( - // Hide icon on hover - !module.exports.hasRelativeCloseIcon(props) && - // If closeIcon is fixed then there's no room for another icon - !module.exports.hasFixedCloseIcon(props) && - // completely hide it for small sizes - !module.exports.hasBreakpoint(props, ['mediumSmall', 'small', 'extraSmall', 'smallest']) - ) -} - -/** - * Check whether or not closeTab icon is always visible (fixed) in tab - * @param {Object} props - Object that hosts the tab props - * @returns {Boolean} Whether or not the close icon is always visible (fixed) - */ -module.exports.hasFixedCloseIcon = (props) => { - return ( - props.isActive && - // larger sizes still have a relative closeIcon - !module.exports.hasBreakpoint(props, ['default', 'large']) && - // We don't resize closeIcon as we do with favicon so don't show it - !module.exports.hasBreakpoint(props, 'smallest') - ) -} - -/** - * Gets the icon color based on tab's background - * @param {Object} props - Object that hosts the tab props - * @returns {String} Contrasting color to use based on tab's color - */ -module.exports.getTabIconColor = (props) => { - const themeColor = props.tab.get('themeColor') || props.tab.get('computedThemeColor') - const activeNonPrivateTab = !props.tab.get('isPrivate') && props.isActive - const isPrivateTab = props.tab.get('isPrivate') && (props.isActive || props.tab.get('hoverState')) - const defaultColor = isPrivateTab ? styles.color.white100 : styles.color.black100 - - return activeNonPrivateTab && props.paintTabs && !!themeColor - ? getTextColorForBackground(themeColor) - : defaultColor + return arr.includes(breakpoint) } /** diff --git a/js/components/main.js b/js/components/main.js index d06859e130c..a5605259ee2 100644 --- a/js/components/main.js +++ b/js/components/main.js @@ -59,6 +59,7 @@ const defaultBrowserState = require('../../app/common/state/defaultBrowserState' const shieldState = require('../../app/common/state/shieldState') const tabState = require('../../app/common/state/tabState') const siteSettingsState = require('../../app/common/state/siteSettingsState') +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) @@ -512,6 +512,22 @@ class Main extends ImmutableComponent { window.onblur = () => { self.resetAltMenuProcessing() } + + 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 () { @@ -536,11 +552,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) } @@ -722,7 +733,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/js/state/frameStateUtil.js b/js/state/frameStateUtil.js index 78d67e8045a..282b67b6936 100644 --- a/js/state/frameStateUtil.js +++ b/js/state/frameStateUtil.js @@ -707,6 +707,12 @@ function onFindBarHide (frameKey) { })) } +function hasTabInFullScreen (windowState) { + return windowState.get('frames') + .map((frame) => frame.get('isFullScreen')) + .some(fullScreenMode => fullScreenMode === true) +} + const frameStatePath = (windowState, key) => ['frames', findIndexForFrameKey(windowState.get('frames'), key)] @@ -782,5 +788,6 @@ module.exports = { tabStatePathForFrame, getLastCommittedURL, getFrameByLastAccessedTime, - onFindBarHide + onFindBarHide, + hasTabInFullScreen }