Merge branch 'develop' into luke/fix-rte-inline-code-format
This commit is contained in:
commit
29b6d70aff
5 changed files with 68 additions and 34 deletions
|
@ -113,31 +113,6 @@ let emojiDecorator = {
|
|||
* Returns a composite decorator which has access to provided scope.
|
||||
*/
|
||||
export function getScopedRTDecorators(scope: any): CompositeDecorator {
|
||||
let MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
||||
|
||||
let usernameDecorator = {
|
||||
strategy: (contentBlock, callback) => {
|
||||
findWithRegex(USERNAME_REGEX, contentBlock, callback);
|
||||
},
|
||||
component: (props) => {
|
||||
let member = scope.room.getMember(props.children[0].props.text);
|
||||
// unused until we make these decorators immutable (autocomplete needed)
|
||||
let name = member ? member.name : null;
|
||||
let avatar = member ? <MemberAvatar member={member} width={16} height={16}/> : null;
|
||||
return <span className="mx_UserPill">{avatar}{props.children}</span>;
|
||||
}
|
||||
};
|
||||
|
||||
let roomDecorator = {
|
||||
strategy: (contentBlock, callback) => {
|
||||
findWithRegex(ROOM_REGEX, contentBlock, callback);
|
||||
},
|
||||
component: (props) => {
|
||||
return <span className="mx_RoomPill">{props.children}</span>;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO Re-enable usernameDecorator and roomDecorator
|
||||
return [emojiDecorator];
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ export default class EmojiProvider extends AutocompleteProvider {
|
|||
}
|
||||
|
||||
renderCompletions(completions: [React.Component]): ?React.Component {
|
||||
return <div className="mx_Autocomplete_Completion_container_pill mx_Autocomplete_Completion_container_truncate">
|
||||
return <div className="mx_Autocomplete_Completion_container_pill">
|
||||
{completions}
|
||||
</div>;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ limitations under the License.
|
|||
import _at from 'lodash/at';
|
||||
import _flatMap from 'lodash/flatMap';
|
||||
import _sortBy from 'lodash/sortBy';
|
||||
import _sortedUniq from 'lodash/sortedUniq';
|
||||
import _uniq from 'lodash/uniq';
|
||||
import _keys from 'lodash/keys';
|
||||
|
||||
class KeyMap {
|
||||
|
@ -101,7 +101,7 @@ export default class QueryMatcher {
|
|||
}
|
||||
});
|
||||
|
||||
return _sortedUniq(_flatMap(_sortBy(results, (candidate) => {
|
||||
return _uniq(_flatMap(_sortBy(results, (candidate) => {
|
||||
return candidate.index;
|
||||
}).map((candidate) => {
|
||||
// return an array of objects (those given to setObjects) that have the given
|
||||
|
|
|
@ -30,6 +30,8 @@ import SdkConfig from '../../../SdkConfig';
|
|||
import dis from '../../../dispatcher';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import UserSettingsStore from "../../../UserSettingsStore";
|
||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||
import {RoomMember} from 'matrix-js-sdk';
|
||||
|
||||
linkifyMatrix(linkify);
|
||||
|
||||
|
@ -80,6 +82,10 @@ module.exports = React.createClass({
|
|||
componentDidMount: function() {
|
||||
this._unmounted = false;
|
||||
|
||||
// pillifyLinks BEFORE linkifyElement because plain room/user URLs in the composer
|
||||
// are still sent as plaintext URLs. If these are ever pillified in the composer,
|
||||
// we should be pillify them here by doing the linkifying BEFORE the pillifying.
|
||||
this.pillifyLinks(this.refs.content.children);
|
||||
linkifyElement(this.refs.content, linkifyMatrix.options);
|
||||
this.calculateUrlPreview();
|
||||
|
||||
|
@ -162,6 +168,55 @@ module.exports = React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
pillifyLinks: function(nodes) {
|
||||
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
||||
const RoomAvatar = sdk.getComponent('avatars.RoomAvatar');
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
const node = nodes[i];
|
||||
if (node.tagName === "A" && node.getAttribute("href")) {
|
||||
const href = node.getAttribute("href");
|
||||
// HtmlUtils transforms `matrix.to` links to local links, so match against
|
||||
// user or room app links.
|
||||
const match = /^#\/(user|room)\/(.*)$/.exec(href) || [];
|
||||
const resourceType = match[1]; // "user" or "room"
|
||||
const resourceId = match[2]; // user ID or room ID
|
||||
if (match && resourceType && resourceId) {
|
||||
let avatar;
|
||||
let roomId;
|
||||
let room;
|
||||
let member;
|
||||
switch (resourceType) {
|
||||
case "user":
|
||||
roomId = this.props.mxEvent.getRoomId();
|
||||
room = MatrixClientPeg.get().getRoom(roomId);
|
||||
member = room.getMember(resourceId) ||
|
||||
new RoomMember(null, resourceId);
|
||||
avatar = <MemberAvatar member={member} width={16} height={16} name={resourceId}/>;
|
||||
break;
|
||||
case "room":
|
||||
room = resourceId[0] === '#' ?
|
||||
MatrixClientPeg.get().getRooms().find((r) => {
|
||||
return r.getCanonicalAlias() === resourceId;
|
||||
}) : MatrixClientPeg.get().getRoom(resourceId);
|
||||
if (room) {
|
||||
avatar = <RoomAvatar room={room} width={16} height={16}/>;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (avatar) {
|
||||
const avatarContainer = document.createElement('span');
|
||||
node.className = "mx_MTextBody_pill " +
|
||||
(resourceType === "user" ? "mx_UserPill" : "mx_RoomPill");
|
||||
ReactDOM.render(avatar, avatarContainer);
|
||||
node.insertBefore(avatarContainer, node.firstChild);
|
||||
}
|
||||
}
|
||||
} else if (node.children && node.children.length) {
|
||||
this.pillifyLinks(node.children);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
findLinks: function(nodes) {
|
||||
var links = [];
|
||||
|
||||
|
|
|
@ -527,15 +527,18 @@ export default class MessageComposerInput extends React.Component {
|
|||
if (this.state.isRichtextEnabled) {
|
||||
// These are block types, not handled by RichUtils by default.
|
||||
const blockCommands = ['code-block', 'blockquote', 'unordered-list-item', 'ordered-list-item'];
|
||||
const currentBlockType = RichUtils.getCurrentBlockType(this.state.editorState);
|
||||
if (blockCommands.includes(command)) {
|
||||
this.setState({
|
||||
editorState: RichUtils.toggleBlockType(this.state.editorState, command),
|
||||
});
|
||||
newState = RichUtils.toggleBlockType(this.state.editorState, command);
|
||||
} else if (command === 'strike') {
|
||||
// this is the only inline style not handled by Draft by default
|
||||
this.setState({
|
||||
editorState: RichUtils.toggleInlineStyle(this.state.editorState, 'STRIKETHROUGH'),
|
||||
});
|
||||
newState = RichUtils.toggleInlineStyle(this.state.editorState, 'STRIKETHROUGH');
|
||||
} else if (command === 'backspace' && currentBlockType !== 'unstyled') {
|
||||
const currentStartOffset = this.state.editorState.getSelection().getStartOffset();
|
||||
if (currentStartOffset === 0) {
|
||||
// Toggle current block type (setting it to 'unstyled')
|
||||
newState = RichUtils.toggleBlockType(this.state.editorState, currentBlockType);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const contentState = this.state.editorState.getCurrentContent();
|
||||
|
@ -655,6 +658,7 @@ export default class MessageComposerInput extends React.Component {
|
|||
// By returning false, we allow the default draft-js key binding to occur,
|
||||
// which in this case invokes "split-block". This creates a new block of the
|
||||
// same type, allowing the user to delete it with backspace.
|
||||
// See handleKeyCommand (when command === 'backspace')
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue