diff --git a/src/components/views/rooms/BasicMessageComposer.js b/src/components/views/rooms/BasicMessageComposer.js index 2b4693646a..99e7b8ea07 100644 --- a/src/components/views/rooms/BasicMessageComposer.js +++ b/src/components/views/rooms/BasicMessageComposer.js @@ -24,7 +24,7 @@ import {setSelection} from '../../../editor/caret'; import { formatRangeAsQuote, formatRangeAsCode, - formatInline, + toggleInlineFormat, replaceRangeAndMoveCaret, } from '../../../editor/operations'; import {getCaretOffsetAndText, getRangeForSelection} from '../../../editor/dom'; @@ -457,13 +457,13 @@ export default class BasicMessageEditor extends React.Component { this.historyManager.ensureLastChangesPushed(this.props.model); switch (action) { case "bold": - formatInline(range, "**"); + toggleInlineFormat(range, "**"); break; case "italics": - formatInline(range, "*"); + toggleInlineFormat(range, "*"); break; case "strikethrough": - formatInline(range, "", ""); + toggleInlineFormat(range, "", ""); break; case "code": formatRangeAsCode(range); diff --git a/src/editor/operations.js b/src/editor/operations.js index 4645e7d805..e2661faf59 100644 --- a/src/editor/operations.js +++ b/src/editor/operations.js @@ -100,10 +100,27 @@ export function formatRangeAsCode(range) { replaceRangeAndExpandSelection(range, parts); } -export function formatInline(range, prefix, suffix = prefix) { +export function toggleInlineFormat(range, prefix, suffix = prefix) { const {model, parts} = range; const {partCreator} = model; - parts.unshift(partCreator.plain(prefix)); - parts.push(partCreator.plain(suffix)); + + const isFormatted = parts.length && + parts[0].text.startsWith(prefix) && + parts[parts.length - 1].text.endsWith(suffix); + + if (isFormatted) { + // remove prefix and suffix + const partWithoutPrefix = parts[0].serialize(); + partWithoutPrefix.text = partWithoutPrefix.text.substr(prefix.length); + parts[0] = partCreator.deserializePart(partWithoutPrefix); + + const partWithoutSuffix = parts[parts.length - 1].serialize(); + const suffixPartText = partWithoutSuffix.text; + partWithoutSuffix.text = suffixPartText.substring(0, suffixPartText.length - suffix.length); + parts[parts.length - 1] = partCreator.deserializePart(partWithoutSuffix); + } else { + parts.unshift(partCreator.plain(prefix)); + parts.push(partCreator.plain(suffix)); + } replaceRangeAndExpandSelection(range, parts); }