Merge branch 'develop' into travis/hide-images
This commit is contained in:
commit
3c589cffec
69 changed files with 1103 additions and 290 deletions
|
@ -20,18 +20,17 @@ import ReactDOM from 'react-dom';
|
|||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import flatMap from 'lodash/flatMap';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import sdk from '../../../index';
|
||||
import type {Completion} from '../../../autocomplete/Autocompleter';
|
||||
import Promise from 'bluebird';
|
||||
import { Room } from 'matrix-js-sdk';
|
||||
|
||||
import {getCompletions} from '../../../autocomplete/Autocompleter';
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import Autocompleter from '../../../autocomplete/Autocompleter';
|
||||
|
||||
const COMPOSER_SELECTED = 0;
|
||||
|
||||
export const generateCompletionDomId = (number) => `mx_Autocomplete_Completion_${number}`;
|
||||
|
||||
export default class Autocomplete extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -224,7 +223,7 @@ export default class Autocomplete extends React.Component {
|
|||
setSelection(selectionOffset: number) {
|
||||
this.setState({selectionOffset, hide: false});
|
||||
if (this.props.onSelectionChange) {
|
||||
this.props.onSelectionChange(this.state.completionList[selectionOffset - 1]);
|
||||
this.props.onSelectionChange(this.state.completionList[selectionOffset - 1], selectionOffset - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,9 +249,8 @@ export default class Autocomplete extends React.Component {
|
|||
let position = 1;
|
||||
const renderedCompletions = this.state.completions.map((completionResult, i) => {
|
||||
const completions = completionResult.completions.map((completion, i) => {
|
||||
const className = classNames('mx_Autocomplete_Completion', {
|
||||
'selected': position === this.state.selectionOffset,
|
||||
});
|
||||
const selected = position === this.state.selectionOffset;
|
||||
const className = classNames('mx_Autocomplete_Completion', {selected});
|
||||
const componentPosition = position;
|
||||
position++;
|
||||
|
||||
|
@ -261,10 +259,12 @@ export default class Autocomplete extends React.Component {
|
|||
};
|
||||
|
||||
return React.cloneElement(completion.component, {
|
||||
key: i,
|
||||
ref: `completion${position - 1}`,
|
||||
"key": i,
|
||||
"ref": `completion${componentPosition}`,
|
||||
"id": generateCompletionDomId(componentPosition - 1), // 0 index the completion IDs
|
||||
className,
|
||||
onClick,
|
||||
"aria-selected": selected,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import {
|
|||
replaceRangeAndMoveCaret,
|
||||
} from '../../../editor/operations';
|
||||
import {getCaretOffsetAndText, getRangeForSelection} from '../../../editor/dom';
|
||||
import Autocomplete from '../rooms/Autocomplete';
|
||||
import Autocomplete, {generateCompletionDomId} from '../rooms/Autocomplete';
|
||||
import {autoCompleteCreator} from '../../../editor/parts';
|
||||
import {parsePlainTextMessage} from '../../../editor/deserialize';
|
||||
import {renderModel} from '../../../editor/render';
|
||||
|
@ -432,8 +432,9 @@ export default class BasicMessageEditor extends React.Component {
|
|||
this.props.model.autoComplete.onComponentConfirm(completion);
|
||||
}
|
||||
|
||||
_onAutoCompleteSelectionChange = (completion) => {
|
||||
_onAutoCompleteSelectionChange = (completion, completionIndex) => {
|
||||
this.props.model.autoComplete.onComponentSelectionChange(completion);
|
||||
this.setState({completionIndex});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -535,6 +536,8 @@ export default class BasicMessageEditor extends React.Component {
|
|||
quote: ctrlShortcutLabel(">"),
|
||||
};
|
||||
|
||||
const {completionIndex} = this.state;
|
||||
|
||||
return (<div className={classes}>
|
||||
{ autoComplete }
|
||||
<MessageComposerFormatBar ref={ref => this._formatBarRef = ref} onAction={this._onFormatAction} shortcuts={shortcuts} />
|
||||
|
@ -548,7 +551,13 @@ export default class BasicMessageEditor extends React.Component {
|
|||
onKeyDown={this._onKeyDown}
|
||||
ref={ref => this._editorRef = ref}
|
||||
aria-label={this.props.label}
|
||||
></div>
|
||||
role="textbox"
|
||||
aria-multiline="true"
|
||||
aria-autocomplete="both"
|
||||
aria-haspopup="listbox"
|
||||
aria-expanded={Boolean(this.state.autoComplete)}
|
||||
aria-activedescendant={completionIndex >= 0 ? generateCompletionDomId(completionIndex) : undefined}
|
||||
/>
|
||||
</div>);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ import sdk from '../../../index';
|
|||
import dis from '../../../dispatcher';
|
||||
import RoomViewStore from '../../../stores/RoomViewStore';
|
||||
import Stickerpicker from './Stickerpicker';
|
||||
import { makeRoomPermalink } from '../../../matrix-to';
|
||||
import { makeRoomPermalink } from '../../../utils/permalinks/Permalinks';
|
||||
import ContentMessages from '../../../ContentMessages';
|
||||
import classNames from 'classnames';
|
||||
import E2EIcon from './E2EIcon';
|
||||
|
|
|
@ -48,13 +48,11 @@ import Markdown from '../../../Markdown';
|
|||
import MessageComposerStore from '../../../stores/MessageComposerStore';
|
||||
import ContentMessages from '../../../ContentMessages';
|
||||
|
||||
import {MATRIXTO_URL_PATTERN} from '../../../linkify-matrix';
|
||||
|
||||
import EMOJIBASE from 'emojibase-data/en/compact.json';
|
||||
import EMOTICON_REGEX from 'emojibase-regex/emoticon';
|
||||
|
||||
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
|
||||
import {makeUserPermalink} from "../../../matrix-to";
|
||||
import {getPrimaryPermalinkEntity, makeUserPermalink} from "../../../utils/permalinks/Permalinks";
|
||||
import ReplyPreview from "./ReplyPreview";
|
||||
import RoomViewStore from '../../../stores/RoomViewStore';
|
||||
import ReplyThread from "../elements/ReplyThread";
|
||||
|
@ -224,18 +222,15 @@ export default class MessageComposerInput extends React.Component {
|
|||
// special case links
|
||||
if (tag === 'a') {
|
||||
const href = el.getAttribute('href');
|
||||
let m;
|
||||
if (href) {
|
||||
m = href.match(MATRIXTO_URL_PATTERN);
|
||||
}
|
||||
if (m) {
|
||||
const permalinkEntity = getPrimaryPermalinkEntity(href);
|
||||
if (permalinkEntity) {
|
||||
return {
|
||||
object: 'inline',
|
||||
type: 'pill',
|
||||
data: {
|
||||
href,
|
||||
completion: el.innerText,
|
||||
completionId: m[1],
|
||||
completionId: permalinkEntity,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
|
@ -541,7 +536,7 @@ export default class MessageComposerInput extends React.Component {
|
|||
|
||||
const textWithMdPills = this.plainWithMdPills.serialize(editorState);
|
||||
const markdown = new Markdown(textWithMdPills);
|
||||
// HTML deserialize has custom rules to turn matrix.to links into pill objects.
|
||||
// HTML deserialize has custom rules to turn permalinks into pill objects.
|
||||
return this.html.deserialize(markdown.toHTML());
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import { _t } from '../../../languageHandler';
|
|||
import RoomViewStore from '../../../stores/RoomViewStore';
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import PropTypes from "prop-types";
|
||||
import {RoomPermalinkCreator} from "../../../matrix-to";
|
||||
import {RoomPermalinkCreator} from "../../../utils/permalinks/Permalinks";
|
||||
|
||||
function cancelQuoting() {
|
||||
dis.dispatch({
|
||||
|
|
|
@ -805,7 +805,7 @@ module.exports = createReactClass({
|
|||
const subListComponents = this._mapSubListProps(subLists);
|
||||
|
||||
return (
|
||||
<div ref={this._collectResizeContainer} className="mx_RoomList"
|
||||
<div ref={this._collectResizeContainer} className="mx_RoomList" role="listbox" aria-label={_t("Rooms")}
|
||||
onMouseMove={this.onMouseMove} onMouseLeave={this.onMouseLeave}>
|
||||
{ subListComponents }
|
||||
</div>
|
||||
|
|
|
@ -33,6 +33,7 @@ import AccessibleButton from '../elements/AccessibleButton';
|
|||
import ActiveRoomObserver from '../../../ActiveRoomObserver';
|
||||
import RoomViewStore from '../../../stores/RoomViewStore';
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import {_t} from "../../../languageHandler";
|
||||
|
||||
module.exports = createReactClass({
|
||||
displayName: 'RoomTile',
|
||||
|
@ -368,6 +369,8 @@ module.exports = createReactClass({
|
|||
|
||||
const RoomAvatar = sdk.getComponent('avatars.RoomAvatar');
|
||||
|
||||
let ariaLabel = name;
|
||||
|
||||
let dmIndicator;
|
||||
if (this._isDirectMessageRoom(this.props.room.roomId)) {
|
||||
dmIndicator = <img
|
||||
|
@ -379,12 +382,24 @@ module.exports = createReactClass({
|
|||
/>;
|
||||
}
|
||||
|
||||
if (notifBadges && mentionBadges && !isInvite) {
|
||||
ariaLabel += " " + _t("It has %(count)s unread messages including mentions.", {
|
||||
count: notificationCount,
|
||||
});
|
||||
} else if (notifBadges) {
|
||||
ariaLabel += " " + _t("It has %(count)s unread messages.", { count: notificationCount });
|
||||
} else if (mentionBadges && !isInvite) {
|
||||
ariaLabel += " " + _t("It has unread mentions.");
|
||||
}
|
||||
|
||||
return <AccessibleButton tabIndex="0"
|
||||
className={classes}
|
||||
onClick={this.onClick}
|
||||
onMouseEnter={this.onMouseEnter}
|
||||
onMouseLeave={this.onMouseLeave}
|
||||
onContextMenu={this.onContextMenu}
|
||||
aria-label={ariaLabel}
|
||||
role="option"
|
||||
>
|
||||
<div className={avatarClasses}>
|
||||
<div className="mx_RoomTile_avatar_container">
|
||||
|
|
|
@ -182,7 +182,7 @@ export default class SendMessageComposer extends React.Component {
|
|||
// be extra resilient when somehow the AutocompleteWrapperModel or
|
||||
// CommandPartCreator fails to insert a command part, so we don't send
|
||||
// a command as a message
|
||||
if (firstPart.type === "plain" && firstPart.text.startsWith("/")) {
|
||||
if (firstPart.text.startsWith("/") && (firstPart.type === "plain" || firstPart.type === "pill-candidate")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import dis from '../../../dispatcher';
|
|||
import RoomViewStore from '../../../stores/RoomViewStore';
|
||||
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
|
||||
import Stickerpicker from './Stickerpicker';
|
||||
import { makeRoomPermalink } from '../../../matrix-to';
|
||||
import { makeRoomPermalink } from '../../../utils/permalinks/Permalinks';
|
||||
import ContentMessages from '../../../ContentMessages';
|
||||
import classNames from 'classnames';
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue