Add a focus_composer dispatcher action

and use it
pull/21833/head
Travis Ralston 2020-06-02 19:07:46 -06:00
parent b50046f1ab
commit 1f1f613777
11 changed files with 31 additions and 17 deletions

View File

@ -31,6 +31,7 @@ import Spinner from "./components/views/elements/Spinner";
// Polyfill for Canvas.toBlob API using Canvas.toDataURL // Polyfill for Canvas.toBlob API using Canvas.toDataURL
import "blueimp-canvas-to-blob"; import "blueimp-canvas-to-blob";
import { Action } from "./dispatcher/actions";
const MAX_WIDTH = 800; const MAX_WIDTH = 800;
const MAX_HEIGHT = 600; const MAX_HEIGHT = 600;
@ -529,7 +530,7 @@ export default class ContentMessages {
dis.dispatch({action: 'upload_started'}); dis.dispatch({action: 'upload_started'});
// Focus the composer view // Focus the composer view
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
function onProgress(ev) { function onProgress(ev) {
upload.total = ev.total; upload.total = ev.total;

View File

@ -27,6 +27,7 @@ import SettingsStore from '../../settings/SettingsStore';
import {_t} from "../../languageHandler"; import {_t} from "../../languageHandler";
import Analytics from "../../Analytics"; import Analytics from "../../Analytics";
import RoomList2 from "../views/rooms/RoomList2"; import RoomList2 from "../views/rooms/RoomList2";
import {Action} from "../../dispatcher/actions";
const LeftPanel = createReactClass({ const LeftPanel = createReactClass({
@ -198,7 +199,7 @@ const LeftPanel = createReactClass({
onSearchCleared: function(source) { onSearchCleared: function(source) {
if (source === "keyboard") { if (source === "keyboard") {
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
} }
this.setState({searchExpanded: false}); this.setState({searchExpanded: false});
}, },

View File

@ -51,6 +51,7 @@ import {
showToast as showServerLimitToast, showToast as showServerLimitToast,
hideToast as hideServerLimitToast hideToast as hideServerLimitToast
} from "../../toasts/ServerLimitToast"; } from "../../toasts/ServerLimitToast";
import { Action } from "../../dispatcher/actions";
// We need to fetch each pinned message individually (if we don't already have it) // We need to fetch each pinned message individually (if we don't already have it)
// so each pinned message may trigger a request. Limit the number per room for sanity. // so each pinned message may trigger a request. Limit the number per room for sanity.
@ -346,7 +347,7 @@ class LoggedInView extends React.PureComponent<IProps, IState> {
// refocusing during a paste event will make the // refocusing during a paste event will make the
// paste end up in the newly focused element, // paste end up in the newly focused element,
// so dispatch synchronously before paste happens // so dispatch synchronously before paste happens
dis.dispatch({action: 'focus_composer'}, true); dis.fire(Action.FocusComposer, true);
} }
}; };
@ -496,7 +497,7 @@ class LoggedInView extends React.PureComponent<IProps, IState> {
if (!isClickShortcut && ev.key !== Key.TAB && !canElementReceiveInput(ev.target)) { if (!isClickShortcut && ev.key !== Key.TAB && !canElementReceiveInput(ev.target)) {
// synchronous dispatch so we focus before key generates input // synchronous dispatch so we focus before key generates input
dis.dispatch({action: 'focus_composer'}, true); dis.fire(Action.FocusComposer, true);
ev.stopPropagation(); ev.stopPropagation();
// we should *not* preventDefault() here as // we should *not* preventDefault() here as
// that would prevent typing in the now-focussed composer // that would prevent typing in the now-focussed composer

View File

@ -347,7 +347,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
Analytics.trackPageChange(durationMs); Analytics.trackPageChange(durationMs);
} }
if (this.focusComposer) { if (this.focusComposer) {
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
this.focusComposer = false; this.focusComposer = false;
} }
} }
@ -1363,7 +1363,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
showNotificationsToast(); showNotificationsToast();
} }
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
this.setState({ this.setState({
ready: true, ready: true,
}); });

View File

@ -27,6 +27,7 @@ import Resend from '../../Resend';
import * as cryptodevices from '../../cryptodevices'; import * as cryptodevices from '../../cryptodevices';
import dis from '../../dispatcher/dispatcher'; import dis from '../../dispatcher/dispatcher';
import {messageForResourceLimitError, messageForSendError} from '../../utils/ErrorUtils'; import {messageForResourceLimitError, messageForSendError} from '../../utils/ErrorUtils';
import {Action} from "../../dispatcher/actions";
const STATUS_BAR_HIDDEN = 0; const STATUS_BAR_HIDDEN = 0;
const STATUS_BAR_EXPANDED = 1; const STATUS_BAR_EXPANDED = 1;
@ -135,12 +136,12 @@ export default createReactClass({
_onResendAllClick: function() { _onResendAllClick: function() {
Resend.resendUnsentEvents(this.props.room); Resend.resendUnsentEvents(this.props.room);
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
}, },
_onCancelAllClick: function() { _onCancelAllClick: function() {
Resend.cancelUnsentEvents(this.props.room); Resend.cancelUnsentEvents(this.props.room);
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
}, },
_onShowDevicesClick: function() { _onShowDevicesClick: function() {

View File

@ -55,6 +55,7 @@ import {haveTileForEvent} from "../views/rooms/EventTile";
import RoomContext from "../../contexts/RoomContext"; import RoomContext from "../../contexts/RoomContext";
import MatrixClientContext from "../../contexts/MatrixClientContext"; import MatrixClientContext from "../../contexts/MatrixClientContext";
import { shieldStatusForRoom } from '../../utils/ShieldUtils'; import { shieldStatusForRoom } from '../../utils/ShieldUtils';
import {Action} from "../../dispatcher/actions";
const DEBUG = false; const DEBUG = false;
let debuglog = function() {}; let debuglog = function() {};
@ -1171,7 +1172,7 @@ export default createReactClass({
ev.dataTransfer.files, this.state.room.roomId, this.context, ev.dataTransfer.files, this.state.room.roomId, this.context,
); );
this.setState({ draggingFile: false }); this.setState({ draggingFile: false });
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
}, },
onDragLeaveOrEnd: function(ev) { onDragLeaveOrEnd: function(ev) {
@ -1377,7 +1378,7 @@ export default createReactClass({
event: null, event: null,
}); });
} }
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
}, },
onLeaveClick: function() { onLeaveClick: function() {
@ -1488,7 +1489,7 @@ export default createReactClass({
// jump down to the bottom of this room, where new events are arriving // jump down to the bottom of this room, where new events are arriving
jumpToLiveTimeline: function() { jumpToLiveTimeline: function() {
this._messagePanel.jumpToLiveTimeline(); this._messagePanel.jumpToLiveTimeline();
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
}, },
// jump up to wherever our read marker is // jump up to wherever our read marker is

View File

@ -26,6 +26,7 @@ import {makeUserPermalink, RoomPermalinkCreator} from "../../../utils/permalinks
import SettingsStore from "../../../settings/SettingsStore"; import SettingsStore from "../../../settings/SettingsStore";
import escapeHtml from "escape-html"; import escapeHtml from "escape-html";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {Action} from "../../../dispatcher/actions";
// This component does no cycle detection, simply because the only way to make such a cycle would be to // This component does no cycle detection, simply because the only way to make such a cycle would be to
// craft event_id's, using a homeserver that generates predictable event IDs; even then the impact would // craft event_id's, using a homeserver that generates predictable event IDs; even then the impact would
@ -290,7 +291,7 @@ export default class ReplyThread extends React.Component {
events, events,
}, this.loadNextEvent); }, this.loadNextEvent);
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
} }
render() { render() {

View File

@ -31,6 +31,7 @@ import {EventStatus} from 'matrix-js-sdk';
import BasicMessageComposer from "./BasicMessageComposer"; import BasicMessageComposer from "./BasicMessageComposer";
import {Key} from "../../../Keyboard"; import {Key} from "../../../Keyboard";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {Action} from "../../../dispatcher/actions";
function _isReply(mxEvent) { function _isReply(mxEvent) {
const relatesTo = mxEvent.getContent()["m.relates_to"]; const relatesTo = mxEvent.getContent()["m.relates_to"];
@ -157,7 +158,7 @@ export default class EditMessageComposer extends React.Component {
dis.dispatch({action: 'edit_event', event: nextEvent}); dis.dispatch({action: 'edit_event', event: nextEvent});
} else { } else {
dis.dispatch({action: 'edit_event', event: null}); dis.dispatch({action: 'edit_event', event: null});
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
} }
event.preventDefault(); event.preventDefault();
} }
@ -165,7 +166,7 @@ export default class EditMessageComposer extends React.Component {
_cancelEdit = () => { _cancelEdit = () => {
dis.dispatch({action: "edit_event", event: null}); dis.dispatch({action: "edit_event", event: null});
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
} }
_isContentModified(newContent) { _isContentModified(newContent) {
@ -195,7 +196,7 @@ export default class EditMessageComposer extends React.Component {
// close the event editing and focus composer // close the event editing and focus composer
dis.dispatch({action: "edit_event", event: null}); dis.dispatch({action: "edit_event", event: null});
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
}; };
_cancelPreviousPendingEdit() { _cancelPreviousPendingEdit() {

View File

@ -44,6 +44,7 @@ import {Key} from "../../../Keyboard";
import MatrixClientContext from "../../../contexts/MatrixClientContext"; import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {MatrixClientPeg} from "../../../MatrixClientPeg"; import {MatrixClientPeg} from "../../../MatrixClientPeg";
import RateLimitedFunc from '../../../ratelimitedfunc'; import RateLimitedFunc from '../../../ratelimitedfunc';
import {Action} from "../../../dispatcher/actions";
function addReplyToMessageContent(content, repliedToEvent, permalinkCreator) { function addReplyToMessageContent(content, repliedToEvent, permalinkCreator) {
const replyContent = ReplyThread.makeReplyMixIn(repliedToEvent); const replyContent = ReplyThread.makeReplyMixIn(repliedToEvent);
@ -364,7 +365,7 @@ export default class SendMessageComposer extends React.Component {
onAction = (payload) => { onAction = (payload) => {
switch (payload.action) { switch (payload.action) {
case 'reply_to_event': case 'reply_to_event':
case 'focus_composer': case Action.FocusComposer:
this._editorRef && this._editorRef.focus(); this._editorRef && this._editorRef.focus();
break; break;
case 'insert_mention': case 'insert_mention':

View File

@ -19,6 +19,7 @@ import * as sdk from './index';
import dis from './dispatcher/dispatcher'; import dis from './dispatcher/dispatcher';
import Modal from './Modal'; import Modal from './Modal';
import { _t } from './languageHandler'; import { _t } from './languageHandler';
import {Action} from "./dispatcher/actions";
/** /**
* Mark all given devices as 'known' * Mark all given devices as 'known'
@ -66,7 +67,7 @@ export async function getUnknownDevicesForRoom(matrixClient, room) {
} }
function focusComposer() { function focusComposer() {
dis.dispatch({action: 'focus_composer'}); dis.fire(Action.FocusComposer);
} }
/** /**

View File

@ -53,4 +53,9 @@ export enum Action {
* Provide status information for an ongoing update check. Should be used with a CheckUpdatesPayload. * Provide status information for an ongoing update check. Should be used with a CheckUpdatesPayload.
*/ */
CheckUpdates = "check_updates", CheckUpdates = "check_updates",
/**
* Focuses the user's cursor to the composer. No additional payload information required.
*/
FocusComposer = "focus_composer",
} }