Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #2082 from matrix-org/t3chguy/slate_cont2
Browse files Browse the repository at this point in the history
Moar Slate Fixes
  • Loading branch information
dbkr authored Jul 24, 2018
2 parents c19a5bd + 020e714 commit cf6ce0c
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 48 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"react-dom": "^15.6.0",
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#5e97aef",
"resize-observer-polyfill": "^1.5.0",
"slate": "0.33.4",
"slate": "0.34.7",
"slate-react": "^0.12.4",
"slate-html-serializer": "^0.6.1",
"slate-md-serializer": "matrix-org/slate-md-serializer#f7c4ad3",
Expand Down
3 changes: 2 additions & 1 deletion res/css/views/rooms/_Autocomplete.scss
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@
flex-flow: wrap;
}

.mx_Autocomplete_Completion.selected {
.mx_Autocomplete_Completion.selected,
.mx_Autocomplete_Completion:hover {
background: $menu-bg-color;
outline: none;
}
Expand Down
34 changes: 11 additions & 23 deletions src/RichText.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,25 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';

import * as sdk from './index';
import * as emojione from 'emojione';

import { SelectionRange } from "./autocomplete/Autocompleter";


export function unicodeToEmojiUri(str) {
let replaceWith, unicode, alt;
if ((!emojione.unicodeAlt) || (emojione.sprites)) {
// if we are using the shortname as the alt tag then we need a reversed array to map unicode code point to shortnames
const mappedUnicode = emojione.mapUnicodeToShort();
}

str = str.replace(emojione.regUnicode, function(unicodeChar) {
if ( (typeof unicodeChar === 'undefined') || (unicodeChar === '') || (!(unicodeChar in emojione.jsEscapeMap)) ) {
// if the unicodeChar doesnt exist just return the entire match
const mappedUnicode = emojione.mapUnicodeToShort();

// remove any zero width joiners/spaces used in conjugate emojis as the emojione URIs don't contain them
return str.replace(emojione.regUnicode, function(unicodeChar) {
if ((typeof unicodeChar === 'undefined') || (unicodeChar === '') || (!(unicodeChar in emojione.jsEscapeMap))) {
// if the unicodeChar doesn't exist just return the entire match
return unicodeChar;
} else {
// Remove variant selector VS16 (explicitly emoji) as it is unnecessary and leads to an incorrect URL below
if (unicodeChar.length == 2 && unicodeChar[1] == '\ufe0f') {
unicodeChar = unicodeChar[0];
}

// get the unicode codepoint from the actual char
unicode = emojione.jsEscapeMap[unicodeChar];
const unicode = emojione.jsEscapeMap[unicodeChar];

const short = mappedUnicode[unicode];
const fname = emojione.emojioneList[short].fname;

return emojione.imagePathSVG+unicode+'.svg'+emojione.cacheBustParam;
return emojione.imagePathSVG+fname+'.svg'+emojione.cacheBustParam;
}
});

return str;
}
2 changes: 1 addition & 1 deletion src/autocomplete/CommandProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default class CommandProvider extends AutocompleteProvider {
const name = command[1].substr(1); // strip leading `/`
if (CommandMap[name]) {
// some commands, namely `me` and `ddg` don't suit having the usage shown whilst typing their arguments
if (!CommandMap[name].hideCompletionAfterSpace) return [];
if (CommandMap[name].hideCompletionAfterSpace) return [];
matches = [CommandMap[name]];
}
} else {
Expand Down
10 changes: 7 additions & 3 deletions src/autocomplete/PlainWithPillsSerializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,17 @@ class PlainWithPillsSerializer {
} else if (node.type == 'emoji') {
return node.data.get('emojiUnicode');
} else if (node.type == 'pill') {
const completion = node.data.get('completion');
// over the wire the @room pill is just plaintext
if (completion === '@room') return completion;

switch (this.pillFormat) {
case 'plain':
return node.data.get('completion');
return completion;
case 'md':
return `[${ node.data.get('completion') }](${ node.data.get('href') })`;
return `[${ completion }](${ node.data.get('href') })`;
case 'id':
return node.data.get('completionId') || node.data.get('completion');
return node.data.get('completionId') || completion;
}
} else if (node.nodes) {
return node.nodes.map(this._serializeNode).join('');
Expand Down
14 changes: 7 additions & 7 deletions src/components/views/messages/TextualBody.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ module.exports = React.createClass({
// update the current node with one that's now taken its place
node = pillContainer;
}
} else if (node.nodeType == Node.TEXT_NODE) {
} else if (node.nodeType === Node.TEXT_NODE) {
const Pill = sdk.getComponent('elements.Pill');

let currentTextNode = node;
Expand Down Expand Up @@ -232,6 +232,12 @@ module.exports = React.createClass({
if (atRoomRule && pushProcessor.ruleMatchesEvent(atRoomRule, this.props.mxEvent)) {
// Now replace all those nodes with Pills
for (const roomNotifTextNode of roomNotifTextNodes) {
// Set the next node to be processed to the one after the node
// we're adding now, since we've just inserted nodes into the structure
// we're iterating over.
// Note we've checked roomNotifTextNodes.length > 0 so we'll do this at least once
node = roomNotifTextNode.nextSibling;

const pillContainer = document.createElement('span');
const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
const pill = <Pill
Expand All @@ -243,12 +249,6 @@ module.exports = React.createClass({

ReactDOM.render(pill, pillContainer);
roomNotifTextNode.parentNode.replaceChild(pillContainer, roomNotifTextNode);

// Set the next node to be processed to the one after the node
// we're adding now, since we've just inserted nodes into the structure
// we're iterating over.
// Note we've checked roomNotifTextNodes.length > 0 so we'll do this at least once
node = roomNotifTextNode.nextSibling;
}
// Nothing else to do for a text node (and we don't need to advance
// the loop pointer because we did it above)
Expand Down
9 changes: 4 additions & 5 deletions src/components/views/rooms/Autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,12 @@ export default class Autocomplete extends React.Component {
return done.promise;
}

onCompletionClicked(): boolean {
if (this.countCompletions() === 0 || this.state.selectionOffset === COMPOSER_SELECTED) {
onCompletionClicked(selectionOffset: number): boolean {
if (this.countCompletions() === 0 || selectionOffset === COMPOSER_SELECTED) {
return false;
}

this.props.onConfirm(this.state.completionList[this.state.selectionOffset - 1]);
this.props.onConfirm(this.state.completionList[selectionOffset - 1]);
this.hide();

return true;
Expand Down Expand Up @@ -264,8 +264,7 @@ export default class Autocomplete extends React.Component {
position++;

const onClick = () => {
this.setSelection(componentPosition);
this.onCompletionClicked();
this.onCompletionClicked(componentPosition);
};

return React.cloneElement(completion.component, {
Expand Down
33 changes: 26 additions & 7 deletions src/components/views/rooms/MessageComposerInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -387,17 +387,28 @@ export default class MessageComposerInput extends React.Component {
const anchorText = editorState.anchorText;
if ((!anchorText || anchorText.text === '') && editorState.anchorBlock.nodes.size === 1) {
// replace the current block rather than split the block
// XXX: this destroys our focus by deleting the thing we are anchored/focused on
change = change.replaceNodeByKey(editorState.anchorBlock.key, quote);
}
else {
} else {
// insert it into the middle of the block (splitting it)
change = change.insertBlock(quote);
}
change = change.insertFragmentByKey(quote.key, 0, fragment.document)
.focus();

// XXX: heuristic to strip out wrapping <p> which breaks quoting in RT mode
if (fragment.document.nodes.size && fragment.document.nodes.get(0).type === DEFAULT_NODE) {
change = change.insertFragmentByKey(quote.key, 0, fragment.document.nodes.get(0));
} else {
change = change.insertFragmentByKey(quote.key, 0, fragment.document);
}

// XXX: this is to bring back the focus in a sane place and add a paragraph after it
change = change.select({
anchorKey: quote.key,
focusKey: quote.key,
}).collapseToEndOfBlock().insertBlock(Block.create(DEFAULT_NODE)).focus();

this.onChange(change);
}
else {
} else {
let fragmentChange = fragment.change();
fragmentChange.moveToRangeOf(fragment.document)
.wrapBlock(quote);
Expand Down Expand Up @@ -1301,6 +1312,14 @@ export default class MessageComposerInput extends React.Component {
await this.setDisplayedCompletion(null); // restore originalEditorState
};

onAutocompleteConfirm = (displayedCompletion: ?Completion) => {
this.focusComposer();
// XXX: this fails if the composer isn't focused so focus it and delay the completion until next tick
setImmediate(() => {
this.setDisplayedCompletion(displayedCompletion);
});
};

/* If passed null, restores the original editor content from state.originalEditorState.
* If passed a non-null displayedCompletion, modifies state.originalEditorState to compute new state.editorState.
*/
Expand Down Expand Up @@ -1563,7 +1582,7 @@ export default class MessageComposerInput extends React.Component {
<Autocomplete
ref={(e) => this.autocomplete = e}
room={this.props.room}
onConfirm={this.setDisplayedCompletion}
onConfirm={this.onAutocompleteConfirm}
onSelectionChange={this.setDisplayedCompletion}
query={ this.suppressAutoComplete ? '' : this.getAutocompleteQuery(activeEditorState) }
selection={this.getSelectionRange(activeEditorState)}
Expand Down

0 comments on commit cf6ce0c

Please sign in to comment.