From 76bb56a2bf4b9a9da482480349c29fbe6680f52b Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 7 May 2019 16:27:09 +0200 Subject: [PATCH] initial hookup editor code with react component --- res/css/views/elements/_MessageEditor.scss | 26 +++++++++++++- .../views/elements/MessageEditor.js | 35 +++++++++++++++++-- src/editor/caret.js | 24 ++++++------- src/editor/model.js | 8 +++-- 4 files changed, 75 insertions(+), 18 deletions(-) diff --git a/res/css/views/elements/_MessageEditor.scss b/res/css/views/elements/_MessageEditor.scss index 57ae79da8c..eefb45afe5 100644 --- a/res/css/views/elements/_MessageEditor.scss +++ b/res/css/views/elements/_MessageEditor.scss @@ -17,12 +17,28 @@ limitations under the License. .mx_MessageEditor { border-radius: 4px; background-color: #f3f8fd; - padding: 10px; + padding: 11px 13px 7px 56px; .editor { border-radius: 4px; border: solid 1px #e9edf1; background-color: #ffffff; + padding: 10px; + + span { + display: inline-block; + padding: 0 5px; + border-radius: 4px; + color: white; + } + + span.user-pill { + background: red; + } + + span.room-pill { + background: green; + } } .buttons { @@ -39,4 +55,12 @@ limitations under the License. font-weight: 600; } } + + .model { + background: lightgrey; + padding: 5px; + display: block; + white-space: pre; + font-size: 12px; + } } diff --git a/src/components/views/elements/MessageEditor.js b/src/components/views/elements/MessageEditor.js index f57521dbe9..026f92238b 100644 --- a/src/components/views/elements/MessageEditor.js +++ b/src/components/views/elements/MessageEditor.js @@ -18,6 +18,9 @@ import sdk from '../../../index'; import {_t} from '../../../languageHandler'; import PropTypes from 'prop-types'; import dis from '../../../dispatcher'; +import EditorModel from '../../../editor/model'; +import {PlainPart} from '../../../editor/parts'; +import {getCaretOffset, setCaretPosition} from '../../../editor/caret'; import {MatrixEvent, MatrixClient} from 'matrix-js-sdk'; export default class MessageEditor extends React.Component { @@ -34,8 +37,24 @@ export default class MessageEditor extends React.Component { constructor(props, context) { super(props, context); - this.state = {}; + const body = this.props.event.getContent().body; + this.model = new EditorModel(); + this.model.update(body, undefined, {offset: body.length}); + this.state = { + parts: this.model.serializeParts(), + }; this._onCancelClicked = this._onCancelClicked.bind(this); + this._onInput = this._onInput.bind(this); + } + + _onInput(event) { + const editor = event.target; + const caretOffset = getCaretOffset(editor); + const caret = this.model.update(editor.textContent, event.inputType, caretOffset); + const parts = this.model.serializeParts(); + this.setState({parts}, () => { + setCaretPosition(editor, caret); + }); } _onCancelClicked() { @@ -43,14 +62,24 @@ export default class MessageEditor extends React.Component { } render() { + const parts = this.state.parts.map((p, i) => { + const key = `${i}-${p.type}`; + switch (p.type) { + case "plain": return p.text; + case "room-pill": return ({p.text}); + case "user-pill": return ({p.text}); + } + }); + const modelOutput = JSON.stringify(this.state.parts, undefined, 2); const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); return
-
- {this.props.event.getContent().body} +
+ {parts}
{_t("Cancel")}
+ {modelOutput}
; } } diff --git a/src/editor/caret.js b/src/editor/caret.js index 3b803f35c3..a252ebddc6 100644 --- a/src/editor/caret.js +++ b/src/editor/caret.js @@ -14,21 +14,21 @@ See the License for the specific language governing permissions and limitations under the License. */ -export function getCaretPosition(editor) { +export function getCaretOffset(editor) { const sel = document.getSelection(); const atNodeEnd = sel.focusOffset === sel.focusNode.textContent.length; - let position = sel.focusOffset; + let offset = sel.focusOffset; let node = sel.focusNode; // when deleting the last character of a node, // the caret gets reported as being after the focusOffset-th node, // with the focusNode being the editor if (node === editor) { - let position = 0; + let offset = 0; for (let i = 0; i < sel.focusOffset; ++i) { - position += editor.childNodes[i].textContent.length; + offset += editor.childNodes[i].textContent.length; } - return {position, atNodeEnd: false}; + return {offset, atNodeEnd: false}; } // first make sure we're at the level of a direct child of editor @@ -36,7 +36,7 @@ export function getCaretPosition(editor) { // include all preceding siblings of the non-direct editor children while (node.previousSibling) { node = node.previousSibling; - position += node.textContent.length; + offset += node.textContent.length; } // then move up // I guess technically there could be preceding text nodes in the parents here as well, @@ -48,13 +48,13 @@ export function getCaretPosition(editor) { // now include the text length of all preceding direct editor children while (node.previousSibling) { node = node.previousSibling; - position += node.textContent.length; + offset += node.textContent.length; } - { - const {focusOffset, focusNode} = sel; - console.log("selection", {focusOffset, focusNode, position, atNodeEnd}); - } - return {position, atNodeEnd}; + // { + // const {focusOffset, focusNode} = sel; + // console.log("selection", {focusOffset, focusNode, position, atNodeEnd}); + // } + return {offset, atNodeEnd}; } export function setCaretPosition(editor, caretPosition) { diff --git a/src/editor/model.js b/src/editor/model.js index ffd2e17c01..b3d6682f79 100644 --- a/src/editor/model.js +++ b/src/editor/model.js @@ -40,18 +40,22 @@ export default class EditorModel { return this._parts; } + serializeParts() { + return this._parts.map(({type, text}) => {return {type, text};}); + } + _diff(newValue, inputType, caret) { if (inputType === "deleteByDrag") { return diffDeletion(this._previousValue, newValue); } else { - return diffAtCaret(this._previousValue, newValue, caret.position); + return diffAtCaret(this._previousValue, newValue, caret.offset); } } update(newValue, inputType, caret) { const diff = this._diff(newValue, inputType, caret); const position = this._positionForOffset(diff.at, caret.atNodeEnd); - console.log("update at", {position, diff}); + console.log("update at", {position, diff, newValue, prevValue: this._previousValue}); if (diff.removed) { this._removeText(position, diff.removed.length); }