Apply prettier formatting
This commit is contained in:
parent
1cac306093
commit
526645c791
1576 changed files with 65385 additions and 62478 deletions
|
@ -14,23 +14,27 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import classNames from 'classnames';
|
||||
import React, { createRef, ClipboardEvent } from 'react';
|
||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||
import EMOTICON_REGEX from 'emojibase-regex/emoticon';
|
||||
import classNames from "classnames";
|
||||
import React, { createRef, ClipboardEvent } from "react";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
import EMOTICON_REGEX from "emojibase-regex/emoticon";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import EditorModel from '../../../editor/model';
|
||||
import HistoryManager from '../../../editor/history';
|
||||
import { Caret, setSelection } from '../../../editor/caret';
|
||||
import { formatRange, formatRangeAsLink, replaceRangeAndMoveCaret, toggleInlineFormat }
|
||||
from '../../../editor/operations';
|
||||
import { getCaretOffsetAndText, getRangeForSelection } from '../../../editor/dom';
|
||||
import Autocomplete, { generateCompletionDomId } from '../rooms/Autocomplete';
|
||||
import { getAutoCompleteCreator, Part, Type } from '../../../editor/parts';
|
||||
import { parseEvent, parsePlainTextMessage } from '../../../editor/deserialize';
|
||||
import { renderModel } from '../../../editor/render';
|
||||
import EditorModel from "../../../editor/model";
|
||||
import HistoryManager from "../../../editor/history";
|
||||
import { Caret, setSelection } from "../../../editor/caret";
|
||||
import {
|
||||
formatRange,
|
||||
formatRangeAsLink,
|
||||
replaceRangeAndMoveCaret,
|
||||
toggleInlineFormat,
|
||||
} from "../../../editor/operations";
|
||||
import { getCaretOffsetAndText, getRangeForSelection } from "../../../editor/dom";
|
||||
import Autocomplete, { generateCompletionDomId } from "../rooms/Autocomplete";
|
||||
import { getAutoCompleteCreator, Part, Type } from "../../../editor/parts";
|
||||
import { parseEvent, parsePlainTextMessage } from "../../../editor/deserialize";
|
||||
import { renderModel } from "../../../editor/render";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { IS_MAC, Key } from "../../../Keyboard";
|
||||
import { EMOTICON_TO_EMOJI } from "../../../emoji";
|
||||
|
@ -40,19 +44,19 @@ import MessageComposerFormatBar, { Formatting } from "./MessageComposerFormatBar
|
|||
import DocumentOffset from "../../../editor/offset";
|
||||
import { IDiff } from "../../../editor/diff";
|
||||
import AutocompleteWrapperModel from "../../../editor/autocomplete";
|
||||
import DocumentPosition from '../../../editor/position';
|
||||
import DocumentPosition from "../../../editor/position";
|
||||
import { ICompletion } from "../../../autocomplete/Autocompleter";
|
||||
import { getKeyBindingsManager } from '../../../KeyBindingsManager';
|
||||
import { ALTERNATE_KEY_NAME, KeyBindingAction } from '../../../accessibility/KeyboardShortcuts';
|
||||
import { getKeyBindingsManager } from "../../../KeyBindingsManager";
|
||||
import { ALTERNATE_KEY_NAME, KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { linkify } from '../../../linkify-matrix';
|
||||
import { SdkContextClass } from '../../../contexts/SDKContext';
|
||||
import { linkify } from "../../../linkify-matrix";
|
||||
import { SdkContextClass } from "../../../contexts/SDKContext";
|
||||
|
||||
// matches emoticons which follow the start of a line or whitespace
|
||||
const REGEX_EMOTICON_WHITESPACE = new RegExp('(?:^|\\s)(' + EMOTICON_REGEX.source + ')\\s|:^$');
|
||||
export const REGEX_EMOTICON = new RegExp('(?:^|\\s)(' + EMOTICON_REGEX.source + ')$');
|
||||
const REGEX_EMOTICON_WHITESPACE = new RegExp("(?:^|\\s)(" + EMOTICON_REGEX.source + ")\\s|:^$");
|
||||
export const REGEX_EMOTICON = new RegExp("(?:^|\\s)(" + EMOTICON_REGEX.source + ")$");
|
||||
|
||||
const SURROUND_WITH_CHARACTERS = ["\"", "_", "`", "'", "*", "~", "$"];
|
||||
const SURROUND_WITH_CHARACTERS = ['"', "_", "`", "'", "*", "~", "$"];
|
||||
const SURROUND_WITH_DOUBLE_CHARACTERS = new Map([
|
||||
["(", ")"],
|
||||
["[", "]"],
|
||||
|
@ -61,10 +65,13 @@ const SURROUND_WITH_DOUBLE_CHARACTERS = new Map([
|
|||
]);
|
||||
|
||||
function ctrlShortcutLabel(key: string, needsShift = false, needsAlt = false): string {
|
||||
return (IS_MAC ? "⌘" : _t(ALTERNATE_KEY_NAME[Key.CONTROL])) +
|
||||
(needsShift ? ("+" + _t(ALTERNATE_KEY_NAME[Key.SHIFT])) : "") +
|
||||
(needsAlt ? ("+" + _t(ALTERNATE_KEY_NAME[Key.ALT])) : "") +
|
||||
"+" + key;
|
||||
return (
|
||||
(IS_MAC ? "⌘" : _t(ALTERNATE_KEY_NAME[Key.CONTROL])) +
|
||||
(needsShift ? "+" + _t(ALTERNATE_KEY_NAME[Key.SHIFT]) : "") +
|
||||
(needsAlt ? "+" + _t(ALTERNATE_KEY_NAME[Key.ALT]) : "") +
|
||||
"+" +
|
||||
key
|
||||
);
|
||||
}
|
||||
|
||||
function cloneSelection(selection: Selection): Partial<Selection> {
|
||||
|
@ -80,13 +87,15 @@ function cloneSelection(selection: Selection): Partial<Selection> {
|
|||
}
|
||||
|
||||
function selectionEquals(a: Partial<Selection>, b: Selection): boolean {
|
||||
return a.anchorNode === b.anchorNode &&
|
||||
return (
|
||||
a.anchorNode === b.anchorNode &&
|
||||
a.anchorOffset === b.anchorOffset &&
|
||||
a.focusNode === b.focusNode &&
|
||||
a.focusOffset === b.focusOffset &&
|
||||
a.isCollapsed === b.isCollapsed &&
|
||||
a.rangeCount === b.rangeCount &&
|
||||
a.type === b.type;
|
||||
a.type === b.type
|
||||
);
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
|
@ -140,15 +149,27 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
showVisualBell: false,
|
||||
};
|
||||
|
||||
this.useMarkdownHandle = SettingsStore.watchSetting('MessageComposerInput.useMarkdown', null,
|
||||
this.configureUseMarkdown);
|
||||
this.emoticonSettingHandle = SettingsStore.watchSetting('MessageComposerInput.autoReplaceEmoji', null,
|
||||
this.configureEmoticonAutoReplace);
|
||||
this.useMarkdownHandle = SettingsStore.watchSetting(
|
||||
"MessageComposerInput.useMarkdown",
|
||||
null,
|
||||
this.configureUseMarkdown,
|
||||
);
|
||||
this.emoticonSettingHandle = SettingsStore.watchSetting(
|
||||
"MessageComposerInput.autoReplaceEmoji",
|
||||
null,
|
||||
this.configureEmoticonAutoReplace,
|
||||
);
|
||||
this.configureEmoticonAutoReplace();
|
||||
this.shouldShowPillAvatarSettingHandle = SettingsStore.watchSetting("Pill.shouldShowPillAvatar", null,
|
||||
this.configureShouldShowPillAvatar);
|
||||
this.surroundWithHandle = SettingsStore.watchSetting("MessageComposerInput.surroundWith", null,
|
||||
this.surroundWithSettingChanged);
|
||||
this.shouldShowPillAvatarSettingHandle = SettingsStore.watchSetting(
|
||||
"Pill.shouldShowPillAvatar",
|
||||
null,
|
||||
this.configureShouldShowPillAvatar,
|
||||
);
|
||||
this.surroundWithHandle = SettingsStore.watchSetting(
|
||||
"MessageComposerInput.surroundWith",
|
||||
null,
|
||||
this.surroundWithSettingChanged,
|
||||
);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: IProps) {
|
||||
|
@ -208,7 +229,8 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
|
||||
private updateEditorState = (selection: Caret, inputType?: string, diff?: IDiff): void => {
|
||||
renderModel(this.editorRef.current, this.props.model);
|
||||
if (selection) { // set the caret/selection
|
||||
if (selection) {
|
||||
// set the caret/selection
|
||||
try {
|
||||
setSelection(this.editorRef.current, this.props.model, selection);
|
||||
} catch (err) {
|
||||
|
@ -246,11 +268,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
isTyping = false;
|
||||
}
|
||||
}
|
||||
SdkContextClass.instance.typingStore.setSelfTyping(
|
||||
this.props.room.roomId,
|
||||
this.props.threadId,
|
||||
isTyping,
|
||||
);
|
||||
SdkContextClass.instance.typingStore.setSelfTyping(this.props.room.roomId, this.props.threadId, isTyping);
|
||||
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange();
|
||||
|
@ -259,7 +277,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
|
||||
private showPlaceholder(): void {
|
||||
// escape single quotes
|
||||
const placeholder = this.props.placeholder.replace(/'/g, '\\\'');
|
||||
const placeholder = this.props.placeholder.replace(/'/g, "\\'");
|
||||
this.editorRef.current.style.setProperty("--placeholder", `'${placeholder}'`);
|
||||
this.editorRef.current.classList.add("mx_BasicMessageComposer_inputEmpty");
|
||||
}
|
||||
|
@ -287,7 +305,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
// however, doing this async seems to break things in Safari for some reason, so browser sniff.
|
||||
|
||||
const ua = navigator.userAgent.toLowerCase();
|
||||
const isSafari = ua.includes('safari/') && !ua.includes('chrome/');
|
||||
const isSafari = ua.includes("safari/") && !ua.includes("chrome/");
|
||||
|
||||
if (isSafari) {
|
||||
this.onInput({ inputType: "insertCompositionText" });
|
||||
|
@ -311,7 +329,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
if (text) {
|
||||
const { model } = this.props;
|
||||
const range = getRangeForSelection(this.editorRef.current, model, selection);
|
||||
const selectedParts = range.parts.map(p => p.serialize());
|
||||
const selectedParts = range.parts.map((p) => p.serialize());
|
||||
event.clipboardData.setData("application/x-element-composer", JSON.stringify(selectedParts));
|
||||
event.clipboardData.setData("text/plain", text); // so plain copy/paste works
|
||||
if (type === "cut") {
|
||||
|
@ -346,7 +364,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
let parts: Part[];
|
||||
if (partsText) {
|
||||
const serializedTextParts = JSON.parse(partsText);
|
||||
parts = serializedTextParts.map(p => partCreator.deserializePart(p));
|
||||
parts = serializedTextParts.map((p) => partCreator.deserializePart(p));
|
||||
} else {
|
||||
parts = parsePlainTextMessage(plainText, partCreator, { shouldEscape: false });
|
||||
}
|
||||
|
@ -593,16 +611,16 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
|
||||
private async tabCompleteName(): Promise<void> {
|
||||
try {
|
||||
await new Promise<void>(resolve => this.setState({ showVisualBell: false }, resolve));
|
||||
await new Promise<void>((resolve) => this.setState({ showVisualBell: false }, resolve));
|
||||
const { model } = this.props;
|
||||
const caret = this.getCaret();
|
||||
const position = model.positionForOffset(caret.offset, caret.atNodeEnd);
|
||||
const range = model.startRange(position);
|
||||
range.expandBackwardsWhile((index, offset, part) => {
|
||||
return part.text[offset] !== " " && part.text[offset] !== "+" && (
|
||||
part.type === Type.Plain ||
|
||||
part.type === Type.PillCandidate ||
|
||||
part.type === Type.Command
|
||||
return (
|
||||
part.text[offset] !== " " &&
|
||||
part.text[offset] !== "+" &&
|
||||
(part.type === Type.Plain || part.type === Type.PillCandidate || part.type === Type.Command)
|
||||
);
|
||||
});
|
||||
const { partCreator } = model;
|
||||
|
@ -664,7 +682,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
};
|
||||
|
||||
private transform = (documentPosition: DocumentPosition): void => {
|
||||
const shouldReplace = SettingsStore.getValue('MessageComposerInput.autoReplaceEmoji');
|
||||
const shouldReplace = SettingsStore.getValue("MessageComposerInput.autoReplaceEmoji");
|
||||
if (shouldReplace) this.replaceEmoticon(documentPosition, REGEX_EMOTICON_WHITESPACE);
|
||||
};
|
||||
|
||||
|
@ -685,10 +703,12 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
const partCreator = model.partCreator;
|
||||
// TODO: does this allow us to get rid of EditorStateTransfer?
|
||||
// not really, but we could not serialize the parts, and just change the autoCompleter
|
||||
partCreator.setAutoCompleteCreator(getAutoCompleteCreator(
|
||||
() => this.autocompleteRef.current,
|
||||
query => new Promise(resolve => this.setState({ query }, resolve)),
|
||||
));
|
||||
partCreator.setAutoCompleteCreator(
|
||||
getAutoCompleteCreator(
|
||||
() => this.autocompleteRef.current,
|
||||
(query) => new Promise((resolve) => this.setState({ query }, resolve)),
|
||||
),
|
||||
);
|
||||
// initial render of model
|
||||
this.updateEditorState(this.getInitialCaretPosition());
|
||||
// attach input listener by hand so React doesn't proxy the events,
|
||||
|
@ -731,23 +751,25 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
if (this.state.autoComplete) {
|
||||
const query = this.state.query;
|
||||
const queryLen = query.length;
|
||||
autoComplete = (<div className="mx_BasicMessageComposer_AutoCompleteWrapper">
|
||||
<Autocomplete
|
||||
ref={this.autocompleteRef}
|
||||
query={query}
|
||||
onConfirm={this.onAutoCompleteConfirm}
|
||||
onSelectionChange={this.onAutoCompleteSelectionChange}
|
||||
selection={{ beginning: true, end: queryLen, start: queryLen }}
|
||||
room={this.props.room}
|
||||
/>
|
||||
</div>);
|
||||
autoComplete = (
|
||||
<div className="mx_BasicMessageComposer_AutoCompleteWrapper">
|
||||
<Autocomplete
|
||||
ref={this.autocompleteRef}
|
||||
query={query}
|
||||
onConfirm={this.onAutoCompleteConfirm}
|
||||
onSelectionChange={this.onAutoCompleteSelectionChange}
|
||||
selection={{ beginning: true, end: queryLen, start: queryLen }}
|
||||
room={this.props.room}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
const wrapperClasses = classNames("mx_BasicMessageComposer", {
|
||||
"mx_BasicMessageComposer_input_error": this.state.showVisualBell,
|
||||
mx_BasicMessageComposer_input_error: this.state.showVisualBell,
|
||||
});
|
||||
const classes = classNames("mx_BasicMessageComposer_input", {
|
||||
"mx_BasicMessageComposer_input_shouldShowPillAvatar": this.state.showPillAvatar,
|
||||
"mx_BasicMessageComposer_input_disabled": this.props.disabled,
|
||||
mx_BasicMessageComposer_input_shouldShowPillAvatar: this.state.showPillAvatar,
|
||||
mx_BasicMessageComposer_input_disabled: this.props.disabled,
|
||||
});
|
||||
|
||||
const shortcuts = {
|
||||
|
@ -765,33 +787,39 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
activeDescendant = generateCompletionDomId(completionIndex);
|
||||
}
|
||||
|
||||
return (<div className={wrapperClasses}>
|
||||
{ autoComplete }
|
||||
<MessageComposerFormatBar ref={this.formatBarRef} onAction={this.onFormatAction} shortcuts={shortcuts} />
|
||||
<div
|
||||
className={classes}
|
||||
contentEditable={this.props.disabled ? null : true}
|
||||
tabIndex={0}
|
||||
onBlur={this.onBlur}
|
||||
onFocus={this.onFocus}
|
||||
onCopy={this.onCopy}
|
||||
onCut={this.onCut}
|
||||
onPaste={this.onPaste}
|
||||
onKeyDown={this.onKeyDown}
|
||||
ref={this.editorRef}
|
||||
aria-label={this.props.label}
|
||||
role="textbox"
|
||||
aria-multiline="true"
|
||||
aria-autocomplete="list"
|
||||
aria-haspopup="listbox"
|
||||
aria-expanded={hasAutocomplete ? true : undefined}
|
||||
aria-owns={hasAutocomplete ? "mx_Autocomplete" : undefined}
|
||||
aria-activedescendant={activeDescendant}
|
||||
dir="auto"
|
||||
aria-disabled={this.props.disabled}
|
||||
data-testid="basicmessagecomposer"
|
||||
/>
|
||||
</div>);
|
||||
return (
|
||||
<div className={wrapperClasses}>
|
||||
{autoComplete}
|
||||
<MessageComposerFormatBar
|
||||
ref={this.formatBarRef}
|
||||
onAction={this.onFormatAction}
|
||||
shortcuts={shortcuts}
|
||||
/>
|
||||
<div
|
||||
className={classes}
|
||||
contentEditable={this.props.disabled ? null : true}
|
||||
tabIndex={0}
|
||||
onBlur={this.onBlur}
|
||||
onFocus={this.onFocus}
|
||||
onCopy={this.onCopy}
|
||||
onCut={this.onCut}
|
||||
onPaste={this.onPaste}
|
||||
onKeyDown={this.onKeyDown}
|
||||
ref={this.editorRef}
|
||||
aria-label={this.props.label}
|
||||
role="textbox"
|
||||
aria-multiline="true"
|
||||
aria-autocomplete="list"
|
||||
aria-haspopup="listbox"
|
||||
aria-expanded={hasAutocomplete ? true : undefined}
|
||||
aria-owns={hasAutocomplete ? "mx_Autocomplete" : undefined}
|
||||
aria-activedescendant={activeDescendant}
|
||||
dir="auto"
|
||||
aria-disabled={this.props.disabled}
|
||||
data-testid="basicmessagecomposer"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public focus(): void {
|
||||
|
@ -803,8 +831,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
const { model } = this.props;
|
||||
const { partCreator } = model;
|
||||
const member = this.props.room.getMember(userId);
|
||||
const displayName = member ?
|
||||
member.rawDisplayName : userId;
|
||||
const displayName = member ? member.rawDisplayName : userId;
|
||||
const caret = this.getCaret();
|
||||
const position = model.positionForOffset(caret.offset, caret.atNodeEnd);
|
||||
// Insert suffix only if the caret is at the start of the composer
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue