Merge pull request #5858 from matrix-org/t3chguy/fix/12740
This commit is contained in:
commit
d9caa3533b
12 changed files with 243 additions and 151 deletions
|
@ -39,6 +39,7 @@ import {haveTileForEvent} from "../views/rooms/EventTile";
|
||||||
import { UIFeature } from "../../settings/UIFeature";
|
import { UIFeature } from "../../settings/UIFeature";
|
||||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import { arrayFastClone } from "../../utils/arrays";
|
import { arrayFastClone } from "../../utils/arrays";
|
||||||
|
import { Action } from "../../dispatcher/actions";
|
||||||
|
|
||||||
const PAGINATE_SIZE = 20;
|
const PAGINATE_SIZE = 20;
|
||||||
const INITIAL_SIZE = 20;
|
const INITIAL_SIZE = 20;
|
||||||
|
@ -439,10 +440,12 @@ class TimelinePanel extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
onAction = payload => {
|
onAction = payload => {
|
||||||
if (payload.action === 'ignore_state_changed') {
|
switch (payload.action) {
|
||||||
|
case "ignore_state_changed":
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
}
|
break;
|
||||||
if (payload.action === "edit_event") {
|
|
||||||
|
case "edit_event": {
|
||||||
const editState = payload.event ? new EditorStateTransfer(payload.event) : null;
|
const editState = payload.event ? new EditorStateTransfer(payload.event) : null;
|
||||||
this.setState({editState}, () => {
|
this.setState({editState}, () => {
|
||||||
if (payload.event && this._messagePanel.current) {
|
if (payload.event && this._messagePanel.current) {
|
||||||
|
@ -451,9 +454,28 @@ class TimelinePanel extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (payload.action === "scroll_to_bottom") {
|
|
||||||
|
case Action.ComposerInsert: {
|
||||||
|
// re-dispatch to the correct composer
|
||||||
|
if (this.state.editState) {
|
||||||
|
dis.dispatch({
|
||||||
|
...payload,
|
||||||
|
action: "edit_composer_insert",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dis.dispatch({
|
||||||
|
...payload,
|
||||||
|
action: "send_composer_insert",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case "scroll_to_bottom":
|
||||||
this.jumpToLiveTimeline();
|
this.jumpToLiveTimeline();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@ import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { ReadPinsEventId } from "../right_panel/PinnedMessagesCard";
|
import { ReadPinsEventId } from "../right_panel/PinnedMessagesCard";
|
||||||
import ForwardDialog from "../dialogs/ForwardDialog";
|
import ForwardDialog from "../dialogs/ForwardDialog";
|
||||||
|
import { ComposerInsertPayload } from "../../../dispatcher/payloads/ComposerInsertPayload";
|
||||||
|
import { Action } from "../../../dispatcher/actions";
|
||||||
|
|
||||||
export function canCancel(eventStatus) {
|
export function canCancel(eventStatus) {
|
||||||
return eventStatus === EventStatus.QUEUED || eventStatus === EventStatus.NOT_SENT;
|
return eventStatus === EventStatus.QUEUED || eventStatus === EventStatus.NOT_SENT;
|
||||||
|
@ -199,8 +201,8 @@ export default class MessageContextMenu extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
onQuoteClick = () => {
|
onQuoteClick = () => {
|
||||||
dis.dispatch({
|
dis.dispatch<ComposerInsertPayload>({
|
||||||
action: 'quote',
|
action: Action.ComposerInsert,
|
||||||
event: this.props.mxEvent,
|
event: this.props.mxEvent,
|
||||||
});
|
});
|
||||||
this.closeMenu();
|
this.closeMenu();
|
||||||
|
|
|
@ -37,6 +37,8 @@ import {copyPlaintext} from "../../../utils/strings";
|
||||||
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import UIStore from "../../../stores/UIStore";
|
import UIStore from "../../../stores/UIStore";
|
||||||
|
import { ComposerInsertPayload } from "../../../dispatcher/payloads/ComposerInsertPayload";
|
||||||
|
import { Action } from "../../../dispatcher/actions";
|
||||||
|
|
||||||
@replaceableComponent("views.messages.TextualBody")
|
@replaceableComponent("views.messages.TextualBody")
|
||||||
export default class TextualBody extends React.Component {
|
export default class TextualBody extends React.Component {
|
||||||
|
@ -390,9 +392,9 @@ export default class TextualBody extends React.Component {
|
||||||
|
|
||||||
onEmoteSenderClick = event => {
|
onEmoteSenderClick = event => {
|
||||||
const mxEvent = this.props.mxEvent;
|
const mxEvent = this.props.mxEvent;
|
||||||
dis.dispatch({
|
dis.dispatch<ComposerInsertPayload>({
|
||||||
action: 'insert_mention',
|
action: Action.ComposerInsert,
|
||||||
user_id: mxEvent.getSender(),
|
userId: mxEvent.getSender(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ import RoomAvatar from "../avatars/RoomAvatar";
|
||||||
import RoomName from "../elements/RoomName";
|
import RoomName from "../elements/RoomName";
|
||||||
import { mediaFromMxc } from "../../../customisations/Media";
|
import { mediaFromMxc } from "../../../customisations/Media";
|
||||||
import UIStore from "../../../stores/UIStore";
|
import UIStore from "../../../stores/UIStore";
|
||||||
|
import { ComposerInsertPayload } from "../../../dispatcher/payloads/ComposerInsertPayload";
|
||||||
|
|
||||||
export interface IDevice {
|
export interface IDevice {
|
||||||
deviceId: string;
|
deviceId: string;
|
||||||
|
@ -368,9 +369,9 @@ const UserOptionsSection: React.FC<{
|
||||||
};
|
};
|
||||||
|
|
||||||
const onInsertPillButton = function() {
|
const onInsertPillButton = function() {
|
||||||
dis.dispatch({
|
dis.dispatch<ComposerInsertPayload>({
|
||||||
action: 'insert_mention',
|
action: Action.ComposerInsert,
|
||||||
user_id: member.userId,
|
userId: member.userId,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ limitations under the License.
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { createRef, ClipboardEvent } from 'react';
|
import React, { createRef, ClipboardEvent } from 'react';
|
||||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
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 EMOTICON_REGEX from 'emojibase-regex/emoticon';
|
||||||
|
|
||||||
import EditorModel from '../../../editor/model';
|
import EditorModel from '../../../editor/model';
|
||||||
|
@ -32,7 +33,7 @@ import {
|
||||||
import { getCaretOffsetAndText, getRangeForSelection } from '../../../editor/dom';
|
import { getCaretOffsetAndText, getRangeForSelection } from '../../../editor/dom';
|
||||||
import Autocomplete, { generateCompletionDomId } from '../rooms/Autocomplete';
|
import Autocomplete, { generateCompletionDomId } from '../rooms/Autocomplete';
|
||||||
import { getAutoCompleteCreator } from '../../../editor/parts';
|
import { getAutoCompleteCreator } from '../../../editor/parts';
|
||||||
import {parsePlainTextMessage} from '../../../editor/deserialize';
|
import { parseEvent, parsePlainTextMessage } from '../../../editor/deserialize';
|
||||||
import { renderModel } from '../../../editor/render';
|
import { renderModel } from '../../../editor/render';
|
||||||
import TypingStore from "../../../stores/TypingStore";
|
import TypingStore from "../../../stores/TypingStore";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
|
@ -716,4 +717,48 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
||||||
focus() {
|
focus() {
|
||||||
this.editorRef.current.focus();
|
this.editorRef.current.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public insertMention(userId: string) {
|
||||||
|
const {model} = this.props;
|
||||||
|
const {partCreator} = model;
|
||||||
|
const member = this.props.room.getMember(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
|
||||||
|
const parts = partCreator.createMentionParts(caret.offset === 0, displayName, userId);
|
||||||
|
model.transform(() => {
|
||||||
|
const addedLen = model.insert(parts, position);
|
||||||
|
return model.positionForOffset(caret.offset + addedLen, true);
|
||||||
|
});
|
||||||
|
// refocus on composer, as we just clicked "Mention"
|
||||||
|
this.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public insertQuotedMessage(event: MatrixEvent) {
|
||||||
|
const {model} = this.props;
|
||||||
|
const {partCreator} = model;
|
||||||
|
const quoteParts = parseEvent(event, partCreator, {isQuotedMessage: true});
|
||||||
|
// add two newlines
|
||||||
|
quoteParts.push(partCreator.newline());
|
||||||
|
quoteParts.push(partCreator.newline());
|
||||||
|
model.transform(() => {
|
||||||
|
const addedLen = model.insert(quoteParts, model.positionForOffset(0));
|
||||||
|
return model.positionForOffset(addedLen, true);
|
||||||
|
});
|
||||||
|
// refocus on composer, as we just clicked "Quote"
|
||||||
|
this.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public insertPlaintext(text: string) {
|
||||||
|
const {model} = this.props;
|
||||||
|
const {partCreator} = model;
|
||||||
|
const caret = this.getCaret();
|
||||||
|
const position = model.positionForOffset(caret.offset, caret.atNodeEnd);
|
||||||
|
model.transform(() => {
|
||||||
|
const addedLen = model.insert([partCreator.plain(text)], position);
|
||||||
|
return model.positionForOffset(caret.offset + addedLen, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,6 +124,7 @@ export default class EditMessageComposer extends React.Component {
|
||||||
};
|
};
|
||||||
this._createEditorModel();
|
this._createEditorModel();
|
||||||
window.addEventListener("beforeunload", this._saveStoredEditorState);
|
window.addEventListener("beforeunload", this._saveStoredEditorState);
|
||||||
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
_setEditorRef = ref => {
|
_setEditorRef = ref => {
|
||||||
|
@ -399,6 +400,7 @@ export default class EditMessageComposer extends React.Component {
|
||||||
if (this._shouldSaveStoredEditorState) {
|
if (this._shouldSaveStoredEditorState) {
|
||||||
this._saveStoredEditorState();
|
this._saveStoredEditorState();
|
||||||
}
|
}
|
||||||
|
dis.unregister(this.dispatcherRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
_createEditorModel() {
|
_createEditorModel() {
|
||||||
|
@ -443,6 +445,18 @@ export default class EditMessageComposer extends React.Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onAction = payload => {
|
||||||
|
if (payload.action === "edit_composer_insert" && this._editorRef) {
|
||||||
|
if (payload.userId) {
|
||||||
|
this._editorRef.insertMention(payload.userId);
|
||||||
|
} else if (payload.event) {
|
||||||
|
this._editorRef.insertQuotedMessage(payload.event);
|
||||||
|
} else if (payload.text) {
|
||||||
|
this._editorRef.insertPlaintext(payload.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
return (<div className={classNames("mx_EditMessageComposer", this.props.className)} onKeyDown={this._onKeyDown}>
|
return (<div className={classNames("mx_EditMessageComposer", this.props.className)} onKeyDown={this._onKeyDown}>
|
||||||
|
|
|
@ -46,6 +46,8 @@ import { EditorStateTransfer } from "../../../utils/EditorStateTransfer";
|
||||||
import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks';
|
import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks';
|
||||||
import {StaticNotificationState} from "../../../stores/notifications/StaticNotificationState";
|
import {StaticNotificationState} from "../../../stores/notifications/StaticNotificationState";
|
||||||
import NotificationBadge from "./NotificationBadge";
|
import NotificationBadge from "./NotificationBadge";
|
||||||
|
import {ComposerInsertPayload} from "../../../dispatcher/payloads/ComposerInsertPayload";
|
||||||
|
import { Action } from '../../../dispatcher/actions';
|
||||||
|
|
||||||
const eventTileTypes = {
|
const eventTileTypes = {
|
||||||
[EventType.RoomMessage]: 'messages.MessageEvent',
|
[EventType.RoomMessage]: 'messages.MessageEvent',
|
||||||
|
@ -727,9 +729,9 @@ export default class EventTile extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
onSenderProfileClick = event => {
|
onSenderProfileClick = event => {
|
||||||
const mxEvent = this.props.mxEvent;
|
const mxEvent = this.props.mxEvent;
|
||||||
dis.dispatch({
|
dis.dispatch<ComposerInsertPayload>({
|
||||||
action: 'insert_mention',
|
action: Action.ComposerInsert,
|
||||||
user_id: mxEvent.getSender(),
|
userId: mxEvent.getSender(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ import Tooltip, {Alignment} from "../elements/Tooltip";
|
||||||
import ResizeNotifier from "../../../utils/ResizeNotifier";
|
import ResizeNotifier from "../../../utils/ResizeNotifier";
|
||||||
import { E2EStatus } from '../../../utils/ShieldUtils';
|
import { E2EStatus } from '../../../utils/ShieldUtils';
|
||||||
import SendMessageComposer from "./SendMessageComposer";
|
import SendMessageComposer from "./SendMessageComposer";
|
||||||
|
import { ComposerInsertPayload } from "../../../dispatcher/payloads/ComposerInsertPayload";
|
||||||
|
import { Action } from "../../../dispatcher/actions";
|
||||||
|
|
||||||
interface IComposerAvatarProps {
|
interface IComposerAvatarProps {
|
||||||
me: object;
|
me: object;
|
||||||
|
@ -316,10 +318,10 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addEmoji(emoji) {
|
addEmoji(emoji: string) {
|
||||||
dis.dispatch({
|
dis.dispatch<ComposerInsertPayload>({
|
||||||
action: "insert_emoji",
|
action: Action.ComposerInsert,
|
||||||
emoji,
|
text: emoji,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,6 @@ import {
|
||||||
import { CommandPartCreator } from '../../../editor/parts';
|
import { CommandPartCreator } from '../../../editor/parts';
|
||||||
import BasicMessageComposer from "./BasicMessageComposer";
|
import BasicMessageComposer from "./BasicMessageComposer";
|
||||||
import ReplyThread from "../elements/ReplyThread";
|
import ReplyThread from "../elements/ReplyThread";
|
||||||
import {parseEvent} from '../../../editor/deserialize';
|
|
||||||
import { findEditableEvent } from '../../../utils/EventUtils';
|
import { findEditableEvent } from '../../../utils/EventUtils';
|
||||||
import SendHistoryManager from "../../../SendHistoryManager";
|
import SendHistoryManager from "../../../SendHistoryManager";
|
||||||
import { CommandCategories, getCommand } from '../../../SlashCommands';
|
import { CommandCategories, getCommand } from '../../../SlashCommands';
|
||||||
|
@ -486,62 +485,18 @@ export default class SendMessageComposer extends React.Component {
|
||||||
case Action.FocusComposer:
|
case Action.FocusComposer:
|
||||||
this._editorRef && this._editorRef.focus();
|
this._editorRef && this._editorRef.focus();
|
||||||
break;
|
break;
|
||||||
case 'insert_mention':
|
case "send_composer_insert":
|
||||||
this._insertMention(payload.user_id);
|
if (payload.userId) {
|
||||||
break;
|
this._editorRef && this._editorRef.insertMention(payload.userId);
|
||||||
case 'quote':
|
} else if (payload.event) {
|
||||||
this._insertQuotedMessage(payload.event);
|
this._editorRef && this._editorRef.insertQuotedMessage(payload.event);
|
||||||
break;
|
} else if (payload.text) {
|
||||||
case 'insert_emoji':
|
this._editorRef && this._editorRef.insertPlaintext(payload.text);
|
||||||
this._insertEmoji(payload.emoji);
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_insertMention(userId) {
|
|
||||||
const {model} = this;
|
|
||||||
const {partCreator} = model;
|
|
||||||
const member = this.props.room.getMember(userId);
|
|
||||||
const displayName = member ?
|
|
||||||
member.rawDisplayName : userId;
|
|
||||||
const caret = this._editorRef.getCaret();
|
|
||||||
const position = model.positionForOffset(caret.offset, caret.atNodeEnd);
|
|
||||||
// Insert suffix only if the caret is at the start of the composer
|
|
||||||
const parts = partCreator.createMentionParts(caret.offset === 0, displayName, userId);
|
|
||||||
model.transform(() => {
|
|
||||||
const addedLen = model.insert(parts, position);
|
|
||||||
return model.positionForOffset(caret.offset + addedLen, true);
|
|
||||||
});
|
|
||||||
// refocus on composer, as we just clicked "Mention"
|
|
||||||
this._editorRef && this._editorRef.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
_insertQuotedMessage(event) {
|
|
||||||
const {model} = this;
|
|
||||||
const {partCreator} = model;
|
|
||||||
const quoteParts = parseEvent(event, partCreator, {isQuotedMessage: true});
|
|
||||||
// add two newlines
|
|
||||||
quoteParts.push(partCreator.newline());
|
|
||||||
quoteParts.push(partCreator.newline());
|
|
||||||
model.transform(() => {
|
|
||||||
const addedLen = model.insert(quoteParts, model.positionForOffset(0));
|
|
||||||
return model.positionForOffset(addedLen, true);
|
|
||||||
});
|
|
||||||
// refocus on composer, as we just clicked "Quote"
|
|
||||||
this._editorRef && this._editorRef.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
_insertEmoji = (emoji) => {
|
|
||||||
const {model} = this;
|
|
||||||
const {partCreator} = model;
|
|
||||||
const caret = this._editorRef.getCaret();
|
|
||||||
const position = model.positionForOffset(caret.offset, caret.atNodeEnd);
|
|
||||||
model.transform(() => {
|
|
||||||
const addedLen = model.insert([partCreator.plain(emoji)], position);
|
|
||||||
return model.positionForOffset(caret.offset + addedLen, true);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
_onPaste = (event) => {
|
_onPaste = (event) => {
|
||||||
const {clipboardData} = event;
|
const {clipboardData} = event;
|
||||||
// Prioritize text on the clipboard over files as Office on macOS puts a bitmap
|
// Prioritize text on the clipboard over files as Office on macOS puts a bitmap
|
||||||
|
|
|
@ -159,4 +159,9 @@ export enum Action {
|
||||||
* Fired when joining a room failed
|
* Fired when joining a room failed
|
||||||
*/
|
*/
|
||||||
JoinRoomError = "join_room_error",
|
JoinRoomError = "join_room_error",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts content into the active composer. Should be used with ComposerInsertPayload
|
||||||
|
*/
|
||||||
|
ComposerInsert = "composer_insert",
|
||||||
}
|
}
|
||||||
|
|
42
src/dispatcher/payloads/ComposerInsertPayload.ts
Normal file
42
src/dispatcher/payloads/ComposerInsertPayload.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
|
||||||
|
import { ActionPayload } from "../payloads";
|
||||||
|
import { Action } from "../actions";
|
||||||
|
|
||||||
|
interface IBaseComposerInsertPayload extends ActionPayload {
|
||||||
|
action: Action.ComposerInsert,
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IComposerInsertMentionPayload extends IBaseComposerInsertPayload {
|
||||||
|
userId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IComposerInsertQuotePayload extends IBaseComposerInsertPayload {
|
||||||
|
event: MatrixEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IComposerInsertPlaintextPayload extends IBaseComposerInsertPayload {
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ComposerInsertPayload =
|
||||||
|
IComposerInsertMentionPayload |
|
||||||
|
IComposerInsertQuotePayload |
|
||||||
|
IComposerInsertPlaintextPayload;
|
||||||
|
|
|
@ -390,7 +390,7 @@ export default class EditorModel {
|
||||||
return addLen;
|
return addLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
positionForOffset(totalOffset: number, atPartEnd: boolean) {
|
positionForOffset(totalOffset: number, atPartEnd = false) {
|
||||||
let currentOffset = 0;
|
let currentOffset = 0;
|
||||||
const index = this._parts.findIndex(part => {
|
const index = this._parts.findIndex(part => {
|
||||||
const partLen = part.text.length;
|
const partLen = part.text.length;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue