From c8cee24cb34fadf5d3887346f5b9333e0036adf6 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Mon, 25 May 2020 20:04:06 +0200 Subject: Fix Cmd-Enter not working to send toot Fixes #1333 --- .../glitch/features/compose/components/compose_form.js | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) (limited to 'app/javascript/flavours/glitch/features') diff --git a/app/javascript/flavours/glitch/features/compose/components/compose_form.js b/app/javascript/flavours/glitch/features/compose/components/compose_form.js index 3d736e83f..a7cb95222 100644 --- a/app/javascript/flavours/glitch/features/compose/components/compose_form.js +++ b/app/javascript/flavours/glitch/features/compose/components/compose_form.js @@ -158,19 +158,12 @@ class ComposeForm extends ImmutablePureComponent { this.props.onSuggestionSelected(tokenStart, token, value, ['spoiler_text']); } - // When the escape key is released, we focus the UI. - handleKeyUp = ({ key, ctrlKey, keyCode, metaKey, altKey }) => { - if (key === 'Escape') { - document.querySelector('.ui').parentElement.focus(); - } - - // We submit the status on control/meta + enter. - if (keyCode === 13 && (ctrlKey || metaKey)) { + handleKeyDown = (e) => { + if (e.keyCode === 13 && (e.ctrlKey || e.metaKey)) { this.handleSubmit(); } - // Submit the status with secondary visibility on alt + enter. - if (keyCode === 13 && altKey) { + if (e.keyCode == 13 && e.altKey) { this.handleSecondarySubmit(); } } @@ -305,7 +298,7 @@ class ComposeForm extends ImmutablePureComponent { placeholder={intl.formatMessage(messages.spoiler_placeholder)} value={spoilerText} onChange={this.handleChangeSpoiler} - onKeyUp={this.handleKeyUp} + onKeyDown={this.handleKeyDown} disabled={!spoiler} ref={this.handleRefSpoilerText} suggestions={this.props.suggestions} @@ -325,7 +318,7 @@ class ComposeForm extends ImmutablePureComponent { disabled={isSubmitting} value={this.props.text} onChange={this.handleChange} - onKeyUp={this.handleKeyUp} + onKeyDown={this.handleKeyDown} suggestions={this.props.suggestions} onFocus={this.handleFocus} onSuggestionsFetchRequested={onFetchSuggestions} -- cgit From 44ea965557f6a7577218e475df4a9d671dcff506 Mon Sep 17 00:00:00 2001 From: Takeshi Umeda Date: Sat, 23 May 2020 12:46:29 +0900 Subject: [Glitch] Fix local streaming of hashtag timelines Port 3a1a21ad5725bed7f82b516b4174272c1e931223 to glitch-soc Signed-off-by: Thibaut Girka --- app/javascript/flavours/glitch/actions/streaming.js | 2 +- app/javascript/flavours/glitch/actions/timelines.js | 2 +- .../flavours/glitch/features/hashtag_timeline/index.js | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'app/javascript/flavours/glitch/features') diff --git a/app/javascript/flavours/glitch/actions/streaming.js b/app/javascript/flavours/glitch/actions/streaming.js index 875013efc..e7e57f5f5 100644 --- a/app/javascript/flavours/glitch/actions/streaming.js +++ b/app/javascript/flavours/glitch/actions/streaming.js @@ -74,6 +74,6 @@ const refreshHomeTimelineAndNotification = (dispatch, done) => { export const connectUserStream = () => connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification); export const connectCommunityStream = ({ onlyMedia } = {}) => connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`); export const connectPublicStream = ({ onlyMedia, onlyRemote } = {}) => connectTimelineStream(`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`, `public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`); -export const connectHashtagStream = (id, tag, accept) => connectTimelineStream(`hashtag:${id}`, `hashtag&tag=${tag}`, null, accept); +export const connectHashtagStream = (id, tag, local, accept) => connectTimelineStream(`hashtag:${id}${local ? ':local' : ''}`, `hashtag${local ? ':local' : ''}&tag=${tag}`, null, accept); export const connectDirectStream = () => connectTimelineStream('direct', 'direct'); export const connectListStream = id => connectTimelineStream(`list:${id}`, `list&list=${id}`); diff --git a/app/javascript/flavours/glitch/actions/timelines.js b/app/javascript/flavours/glitch/actions/timelines.js index b01109134..0993824b3 100644 --- a/app/javascript/flavours/glitch/actions/timelines.js +++ b/app/javascript/flavours/glitch/actions/timelines.js @@ -129,7 +129,7 @@ export const expandAccountFeaturedTimeline = accountId => expandTimeline(`accoun export const expandAccountMediaTimeline = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: 40 }); export const expandListTimeline = (id, { maxId } = {}, done = noOp) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId }, done); export const expandHashtagTimeline = (hashtag, { maxId, tags, local } = {}, done = noOp) => { - return expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`, { + return expandTimeline(`hashtag:${hashtag}${local ? ':local' : ''}`, `/api/v1/timelines/tag/${hashtag}`, { max_id: maxId, any: parseTags(tags, 'any'), all: parseTags(tags, 'all'), diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js index e94f36501..48e52e4cd 100644 --- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js +++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js @@ -12,7 +12,7 @@ import { connectHashtagStream } from 'flavours/glitch/actions/streaming'; import { isEqual } from 'lodash'; const mapStateToProps = (state, props) => ({ - hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}`, 'unread']) > 0, + hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}${props.params.local ? ':local' : ''}`, 'unread']) > 0, }); export default @connect(mapStateToProps) @@ -75,13 +75,13 @@ class HashtagTimeline extends React.PureComponent { this.column.scrollTop(); } - _subscribe (dispatch, id, tags = {}) { + _subscribe (dispatch, id, tags = {}, local) { let any = (tags.any || []).map(tag => tag.value); let all = (tags.all || []).map(tag => tag.value); let none = (tags.none || []).map(tag => tag.value); [id, ...any].map(tag => { - this.disconnects.push(dispatch(connectHashtagStream(id, tag, status => { + this.disconnects.push(dispatch(connectHashtagStream(id, tag, local, status => { let tags = status.tags.map(tag => tag.name); return all.filter(tag => tags.includes(tag)).length === all.length && @@ -99,7 +99,7 @@ class HashtagTimeline extends React.PureComponent { const { dispatch } = this.props; const { id, tags, local } = this.props.params; - this._subscribe(dispatch, id, tags); + this._subscribe(dispatch, id, tags, local); dispatch(expandHashtagTimeline(id, { tags, local })); } @@ -109,8 +109,8 @@ class HashtagTimeline extends React.PureComponent { if (id !== params.id || !isEqual(tags, params.tags) || !isEqual(local, params.local)) { this._unsubscribe(); - this._subscribe(dispatch, id, tags); - dispatch(clearTimeline(`hashtag:${id}`)); + this._subscribe(dispatch, id, tags, local); + dispatch(clearTimeline(`hashtag:${id}${local ? ':local' : ''}`)); dispatch(expandHashtagTimeline(id, { tags, local })); } } @@ -130,7 +130,7 @@ class HashtagTimeline extends React.PureComponent { render () { const { hasUnread, columnId, multiColumn } = this.props; - const { id } = this.props.params; + const { id, local } = this.props.params; const pinned = !!columnId; return ( @@ -153,7 +153,7 @@ class HashtagTimeline extends React.PureComponent { } bindToDocument={!multiColumn} -- cgit From 7a74e46b770d4120890daafee51b36d1a3fa2db9 Mon Sep 17 00:00:00 2001 From: Thibaut Girka Date: Thu, 28 May 2020 14:11:38 +0200 Subject: Fix one import being made on mastodon's codebase instead of glitch-soc's --- .../glitch/features/getting_started/containers/trends_container.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/javascript/flavours/glitch/features') diff --git a/app/javascript/flavours/glitch/features/getting_started/containers/trends_container.js b/app/javascript/flavours/glitch/features/getting_started/containers/trends_container.js index 7a5268780..68568d169 100644 --- a/app/javascript/flavours/glitch/features/getting_started/containers/trends_container.js +++ b/app/javascript/flavours/glitch/features/getting_started/containers/trends_container.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { fetchTrends } from 'mastodon/actions/trends'; +import { fetchTrends } from 'flavours/glitch/actions/trends'; import Trends from '../components/trends'; const mapStateToProps = state => ({ -- cgit From 9bd30b8dd563d1c7066060ccfa456ea350a7fb01 Mon Sep 17 00:00:00 2001 From: ThibG Date: Fri, 29 May 2020 16:14:16 +0200 Subject: [Glitch] Fix timeline markers not working on Chrome Port 5aff2a6957e861162d67c4610277e9bb2a6f8186 to glitch-soc Signed-off-by: Thibaut Girka --- app/javascript/flavours/glitch/actions/markers.js | 70 ++++++++++++++++++---- .../flavours/glitch/actions/notifications.js | 4 ++ .../flavours/glitch/actions/timelines.js | 9 +++ .../flavours/glitch/features/ui/index.js | 4 +- app/javascript/flavours/glitch/reducers/index.js | 2 + app/javascript/flavours/glitch/reducers/markers.js | 25 ++++++++ 6 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 app/javascript/flavours/glitch/reducers/markers.js (limited to 'app/javascript/flavours/glitch/features') diff --git a/app/javascript/flavours/glitch/actions/markers.js b/app/javascript/flavours/glitch/actions/markers.js index 7ffab404d..b237d82ec 100644 --- a/app/javascript/flavours/glitch/actions/markers.js +++ b/app/javascript/flavours/glitch/actions/markers.js @@ -1,38 +1,86 @@ import api from 'flavours/glitch/util/api'; +import { debounce } from 'lodash'; +import compareId from 'flavours/glitch/util/compare_id'; +import { showAlertForError } from './alerts'; export const MARKERS_FETCH_REQUEST = 'MARKERS_FETCH_REQUEST'; export const MARKERS_FETCH_SUCCESS = 'MARKERS_FETCH_SUCCESS'; export const MARKERS_FETCH_FAIL = 'MARKERS_FETCH_FAIL'; +export const MARKERS_SUBMIT_SUCCESS = 'MARKERS_SUBMIT_SUCCESS'; -export const submitMarkers = () => (dispatch, getState) => { +export const synchronouslySubmitMarkers = () => (dispatch, getState) => { const accessToken = getState().getIn(['meta', 'access_token'], ''); - const params = {}; + const params = _buildParams(getState()); - const lastHomeId = getState().getIn(['timelines', 'home', 'items', 0]); - const lastNotificationId = getState().getIn(['notifications', 'lastReadId']); + if (Object.keys(params).length === 0) { + return; + } + + if (window.fetch) { + fetch('/api/v1/markers', { + keepalive: true, + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${accessToken}`, + }, + body: JSON.stringify(params), + }); + } else { + const client = new XMLHttpRequest(); + + client.open('POST', '/api/v1/markers', false); + client.setRequestHeader('Content-Type', 'application/json'); + client.setRequestHeader('Authorization', `Bearer ${accessToken}`); + client.SUBMIT(JSON.stringify(params)); + } +}; + +const _buildParams = (state) => { + const params = {}; - if (lastHomeId) { + const lastHomeId = state.getIn(['timelines', 'home', 'items', 0]); + const lastNotificationId = state.getIn(['notifications', 'lastReadId']); + + if (lastHomeId && compareId(lastHomeId, state.getIn(['markers', 'home'])) > 0) { params.home = { last_read_id: lastHomeId, }; } - if (lastNotificationId && lastNotificationId !== '0') { + if (lastNotificationId && lastNotificationId !== '0' && compareId(lastNotificationId, state.getIn(['markers', 'notifications'])) > 0) { params.notifications = { last_read_id: lastNotificationId, }; } + return params; +}; + +const debouncedSubmitMarkers = debounce((dispatch, getState) => { + const params = _buildParams(getState()); + if (Object.keys(params).length === 0) { return; } - const client = new XMLHttpRequest(); + api().post('/api/v1/markers', params).then(() => { + dispatch(submitMarkersSuccess(params)); + }).catch(error => { + dispatch(showAlertForError(error)); + }); +}, 300000, { leading: true, trailing: true }); + +export function submitMarkersSuccess({ home, notifications }) { + return { + type: MARKERS_SUBMIT_SUCCESS, + home: (home || {}).last_read_id, + notifications: (notifications || {}).last_read_id, + }; +}; - client.open('POST', '/api/v1/markers', false); - client.setRequestHeader('Content-Type', 'application/json'); - client.setRequestHeader('Authorization', `Bearer ${accessToken}`); - client.send(JSON.stringify(params)); +export function submitMarkers() { + return (dispatch, getState) => debouncedSubmitMarkers(dispatch, getState); }; export const fetchMarkers = () => (dispatch, getState) => { diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js index b3de7b5bf..ceb1e6df6 100644 --- a/app/javascript/flavours/glitch/actions/notifications.js +++ b/app/javascript/flavours/glitch/actions/notifications.js @@ -7,6 +7,7 @@ import { importFetchedStatus, importFetchedStatuses, } from './importer'; +import { submitMarkers } from './markers'; import { saveSettings } from './settings'; import { defineMessages } from 'react-intl'; import { List as ImmutableList } from 'immutable'; @@ -81,6 +82,8 @@ export function updateNotifications(notification, intlMessages, intlLocale) { filtered = regex && regex.test(searchIndex); } + dispatch(submitMarkers()); + if (showInColumn) { dispatch(importFetchedAccount(notification.account)); @@ -168,6 +171,7 @@ export function expandNotifications({ maxId } = {}, done = noOp) { dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null, isLoadingMore, isLoadingRecent, isLoadingRecent && preferPendingItems)); fetchRelatedRelationships(dispatch, response.data); + dispatch(submitMarkers()); }).catch(error => { dispatch(expandNotificationsFail(error, isLoadingMore)); }).finally(() => { diff --git a/app/javascript/flavours/glitch/actions/timelines.js b/app/javascript/flavours/glitch/actions/timelines.js index 46b605e04..9a7f62a08 100644 --- a/app/javascript/flavours/glitch/actions/timelines.js +++ b/app/javascript/flavours/glitch/actions/timelines.js @@ -1,4 +1,5 @@ import { importFetchedStatus, importFetchedStatuses } from './importer'; +import { submitMarkers } from './markers'; import api, { getLinks } from 'flavours/glitch/util/api'; import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; import compareId from 'flavours/glitch/util/compare_id'; @@ -49,6 +50,10 @@ export function updateTimeline(timeline, status, accept) { usePendingItems: preferPendingItems, filtered }); + + if (timeline === 'home') { + dispatch(submitMarkers()); + } }; }; @@ -112,6 +117,10 @@ export function expandTimeline(timelineId, path, params = {}, done = noOp) { dispatch(importFetchedStatuses(response.data)); dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null, response.status === 206, isLoadingRecent, isLoadingMore, isLoadingRecent && preferPendingItems)); + + if (timelineId === 'home') { + dispatch(submitMarkers()); + } }).catch(error => { dispatch(expandTimelineFail(timelineId, error, isLoadingMore)); }).finally(() => { diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js index 9f9ef561a..f8f6cff88 100644 --- a/app/javascript/flavours/glitch/features/ui/index.js +++ b/app/javascript/flavours/glitch/features/ui/index.js @@ -12,7 +12,7 @@ import { expandHomeTimeline } from 'flavours/glitch/actions/timelines'; import { expandNotifications, notificationsSetVisibility } from 'flavours/glitch/actions/notifications'; import { fetchFilters } from 'flavours/glitch/actions/filters'; import { clearHeight } from 'flavours/glitch/actions/height_cache'; -import { submitMarkers, fetchMarkers } from 'flavours/glitch/actions/markers'; +import { synchronouslySubmitMarkers, fetchMarkers } from 'flavours/glitch/actions/markers'; import { WrappedSwitch, WrappedRoute } from 'flavours/glitch/util/react_router_helpers'; import UploadArea from './components/upload_area'; import PermaLink from 'flavours/glitch/components/permalink'; @@ -267,7 +267,7 @@ class UI extends React.Component { handleBeforeUnload = (e) => { const { intl, dispatch, hasComposingText, hasMediaAttachments } = this.props; - dispatch(submitMarkers()); + dispatch(synchronouslySubmitMarkers()); if (hasComposingText || hasMediaAttachments) { // Setting returnValue to any string causes confirmation dialog. diff --git a/app/javascript/flavours/glitch/reducers/index.js b/app/javascript/flavours/glitch/reducers/index.js index 586b84749..852abe9dd 100644 --- a/app/javascript/flavours/glitch/reducers/index.js +++ b/app/javascript/flavours/glitch/reducers/index.js @@ -36,6 +36,7 @@ import polls from './polls'; import identity_proofs from './identity_proofs'; import trends from './trends'; import announcements from './announcements'; +import markers from './markers'; const reducers = { announcements, @@ -75,6 +76,7 @@ const reducers = { pinnedAccountsEditor, polls, trends, + markers, }; export default combineReducers(reducers); diff --git a/app/javascript/flavours/glitch/reducers/markers.js b/app/javascript/flavours/glitch/reducers/markers.js new file mode 100644 index 000000000..2e67be82e --- /dev/null +++ b/app/javascript/flavours/glitch/reducers/markers.js @@ -0,0 +1,25 @@ +import { + MARKERS_SUBMIT_SUCCESS, +} from '../actions/notifications'; + +const initialState = ImmutableMap({ + home: '0', + notifications: '0', +}); + +import { Map as ImmutableMap } from 'immutable'; + +export default function markers(state = initialState, action) { + switch(action.type) { + case MARKERS_SUBMIT_SUCCESS: + if (action.home) { + state = state.set('home', action.home); + } + if (action.notifications) { + state = state.set('notifications', action.notifications); + } + return state; + default: + return state; + } +}; -- cgit