2020-02-24 21:56:07 +00:00
'use strict'
2020-08-17 21:07:16 +01:00
import React from 'react'
2020-08-17 21:59:29 +01:00
import PropTypes from 'prop-types'
2020-08-17 21:39:25 +01:00
import { connect } from 'react-redux'
2020-02-24 21:56:07 +00:00
import { HotKeys } from 'react-hotkeys'
import { defineMessages , injectIntl } from 'react-intl'
import { Switch , Redirect , withRouter } from 'react-router-dom'
2020-04-11 23:29:19 +01:00
import debounce from 'lodash.debounce'
2020-05-21 23:03:35 +01:00
import queryString from 'query-string'
2020-07-14 07:05:05 +01:00
import moment from 'moment-mini'
2020-02-24 21:56:07 +00:00
import { uploadCompose , resetCompose } from '../../actions/compose'
import { expandHomeTimeline } from '../../actions/timelines'
2020-04-28 06:33:58 +01:00
import { fetchGroups } from '../../actions/groups'
2020-01-28 16:29:37 +00:00
import {
initializeNotifications ,
expandNotifications ,
2020-05-21 23:03:35 +01:00
setFilter ,
2020-02-24 21:56:07 +00:00
} from '../../actions/notifications'
2020-04-11 23:29:19 +01:00
import LoadingBar from '../../components/loading_bar'
2020-02-24 21:56:07 +00:00
import { fetchFilters } from '../../actions/filters'
import { clearHeight } from '../../actions/height_cache'
import { openModal } from '../../actions/modal'
import WrappedRoute from './util/wrapped_route'
2020-02-28 15:20:47 +00:00
import ModalRoot from '../../components/modal/modal_root'
import PopoverRoot from '../../components/popover/popover_root'
2020-02-24 21:56:07 +00:00
import UploadArea from '../../components/upload_area'
2020-02-17 17:50:29 +00:00
import ProfilePage from '../../pages/profile_page'
2020-03-25 03:08:43 +00:00
import CommunityPage from '../../pages/community_page'
import HashtagPage from '../../pages/hashtag_page'
import ShortcutsPage from '../../pages/shortcuts_page'
2020-02-29 15:42:47 +00:00
import GroupPage from '../../pages/group_page'
2020-02-22 23:26:23 +00:00
import GroupsPage from '../../pages/groups_page'
import SearchPage from '../../pages/search_page'
import ErrorPage from '../../pages/error_page'
2020-02-17 17:50:29 +00:00
import HomePage from '../../pages/home_page'
import NotificationsPage from '../../pages/notifications_page'
2020-02-19 23:57:07 +00:00
import ListPage from '../../pages/list_page'
import ListsPage from '../../pages/lists_page'
2020-03-04 03:45:16 +00:00
import BasicPage from '../../pages/basic_page'
2020-03-05 15:44:17 +00:00
import ModalPage from '../../pages/modal_page'
2020-02-24 21:56:07 +00:00
import SettingsPage from '../../pages/settings_page'
2020-07-02 02:40:00 +01:00
import ProPage from '../../pages/pro_page'
2020-07-02 03:39:43 +01:00
import ExplorePage from '../../pages/explore_page'
2020-08-06 06:16:52 +01:00
import NewsPage from '../../pages/news_page'
2020-07-10 21:22:13 +01:00
import AboutPage from '../../pages/about_page'
2020-10-29 23:46:54 +00:00
import LinkPage from '../../pages/link_page'
2019-08-09 17:06:27 +01:00
import {
2020-07-10 21:22:13 +01:00
About ,
2020-03-04 03:45:16 +00:00
AccountGallery ,
2020-02-17 17:50:29 +00:00
AccountTimeline ,
2020-09-12 00:02:07 +01:00
Assets ,
2020-04-11 23:29:19 +01:00
BlockedAccounts ,
BlockedDomains ,
2020-07-25 00:48:31 +01:00
BookmarkedStatuses ,
2020-03-04 03:45:16 +00:00
CommunityTimeline ,
2020-05-15 03:31:24 +01:00
Compose ,
2020-07-10 21:22:13 +01:00
DMCA ,
2020-09-15 02:20:27 +01:00
ExploreTimeline ,
2020-03-28 00:09:11 +00:00
// Filters,
2020-02-29 15:42:47 +00:00
Followers ,
Following ,
2020-03-04 03:45:16 +00:00
FollowRequests ,
2020-02-22 23:26:23 +00:00
GenericNotFound ,
GroupsCollection ,
2020-08-06 06:02:31 +01:00
GroupCollectionTimeline ,
2020-02-29 15:42:47 +00:00
GroupCreate ,
2020-08-06 06:02:31 +01:00
GroupAbout ,
2020-09-10 23:07:00 +01:00
GroupJoinRequests ,
2020-03-04 03:45:16 +00:00
GroupMembers ,
GroupRemovedAccounts ,
GroupTimeline ,
2020-09-10 23:15:35 +01:00
GroupsCategories ,
2020-09-14 23:12:45 +01:00
GroupCategory ,
GroupTag ,
2020-03-04 03:45:16 +00:00
HashtagTimeline ,
HomeTimeline ,
2020-07-10 21:22:13 +01:00
Investors ,
2020-03-24 04:39:12 +00:00
LikedStatuses ,
2020-10-29 23:46:54 +00:00
LinkTimeline ,
2020-03-05 15:44:17 +00:00
ListCreate ,
2020-03-04 03:45:16 +00:00
ListsDirectory ,
2020-03-05 15:44:17 +00:00
ListEdit ,
2020-03-04 03:45:16 +00:00
ListTimeline ,
Mutes ,
2020-08-06 06:16:52 +01:00
News ,
2020-11-07 05:31:52 +00:00
NewsView ,
2020-03-04 03:45:16 +00:00
Notifications ,
2020-09-12 00:02:07 +01:00
Press ,
2020-07-10 21:22:13 +01:00
PrivacyPolicy ,
2020-07-02 02:40:00 +01:00
ProTimeline ,
2020-03-04 03:45:16 +00:00
Search ,
2020-07-22 04:24:26 +01:00
Shortcuts ,
2020-04-29 23:32:49 +01:00
StatusFeature ,
2020-04-28 06:33:58 +01:00
StatusLikes ,
StatusReposts ,
2020-09-10 22:21:20 +01:00
Suggestions ,
2020-07-10 21:22:13 +01:00
TermsOfSale ,
TermsOfService ,
2020-03-25 03:08:43 +00:00
} from './util/async_components'
2020-02-24 21:56:07 +00:00
import { me , meUsername } from '../../initial_state'
2019-08-09 17:06:27 +01:00
// Dummy import, to make sure that <Status /> ends up in the application bundle.
// Without this it ends up in ~8 very commonly used bundles.
2020-02-24 21:56:07 +00:00
import '../../components/status'
2019-08-09 17:06:27 +01:00
const messages = defineMessages ( {
beforeUnload : { id : 'ui.beforeunload' , defaultMessage : 'Your draft will be lost if you leave Gab Social.' } ,
publish : { id : 'compose_form.publish' , defaultMessage : 'Gab' } ,
2020-02-24 21:56:07 +00:00
} )
2019-08-09 17:06:27 +01:00
2020-04-11 23:29:19 +01:00
const mapStateToProps = ( state ) => ( {
2019-08-09 17:06:27 +01:00
isComposing : state . getIn ( [ 'compose' , 'is_composing' ] ) ,
hasComposingText : state . getIn ( [ 'compose' , 'text' ] ) . trim ( ) . length !== 0 ,
hasMediaAttachments : state . getIn ( [ 'compose' , 'media_attachments' ] ) . size > 0 ,
2020-02-24 21:56:07 +00:00
} )
2019-08-09 17:06:27 +01:00
const keyMap = {
help : '?' ,
new : 'n' ,
search : 's' ,
forceNew : 'option+n' ,
reply : 'r' ,
2020-02-29 15:42:47 +00:00
Favorite : 'f' ,
2019-08-09 17:06:27 +01:00
boost : 'b' ,
mention : 'm' ,
open : [ 'enter' , 'o' ] ,
openProfile : 'p' ,
moveDown : [ 'down' , 'j' ] ,
moveUp : [ 'up' , 'k' ] ,
back : 'backspace' ,
goToHome : 'g h' ,
goToNotifications : 'g n' ,
goToStart : 'g s' ,
2020-02-29 15:42:47 +00:00
goToFavorites : 'g f' ,
2019-08-09 17:06:27 +01:00
goToProfile : 'g u' ,
goToBlocked : 'g b' ,
goToMuted : 'g m' ,
goToRequests : 'g r' ,
2020-02-24 21:56:07 +00:00
}
2019-08-09 17:06:27 +01:00
2020-08-17 21:07:16 +01:00
class SwitchingArea extends React . PureComponent {
2019-08-09 17:06:27 +01:00
2020-04-28 06:33:58 +01:00
componentDidMount ( ) {
2020-02-22 23:26:23 +00:00
window . addEventListener ( 'resize' , this . handleResize , {
passive : true
} )
2019-08-09 17:06:27 +01:00
}
componentWillUnmount ( ) {
2020-02-22 23:26:23 +00:00
window . removeEventListener ( 'resize' , this . handleResize )
2019-08-09 17:06:27 +01:00
}
handleResize = debounce ( ( ) => {
// The cached heights are no longer accurate, invalidate
2020-02-22 23:26:23 +00:00
this . props . onLayoutChange ( )
2019-08-09 17:06:27 +01:00
} , 500 , {
2020-07-14 07:05:05 +01:00
trailing : true ,
} )
2019-08-09 17:06:27 +01:00
setRef = c => {
2020-02-22 23:26:23 +00:00
this . node = c . getWrappedInstance ( )
2019-08-09 17:06:27 +01:00
}
render ( ) {
2020-02-22 23:26:23 +00:00
const { children } = this . props
2019-08-09 17:06:27 +01:00
return (
< Switch >
2020-08-06 06:16:52 +01:00
{
! ! me &&
< Redirect from = '/' to = '/home' exact / >
}
{
! me &&
2020-09-15 02:20:27 +01:00
< WrappedRoute path = '/' exact publicRoute page = { ExplorePage } component = { ExploreTimeline } content = { children } componentParams = { { title : 'Gab.com' } } / >
2020-08-06 06:16:52 +01:00
}
2020-07-10 21:22:13 +01:00
2020-08-06 06:16:52 +01:00
< WrappedRoute path = '/home' exact page = { HomePage } component = { HomeTimeline } content = { children } / >
2020-07-14 07:05:05 +01:00
2020-07-10 21:22:13 +01:00
< WrappedRoute path = '/about' publicRoute exact page = { AboutPage } component = { About } content = { children } componentParams = { { title : 'About' } } / >
2020-09-12 00:02:07 +01:00
< WrappedRoute path = '/about/assets' publicRoute exact page = { AboutPage } component = { Assets } content = { children } componentParams = { { title : 'Assets' } } / >
2020-07-10 21:22:13 +01:00
< WrappedRoute path = '/about/dmca' publicRoute exact page = { AboutPage } component = { DMCA } content = { children } componentParams = { { title : 'DMCA' } } / >
< WrappedRoute path = '/about/investors' publicRoute exact page = { AboutPage } component = { Investors } content = { children } componentParams = { { title : 'Investors' } } / >
2020-09-12 00:02:07 +01:00
< WrappedRoute path = '/about/press' publicRoute exact page = { AboutPage } component = { Press } content = { children } componentParams = { { title : 'Press' } } / >
2020-07-10 21:22:13 +01:00
< WrappedRoute path = '/about/privacy' publicRoute exact page = { AboutPage } component = { PrivacyPolicy } content = { children } componentParams = { { title : 'Privacy Policy' } } / >
< WrappedRoute path = '/about/sales' publicRoute exact page = { AboutPage } component = { TermsOfSale } content = { children } componentParams = { { title : 'Terms of Sale' } } / >
< WrappedRoute path = '/about/tos' publicRoute exact page = { AboutPage } component = { TermsOfService } content = { children } componentParams = { { title : 'Terms of Service' } } / >
2020-09-15 02:20:27 +01:00
< WrappedRoute path = '/explore' publicRoute page = { ExplorePage } component = { ExploreTimeline } content = { children } componentParams = { { title : 'Explore' } } / >
2020-09-10 22:21:20 +01:00
< WrappedRoute path = '/suggestions' exact page = { BasicPage } component = { Suggestions } content = { children } componentParams = { { title : 'Suggestions' } } / >
2019-08-09 17:06:27 +01:00
2020-07-16 05:05:08 +01:00
< WrappedRoute path = '/compose' exact page = { BasicPage } component = { Compose } content = { children } componentParams = { { title : 'Compose' , page : 'compose' } } / >
2020-05-14 07:03:22 +01:00
2020-11-07 05:31:52 +00:00
< WrappedRoute path = '/news' exact publicRoute page = { NewsPage } component = { News } content = { children } / >
< WrappedRoute path = '/news/view/:trendsRSSId' page = { NewsPage } component = { NewsView } content = { children } / >
2020-05-03 06:22:49 +01:00
< WrappedRoute path = '/timeline/all' exact page = { CommunityPage } component = { CommunityTimeline } content = { children } componentParams = { { title : 'Community Feed' } } / >
2020-07-07 21:55:59 +01:00
< WrappedRoute path = '/timeline/pro' exact page = { ProPage } component = { ProTimeline } content = { children } componentParams = { { title : 'Pro Feed' } } / >
2020-02-22 23:26:23 +00:00
2020-08-06 06:01:56 +01:00
< WrappedRoute path = '/groups' publicRoute exact page = { GroupsPage } component = { GroupCollectionTimeline } content = { children } componentParams = { { activeTab : 'timeline' , collectionType : 'member' } } / >
< WrappedRoute path = '/groups/browse/new' exact page = { GroupsPage } component = { GroupsCollection } content = { children } componentParams = { { activeTab : 'new' } } / >
< WrappedRoute path = '/groups/browse/featured' exact page = { GroupsPage } component = { GroupsCollection } content = { children } componentParams = { { activeTab : 'featured' } } / >
2020-02-22 23:26:23 +00:00
< WrappedRoute path = '/groups/browse/member' exact page = { GroupsPage } component = { GroupsCollection } content = { children } componentParams = { { activeTab : 'member' } } / >
< WrappedRoute path = '/groups/browse/admin' exact page = { GroupsPage } component = { GroupsCollection } content = { children } componentParams = { { activeTab : 'admin' } } / >
2020-09-10 23:15:35 +01:00
< WrappedRoute path = '/groups/browse/categories' exact page = { GroupsPage } component = { GroupsCategories } content = { children } componentParams = { { activeTab : 'categories' } } / >
2020-09-14 23:12:45 +01:00
< WrappedRoute path = '/groups/browse/categories/:sluggedCategory' exact page = { GroupsPage } component = { GroupCategory } content = { children } componentParams = { { activeTab : 'categories' } } / >
< WrappedRoute path = '/groups/browse/tags/:sluggedTag' exact page = { GroupsPage } component = { GroupTag } content = { children } / >
2020-02-22 23:26:23 +00:00
2020-07-16 05:05:08 +01:00
< WrappedRoute path = '/groups/create' page = { ModalPage } component = { GroupCreate } content = { children } componentParams = { { title : 'Create Group' , page : 'create-group' } } / >
2020-08-06 06:01:56 +01:00
< WrappedRoute path = '/groups/:id/members' page = { GroupPage } component = { GroupMembers } content = { children } / >
2020-09-10 23:07:00 +01:00
< WrappedRoute path = '/groups/:id/requests' page = { GroupPage } component = { GroupJoinRequests } content = { children } / >
2020-08-06 06:01:56 +01:00
< WrappedRoute path = '/groups/:id/removed-accounts' page = { GroupPage } component = { GroupRemovedAccounts } content = { children } / >
2020-07-16 05:05:08 +01:00
< WrappedRoute path = '/groups/:id/edit' page = { ModalPage } component = { GroupCreate } content = { children } componentParams = { { title : 'Edit Group' , page : 'edit-group' } } / >
2020-08-06 06:01:56 +01:00
< WrappedRoute path = '/groups/:id/about' publicRoute page = { GroupPage } component = { GroupAbout } content = { children } / >
2020-08-07 23:29:23 +01:00
{ /* <WrappedRoute path='/groups/:id/media' publicRoute page={GroupPage} component={GroupTimeline} content={children} componentParams={{ isTimeline: true, onlyMedia: true }} /> */ }
< WrappedRoute path = '/groups/:id' exact publicRoute page = { GroupPage } component = { GroupTimeline } content = { children } componentParams = { { isTimeline : true } } / >
2019-08-09 17:06:27 +01:00
2020-03-25 03:08:43 +00:00
< WrappedRoute path = '/tags/:id' publicRoute page = { HashtagPage } component = { HashtagTimeline } content = { children } componentParams = { { title : 'Hashtag' } } / >
2020-10-29 23:46:54 +00:00
2020-11-01 00:17:04 +00:00
< WrappedRoute path = '/links/:id' page = { LinkPage } component = { LinkTimeline } content = { children } componentParams = { { title : 'Link Feed' } } / >
2020-03-25 03:08:43 +00:00
2020-07-22 04:24:26 +01:00
< WrappedRoute path = '/shortcuts' page = { ShortcutsPage } component = { Shortcuts } content = { children } / >
2020-02-22 23:26:23 +00:00
< WrappedRoute path = '/lists' exact page = { ListsPage } component = { ListsDirectory } content = { children } / >
2020-07-16 05:05:08 +01:00
< WrappedRoute path = '/lists/create' exact page = { ModalPage } component = { ListCreate } content = { children } componentParams = { { title : 'Create List' , page : 'create-list' } } / >
< WrappedRoute path = '/lists/:id/edit' exact page = { ModalPage } component = { ListEdit } content = { children } componentParams = { { title : 'Edit List' , page : 'edit-list' } } / >
2020-03-26 03:11:32 +00:00
< WrappedRoute path = '/lists/:id' page = { ListPage } component = { ListTimeline } content = { children } / >
2019-08-09 17:06:27 +01:00
2020-02-22 23:26:23 +00:00
< WrappedRoute path = '/notifications' exact page = { NotificationsPage } component = { Notifications } content = { children } / >
2020-06-10 22:05:02 +01:00
< Redirect from = '/follow_requests' to = '/notifications/follow_requests' exact / >
2020-06-07 18:37:30 +01:00
< WrappedRoute path = '/notifications/follow_requests' exact page = { NotificationsPage } component = { FollowRequests } content = { children } / >
2020-02-22 23:26:23 +00:00
2020-01-28 16:29:37 +00:00
< WrappedRoute path = '/search' exact publicRoute page = { SearchPage } component = { Search } content = { children } / >
2020-05-09 03:17:19 +01:00
< WrappedRoute path = '/search/people' exact publicRoute page = { SearchPage } component = { Search } content = { children } / >
2020-08-06 06:01:37 +01:00
< WrappedRoute path = '/search/hashtags' exact publicRoute page = { SearchPage } component = { Search } content = { children } / >
2020-07-25 03:41:30 +01:00
< WrappedRoute path = '/search/groups' exact publicRoute page = { SearchPage } component = { Search } content = { children } / >
2020-10-26 06:08:31 +00:00
< WrappedRoute path = '/search/statuses' exact publicRoute page = { SearchPage } component = { Search } content = { children } / >
2020-10-31 23:33:58 +00:00
< WrappedRoute path = '/search/links' exact page = { SearchPage } component = { Search } content = { children } / >
2019-08-09 17:06:27 +01:00
2020-06-10 17:08:31 +01:00
< WrappedRoute path = '/settings/blocks' exact page = { SettingsPage } component = { BlockedAccounts } content = { children } componentParams = { { title : 'Blocked Users' } } / >
< WrappedRoute path = '/settings/mutes' exact page = { SettingsPage } component = { Mutes } content = { children } componentParams = { { title : 'Muted Users' } } / >
2019-08-09 17:06:27 +01:00
< Redirect from = '/@:username' to = '/:username' exact / >
2020-02-22 23:26:23 +00:00
< WrappedRoute path = '/:username' publicRoute exact page = { ProfilePage } component = { AccountTimeline } content = { children } / >
2020-02-24 21:56:07 +00:00
2020-02-29 15:42:47 +00:00
< Redirect from = '/@:username/comments' to = '/:username/comments' / >
< WrappedRoute path = '/:username/comments' page = { ProfilePage } component = { AccountTimeline } content = { children } componentParams = { { commentsOnly : true } } / >
2019-08-09 17:06:27 +01:00
< Redirect from = '/@:username/followers' to = '/:username/followers' / >
2020-02-29 15:42:47 +00:00
< WrappedRoute path = '/:username/followers' page = { ProfilePage } component = { Followers } content = { children } / >
2019-08-09 17:06:27 +01:00
< Redirect from = '/@:username/following' to = '/:username/following' / >
2020-02-29 15:42:47 +00:00
< WrappedRoute path = '/:username/following' page = { ProfilePage } component = { Following } content = { children } / >
2020-03-04 03:45:16 +00:00
2020-06-09 00:38:36 +01:00
< Redirect from = '/@:username/media' to = '/:username/photos' / >
< Redirect from = '/@:username/photos' to = '/:username/photos' / >
< Redirect from = '/:username/media' to = '/:username/photos' / >
< WrappedRoute path = '/:username/photos' page = { ProfilePage } component = { AccountGallery } content = { children } componentParams = { { noSidebar : true , mediaType : 'photo' } } / >
< WrappedRoute path = '/:username/videos' page = { ProfilePage } component = { AccountGallery } content = { children } componentParams = { { noSidebar : true , mediaType : 'video' } } / >
2020-03-04 03:45:16 +00:00
2020-03-24 04:39:12 +00:00
< Redirect from = '/@:username/likes' to = '/:username/likes' / >
< WrappedRoute path = '/:username/likes' page = { ProfilePage } component = { LikedStatuses } content = { children } / >
2020-02-22 23:26:23 +00:00
2020-07-25 00:48:31 +01:00
< Redirect from = '/@:username/bookmarks' to = '/:username/bookmarks' / >
< WrappedRoute path = '/:username/bookmarks' page = { ProfilePage } component = { BookmarkedStatuses } content = { children } / >
2019-08-09 17:06:27 +01:00
< Redirect from = '/@:username/posts/:statusId' to = '/:username/posts/:statusId' exact / >
2020-07-16 05:05:08 +01:00
< WrappedRoute path = '/:username/posts/:statusId' publicRoute exact page = { BasicPage } component = { StatusFeature } content = { children } componentParams = { { title : 'Status' , page : 'status' } } / >
2020-02-22 23:26:23 +00:00
2020-03-04 22:26:01 +00:00
< Redirect from = '/@:username/posts/:statusId/reposts' to = '/:username/posts/:statusId/reposts' / >
2020-08-20 21:11:39 +01:00
< WrappedRoute path = '/:username/posts/:statusId/reposts' publicRoute page = { ModalPage } component = { StatusReposts } content = { children } componentParams = { { title : 'Reposts' } } / >
2020-03-04 03:45:16 +00:00
2020-04-28 06:33:58 +01:00
< Redirect from = '/@:username/posts/:statusId/likes' to = '/:username/posts/:statusId/likes' / >
2020-08-20 21:11:39 +01:00
< WrappedRoute path = '/:username/posts/:statusId/likes' page = { ModalPage } component = { StatusLikes } content = { children } componentParams = { { title : 'Likes' } } / >
2020-03-04 03:45:16 +00:00
2020-02-22 23:26:23 +00:00
< WrappedRoute page = { ErrorPage } component = { GenericNotFound } content = { children } / >
2019-08-09 17:06:27 +01:00
< / S w i t c h >
2020-02-24 21:56:07 +00:00
)
2019-08-09 17:06:27 +01:00
}
}
2020-08-17 23:06:22 +01:00
SwitchingArea . propTypes = {
children : PropTypes . node ,
location : PropTypes . object ,
onLayoutChange : PropTypes . func . isRequired ,
}
2020-08-17 21:07:16 +01:00
class UI extends React . PureComponent {
2019-08-09 17:06:27 +01:00
static contextTypes = {
router : PropTypes . object . isRequired ,
2020-02-22 23:26:23 +00:00
}
2019-08-09 17:06:27 +01:00
state = {
2020-05-21 20:35:24 +01:00
fetchedHome : false ,
fetchedNotifications : false ,
2019-08-09 17:06:27 +01:00
draggingOver : false ,
2020-02-22 23:26:23 +00:00
}
2019-08-09 17:06:27 +01:00
handleBeforeUnload = ( e ) => {
2020-02-22 23:26:23 +00:00
const {
intl ,
isComposing ,
hasComposingText ,
hasMediaAttachments
} = this . props
2019-08-09 17:06:27 +01:00
if ( isComposing && ( hasComposingText || hasMediaAttachments ) ) {
// Setting returnValue to any string causes confirmation dialog.
// Many browsers no longer display this text to users,
// but we set user-friendly message for other browsers, e.g. Edge.
2020-02-22 23:26:23 +00:00
e . returnValue = intl . formatMessage ( messages . beforeUnload )
2019-08-09 17:06:27 +01:00
}
}
handleLayoutChange = ( ) => {
// The cached heights are no longer accurate, invalidate
2020-02-22 23:26:23 +00:00
this . props . dispatch ( clearHeight ( ) )
2019-08-09 17:06:27 +01:00
}
handleDragEnter = ( e ) => {
2020-02-22 23:26:23 +00:00
e . preventDefault ( )
2019-08-09 17:06:27 +01:00
if ( ! this . dragTargets ) {
2020-02-22 23:26:23 +00:00
this . dragTargets = [ ]
2019-08-09 17:06:27 +01:00
}
if ( this . dragTargets . indexOf ( e . target ) === - 1 ) {
2020-02-22 23:26:23 +00:00
this . dragTargets . push ( e . target )
2019-08-09 17:06:27 +01:00
}
if ( e . dataTransfer && Array . from ( e . dataTransfer . types ) . includes ( 'Files' ) ) {
2020-02-22 23:26:23 +00:00
this . setState ( {
2020-03-04 03:45:16 +00:00
draggingOver : true ,
2020-02-22 23:26:23 +00:00
} )
2019-08-09 17:06:27 +01:00
}
}
handleDragOver = ( e ) => {
2020-02-22 23:26:23 +00:00
if ( this . dataTransferIsText ( e . dataTransfer ) ) return false
e . preventDefault ( )
e . stopPropagation ( )
2019-08-09 17:06:27 +01:00
try {
2020-02-24 21:56:07 +00:00
e . dataTransfer . dropEffect = 'copy'
2019-08-09 17:06:27 +01:00
} catch ( err ) {
2020-02-22 23:26:23 +00:00
//
2019-08-09 17:06:27 +01:00
}
2020-02-22 23:26:23 +00:00
return false
2019-08-09 17:06:27 +01:00
}
handleDrop = ( e ) => {
2020-02-22 23:26:23 +00:00
if ( ! me ) return
2019-08-09 17:06:27 +01:00
2020-02-22 23:26:23 +00:00
if ( this . dataTransferIsText ( e . dataTransfer ) ) return
e . preventDefault ( )
2019-08-09 17:06:27 +01:00
2020-02-22 23:26:23 +00:00
this . setState ( {
draggingOver : false
} )
this . dragTargets = [ ]
2019-08-09 17:06:27 +01:00
if ( e . dataTransfer && e . dataTransfer . files . length >= 1 ) {
2020-02-22 23:26:23 +00:00
this . props . dispatch ( uploadCompose ( e . dataTransfer . files ) )
2019-08-09 17:06:27 +01:00
}
}
handleDragLeave = ( e ) => {
2020-02-24 21:56:07 +00:00
e . preventDefault ( )
e . stopPropagation ( )
2019-08-09 17:06:27 +01:00
2020-02-24 21:56:07 +00:00
this . dragTargets = this . dragTargets . filter ( el => el !== e . target && this . node . contains ( el ) )
2019-08-09 17:06:27 +01:00
2020-02-22 23:26:23 +00:00
if ( this . dragTargets . length > 0 ) return
2019-08-09 17:06:27 +01:00
2020-02-22 23:26:23 +00:00
this . setState ( {
draggingOver : false
} )
2019-08-09 17:06:27 +01:00
}
dataTransferIsText = ( dataTransfer ) => {
2020-02-22 23:26:23 +00:00
return (
dataTransfer
&& Array . from ( dataTransfer . types ) . includes ( 'text/plain' )
&& dataTransfer . items . length === 1
)
2019-08-09 17:06:27 +01:00
}
closeUploadModal = ( ) => {
2020-02-22 23:26:23 +00:00
this . setState ( {
draggingOver : false
} )
2019-08-09 17:06:27 +01:00
}
handleServiceWorkerPostMessage = ( { data } ) => {
if ( data . type === 'navigate' ) {
2020-02-24 21:56:07 +00:00
this . context . router . history . push ( data . path )
2019-08-09 17:06:27 +01:00
} else {
2020-02-24 21:56:07 +00:00
console . warn ( 'Unknown message type:' , data . type )
2019-08-09 17:06:27 +01:00
}
}
2020-05-19 20:49:54 +01:00
componentWillMount ( ) {
2020-05-09 03:17:19 +01:00
if ( ! me ) return
2020-04-28 06:33:58 +01:00
2020-02-24 21:56:07 +00:00
window . addEventListener ( 'beforeunload' , this . handleBeforeUnload , false )
2019-08-09 17:06:27 +01:00
2020-02-24 21:56:07 +00:00
document . addEventListener ( 'dragenter' , this . handleDragEnter , false )
document . addEventListener ( 'dragover' , this . handleDragOver , false )
document . addEventListener ( 'drop' , this . handleDrop , false )
document . addEventListener ( 'dragleave' , this . handleDragLeave , false )
document . addEventListener ( 'dragend' , this . handleDragEnd , false )
2019-08-09 17:06:27 +01:00
if ( 'serviceWorker' in navigator ) {
2020-02-24 21:56:07 +00:00
navigator . serviceWorker . addEventListener ( 'message' , this . handleServiceWorkerPostMessage )
2019-08-09 17:06:27 +01:00
}
if ( typeof window . Notification !== 'undefined' && Notification . permission === 'default' ) {
2020-02-24 21:56:07 +00:00
window . setTimeout ( ( ) => Notification . requestPermission ( ) , 120 * 1000 )
2019-08-09 17:06:27 +01:00
}
2020-05-21 20:35:24 +01:00
const pathname = this . context . router . route . location . pathname
if ( pathname === '/home' ) {
this . setState ( { fetchedHome : true } )
2020-05-19 20:49:54 +01:00
this . props . dispatch ( expandHomeTimeline ( ) )
2020-05-21 20:35:24 +01:00
} else if ( pathname . startsWith ( '/notifications' ) ) {
2020-05-21 23:03:35 +01:00
try {
const search = this . context . router . route . location . search
const qp = queryString . parse ( search )
2020-06-09 21:02:02 +01:00
let view = ` ${ qp . view } ` . toLowerCase ( )
if ( pathname . startsWith ( '/notifications/follow_requests' ) ) {
view = 'follow_requests'
}
2020-05-21 23:03:35 +01:00
this . props . dispatch ( setFilter ( 'active' , view ) )
} catch ( error ) {
//
}
2020-05-21 20:35:24 +01:00
this . setState ( { fetchedNotifications : true } )
2020-05-19 20:49:54 +01:00
this . props . dispatch ( expandNotifications ( ) )
}
2020-05-09 03:17:19 +01:00
this . props . dispatch ( initializeNotifications ( ) )
2020-05-19 20:49:54 +01:00
}
2019-08-09 17:06:27 +01:00
2020-05-19 20:49:54 +01:00
componentDidMount ( ) {
2020-03-14 17:31:29 +00:00
// this.hotkeys.__mousetrap__.stopCallback = (e, element) => {
// return ['TEXTAREA', 'SELECT', 'INPUT'].includes(element.tagName)
// }
2019-08-09 17:06:27 +01:00
}
componentWillUnmount ( ) {
2020-02-24 21:56:07 +00:00
window . removeEventListener ( 'beforeunload' , this . handleBeforeUnload )
document . removeEventListener ( 'dragenter' , this . handleDragEnter )
document . removeEventListener ( 'dragover' , this . handleDragOver )
document . removeEventListener ( 'drop' , this . handleDrop )
document . removeEventListener ( 'dragleave' , this . handleDragLeave )
document . removeEventListener ( 'dragend' , this . handleDragEnd )
2019-08-09 17:06:27 +01:00
}
2020-05-21 20:35:24 +01:00
componentDidUpdate ( prevProps ) {
if ( this . props . location !== prevProps . location ) {
const pathname = this . props . location . pathname
if ( pathname === '/home' && ! this . state . fetchedHome ) {
this . setState ( { fetchedHome : true } )
this . props . dispatch ( expandHomeTimeline ( ) )
} else if ( pathname . startsWith ( '/notifications' ) && ! this . state . fetchedNotifications ) {
this . setState ( { fetchedNotifications : true } )
this . props . dispatch ( expandNotifications ( ) )
}
}
}
2020-05-09 03:17:19 +01:00
setRef = ( c ) => {
2020-02-24 21:56:07 +00:00
this . node = c
2019-08-09 17:06:27 +01:00
}
2020-05-09 03:17:19 +01:00
handleHotkeyNew = ( e ) => {
2020-02-24 21:56:07 +00:00
e . preventDefault ( )
2019-08-09 17:06:27 +01:00
2020-02-24 21:56:07 +00:00
const element = this . node . querySelector ( '.compose-form__autosuggest-wrapper textarea' )
2019-08-09 17:06:27 +01:00
if ( element ) {
2020-02-24 21:56:07 +00:00
element . focus ( )
2019-08-09 17:06:27 +01:00
}
}
2020-05-09 03:17:19 +01:00
handleHotkeySearch = ( e ) => {
2020-02-24 21:56:07 +00:00
e . preventDefault ( )
2019-08-09 17:06:27 +01:00
2020-02-24 21:56:07 +00:00
const element = this . node . querySelector ( '.search__input' )
2019-08-09 17:06:27 +01:00
if ( element ) {
2020-02-24 21:56:07 +00:00
element . focus ( )
2019-08-09 17:06:27 +01:00
}
}
2020-05-09 03:17:19 +01:00
handleHotkeyForceNew = ( e ) => {
2020-02-24 21:56:07 +00:00
this . handleHotkeyNew ( e )
this . props . dispatch ( resetCompose ( ) )
2019-08-09 17:06:27 +01:00
}
handleHotkeyBack = ( ) => {
if ( window . history && window . history . length === 1 ) {
2020-02-22 23:26:23 +00:00
this . context . router . history . push ( '/home' ) // homehack
2019-08-09 17:06:27 +01:00
} else {
2020-02-22 23:26:23 +00:00
this . context . router . history . goBack ( )
2019-08-09 17:06:27 +01:00
}
}
2020-05-09 03:17:19 +01:00
setHotkeysRef = ( c ) => {
2020-02-24 21:56:07 +00:00
this . hotkeys = c
2019-08-09 17:06:27 +01:00
}
handleHotkeyToggleHelp = ( ) => {
2020-04-28 06:33:58 +01:00
this . props . dispatch ( openModal ( 'HOTKEYS' ) )
2019-08-09 17:06:27 +01:00
}
handleHotkeyGoToHome = ( ) => {
2020-02-22 23:26:23 +00:00
this . context . router . history . push ( '/home' )
2019-08-09 17:06:27 +01:00
}
handleHotkeyGoToNotifications = ( ) => {
2020-02-22 23:26:23 +00:00
this . context . router . history . push ( '/notifications' )
2019-08-09 17:06:27 +01:00
}
2020-01-28 16:29:37 +00:00
handleHotkeyGoToStart = ( ) => {
2020-02-22 23:26:23 +00:00
this . context . router . history . push ( '/getting-started' )
2020-01-28 16:29:37 +00:00
}
2020-02-29 15:42:47 +00:00
handleHotkeyGoToFavorites = ( ) => {
2020-02-22 23:26:23 +00:00
this . context . router . history . push ( ` / ${ meUsername } /favorites ` )
2019-08-09 17:06:27 +01:00
}
handleHotkeyGoToProfile = ( ) => {
2020-02-22 23:26:23 +00:00
this . context . router . history . push ( ` / ${ meUsername } ` )
2019-08-09 17:06:27 +01:00
}
handleHotkeyGoToBlocked = ( ) => {
2020-02-22 23:26:23 +00:00
this . context . router . history . push ( '/blocks' )
2019-08-09 17:06:27 +01:00
}
handleHotkeyGoToMuted = ( ) => {
2020-02-22 23:26:23 +00:00
this . context . router . history . push ( '/mutes' )
2019-08-09 17:06:27 +01:00
}
handleHotkeyGoToRequests = ( ) => {
2020-02-22 23:26:23 +00:00
this . context . router . history . push ( '/follow_requests' )
2019-08-09 17:06:27 +01:00
}
handleOpenComposeModal = ( ) => {
2020-04-28 06:33:58 +01:00
this . props . dispatch ( openModal ( 'COMPOSE' ) )
2019-08-09 17:06:27 +01:00
}
render ( ) {
2020-07-15 00:48:48 +01:00
const { children , location } = this . props
2020-02-24 21:56:07 +00:00
const { draggingOver } = this . state
2019-08-09 17:06:27 +01:00
2020-04-29 03:24:35 +01:00
// : todo :
// const handlers = me ? {
// help: this.handleHotkeyToggleHelp,
// new: this.handleHotkeyNew,
// search: this.handleHotkeySearch,
// forceNew: this.handleHotkeyForceNew,
// back: this.handleHotkeyBack,
// goToHome: this.handleHotkeyGoToHome,
// goToNotifications: this.handleHotkeyGoToNotifications,
// goToStart: this.handleHotkeyGoToStart,
// goToFavorites: this.handleHotkeyGoToFavorites,
// goToProfile: this.handleHotkeyGoToProfile,
// goToBlocked: this.handleHotkeyGoToBlocked,
// goToMuted: this.handleHotkeyGoToMuted,
// goToRequests: this.handleHotkeyGoToRequests,
// } : {}
2019-08-09 17:06:27 +01:00
return (
2020-05-15 00:56:27 +01:00
< div ref = { this . setRef } className = { _s . gabsocial } >
2020-08-18 21:43:06 +01:00
< LoadingBar className = { [ _s . h1PX , _s . z3 , _s . bgBrandLight ] . join ( ' ' ) } / >
2020-03-24 04:39:12 +00:00
2020-07-15 00:48:48 +01:00
< SwitchingArea location = { location } onLayoutChange = { this . handleLayoutChange } >
2020-03-14 17:31:29 +00:00
{ children }
< / S w i t c h i n g A r e a >
< ModalRoot / >
< PopoverRoot / >
2020-03-24 04:39:12 +00:00
2020-03-14 17:31:29 +00:00
< UploadArea active = { draggingOver } onClose = { this . closeUploadModal } / >
< / d i v >
2020-02-24 21:56:07 +00:00
)
2019-08-09 17:06:27 +01:00
}
}
2020-08-17 23:06:22 +01:00
UI . propTypes = {
dispatch : PropTypes . func . isRequired ,
children : PropTypes . node ,
isComposing : PropTypes . bool ,
hasComposingText : PropTypes . bool ,
hasMediaAttachments : PropTypes . bool ,
location : PropTypes . object ,
intl : PropTypes . object . isRequired ,
}
export default injectIntl ( withRouter ( connect ( mapStateToProps ) ( UI ) ) )