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 }