Merge pull request #5510 from SimonBrandner/feature-surround-with

Add surround with feature
This commit is contained in:
Michael Telatynski 2021-08-05 09:33:52 +01:00 committed by GitHub
commit 58575c335d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 0 deletions

View file

@ -55,6 +55,14 @@ const REGEX_EMOTICON_WHITESPACE = new RegExp('(?:^|\\s)(' + EMOTICON_REGEX.sourc
const IS_MAC = navigator.platform.indexOf("Mac") !== -1;
const SURROUND_WITH_CHARACTERS = ["\"", "_", "`", "'", "*", "~", "$"];
const SURROUND_WITH_DOUBLE_CHARACTERS = new Map([
["(", ")"],
["[", "]"],
["{", "}"],
["<", ">"],
]);
function ctrlShortcutLabel(key: string): string {
return (IS_MAC ? "⌘" : "Ctrl") + "+" + key;
}
@ -99,6 +107,7 @@ interface IState {
showVisualBell?: boolean;
autoComplete?: AutocompleteWrapperModel;
completionIndex?: number;
surroundWith: boolean;
}
@replaceableComponent("views.rooms.BasicMessageEditor")
@ -117,12 +126,14 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
private readonly emoticonSettingHandle: string;
private readonly shouldShowPillAvatarSettingHandle: string;
private readonly surroundWithHandle: string;
private readonly historyManager = new HistoryManager();
constructor(props) {
super(props);
this.state = {
showPillAvatar: SettingsStore.getValue("Pill.shouldShowPillAvatar"),
surroundWith: SettingsStore.getValue("MessageComposerInput.surroundWith"),
};
this.emoticonSettingHandle = SettingsStore.watchSetting('MessageComposerInput.autoReplaceEmoji', null,
@ -130,6 +141,8 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
this.configureEmoticonAutoReplace();
this.shouldShowPillAvatarSettingHandle = SettingsStore.watchSetting("Pill.shouldShowPillAvatar", null,
this.configureShouldShowPillAvatar);
this.surroundWithHandle = SettingsStore.watchSetting("MessageComposerInput.surroundWith", null,
this.surroundWithSettingChanged);
}
public componentDidUpdate(prevProps: IProps) {
@ -422,6 +435,28 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
private onKeyDown = (event: React.KeyboardEvent): void => {
const model = this.props.model;
let handled = false;
if (this.state.surroundWith && document.getSelection().type != "Caret") {
// This surrounds the selected text with a character. This is
// intentionally left out of the keybinding manager as the keybinds
// here shouldn't be changeable
const selectionRange = getRangeForSelection(
this.editorRef.current,
this.props.model,
document.getSelection(),
);
// trim the range as we want it to exclude leading/trailing spaces
selectionRange.trim();
if ([...SURROUND_WITH_DOUBLE_CHARACTERS.keys(), ...SURROUND_WITH_CHARACTERS].includes(event.key)) {
this.historyManager.ensureLastChangesPushed(this.props.model);
this.modifiedFlag = true;
toggleInlineFormat(selectionRange, event.key, SURROUND_WITH_DOUBLE_CHARACTERS.get(event.key));
handled = true;
}
}
const action = getKeyBindingsManager().getMessageComposerAction(event);
switch (action) {
case MessageComposerAction.FormatBold:
@ -574,6 +609,11 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
this.setState({ showPillAvatar });
};
private surroundWithSettingChanged = () => {
const surroundWith = SettingsStore.getValue("MessageComposerInput.surroundWith");
this.setState({ surroundWith });
};
componentWillUnmount() {
document.removeEventListener("selectionchange", this.onSelectionChange);
this.editorRef.current.removeEventListener("input", this.onInput, true);
@ -581,6 +621,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
this.editorRef.current.removeEventListener("compositionend", this.onCompositionEnd, true);
SettingsStore.unwatchSetting(this.emoticonSettingHandle);
SettingsStore.unwatchSetting(this.shouldShowPillAvatarSettingHandle);
SettingsStore.unwatchSetting(this.surroundWithHandle);
}
componentDidMount() {

View file

@ -61,6 +61,7 @@ export default class PreferencesUserSettingsTab extends React.Component<{}, ISta
'MessageComposerInput.suggestEmoji',
'sendTypingNotifications',
'MessageComposerInput.ctrlEnterToSend',
'MessageComposerInput.surroundWith',
'MessageComposerInput.showStickersButton',
];

View file

@ -847,6 +847,7 @@
"Use Ctrl + F to search timeline": "Use Ctrl + F to search timeline",
"Use Command + Enter to send a message": "Use Command + Enter to send a message",
"Use Ctrl + Enter to send a message": "Use Ctrl + Enter to send a message",
"Surround selected text when typing special characters": "Surround selected text when typing special characters",
"Automatically replace plain text Emoji": "Automatically replace plain text Emoji",
"Mirror local video feed": "Mirror local video feed",
"Enable Community Filter Panel": "Enable Community Filter Panel",

View file

@ -449,6 +449,11 @@ export const SETTINGS: {[setting: string]: ISetting} = {
displayName: isMac ? _td("Use Command + Enter to send a message") : _td("Use Ctrl + Enter to send a message"),
default: false,
},
"MessageComposerInput.surroundWith": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td("Surround selected text when typing special characters"),
default: false,
},
"MessageComposerInput.autoReplaceEmoji": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Automatically replace plain text Emoji'),