Merge pull request #3392 from matrix-org/bwindels/cider-paste-plain

New composer: fix pasting from word processors
This commit is contained in:
Bruno Windels 2019-09-06 09:22:37 +00:00 committed by GitHub
commit df4762871a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 32 additions and 5 deletions

View file

@ -25,10 +25,12 @@ import {
formatRangeAsQuote, formatRangeAsQuote,
formatRangeAsCode, formatRangeAsCode,
formatInline, formatInline,
replaceRangeAndMoveCaret,
} from '../../../editor/operations'; } from '../../../editor/operations';
import {getCaretOffsetAndText, getRangeForSelection} from '../../../editor/dom'; import {getCaretOffsetAndText, getRangeForSelection} from '../../../editor/dom';
import Autocomplete from '../rooms/Autocomplete'; import Autocomplete from '../rooms/Autocomplete';
import {autoCompleteCreator} from '../../../editor/parts'; import {autoCompleteCreator} from '../../../editor/parts';
import {parsePlainTextMessage} from '../../../editor/deserialize';
import {renderModel} from '../../../editor/render'; import {renderModel} from '../../../editor/render';
import {Room} from 'matrix-js-sdk'; import {Room} from 'matrix-js-sdk';
import TypingStore from "../../../stores/TypingStore"; import TypingStore from "../../../stores/TypingStore";
@ -172,6 +174,18 @@ export default class BasicMessageEditor extends React.Component {
this._onInput({inputType: "insertCompositionText"}); this._onInput({inputType: "insertCompositionText"});
} }
_onPaste = (event) => {
const {model} = this.props;
const {partCreator} = model;
const text = event.clipboardData.getData("text/plain");
if (text) {
const range = getRangeForSelection(this._editorRef, model, document.getSelection());
const parts = parsePlainTextMessage(text, partCreator);
replaceRangeAndMoveCaret(range, parts);
event.preventDefault();
}
}
_onInput = (event) => { _onInput = (event) => {
// ignore any input while doing IME compositions // ignore any input while doing IME compositions
if (this._isIMEComposing) { if (this._isIMEComposing) {
@ -495,6 +509,7 @@ export default class BasicMessageEditor extends React.Component {
tabIndex="1" tabIndex="1"
onBlur={this._onBlur} onBlur={this._onBlur}
onFocus={this._onFocus} onFocus={this._onFocus}
onPaste={this._onPaste}
onKeyDown={this._onKeyDown} onKeyDown={this._onKeyDown}
ref={ref => this._editorRef = ref} ref={ref => this._editorRef = ref}
aria-label={this.props.label} aria-label={this.props.label}

View file

@ -232,7 +232,7 @@ function parseHtmlMessage(html, partCreator, isQuotedMessage) {
return parts; return parts;
} }
function parsePlainTextMessage(body, partCreator, isQuotedMessage) { export function parsePlainTextMessage(body, partCreator, isQuotedMessage) {
const lines = body.split("\n"); const lines = body.split("\n");
const parts = lines.reduce((parts, line, i) => { const parts = lines.reduce((parts, line, i) => {
if (isQuotedMessage) { if (isQuotedMessage) {

View file

@ -18,7 +18,8 @@ limitations under the License.
* Some common queries and transformations on the editor model * Some common queries and transformations on the editor model
*/ */
export function replaceRangeAndExpandSelection(model, range, newParts) { export function replaceRangeAndExpandSelection(range, newParts) {
const {model} = range;
model.transform(() => { model.transform(() => {
const oldLen = range.length; const oldLen = range.length;
const addedLen = range.replace(newParts); const addedLen = range.replace(newParts);
@ -28,6 +29,17 @@ export function replaceRangeAndExpandSelection(model, range, newParts) {
}); });
} }
export function replaceRangeAndMoveCaret(range, newParts) {
const {model} = range;
model.transform(() => {
const oldLen = range.length;
const addedLen = range.replace(newParts);
const firstOffset = range.start.asOffset(model);
const lastOffset = firstOffset.add(oldLen + addedLen);
return lastOffset.asPosition(model);
});
}
export function rangeStartsAtBeginningOfLine(range) { export function rangeStartsAtBeginningOfLine(range) {
const {model} = range; const {model} = range;
const startsWithPartial = range.start.offset !== 0; const startsWithPartial = range.start.offset !== 0;
@ -63,7 +75,7 @@ export function formatRangeAsQuote(range) {
} }
parts.push(partCreator.newline()); parts.push(partCreator.newline());
replaceRangeAndExpandSelection(model, range, parts); replaceRangeAndExpandSelection(range, parts);
} }
export function formatRangeAsCode(range) { export function formatRangeAsCode(range) {
@ -85,7 +97,7 @@ export function formatRangeAsCode(range) {
parts.unshift(partCreator.plain("`")); parts.unshift(partCreator.plain("`"));
parts.push(partCreator.plain("`")); parts.push(partCreator.plain("`"));
} }
replaceRangeAndExpandSelection(model, range, parts); replaceRangeAndExpandSelection(range, parts);
} }
export function formatInline(range, prefix, suffix = prefix) { export function formatInline(range, prefix, suffix = prefix) {
@ -93,5 +105,5 @@ export function formatInline(range, prefix, suffix = prefix) {
const {partCreator} = model; const {partCreator} = model;
parts.unshift(partCreator.plain(prefix)); parts.unshift(partCreator.plain(prefix));
parts.push(partCreator.plain(suffix)); parts.push(partCreator.plain(suffix));
replaceRangeAndExpandSelection(model, range, parts); replaceRangeAndExpandSelection(range, parts);
} }