Merge branch 'develop' into t3chguy/address_picker_dialog_tab_trap
This commit is contained in:
commit
d7a411f588
25 changed files with 318 additions and 289 deletions
|
@ -175,6 +175,7 @@
|
||||||
@import "./views/rooms/_Stickers.scss";
|
@import "./views/rooms/_Stickers.scss";
|
||||||
@import "./views/rooms/_TopUnreadMessagesBar.scss";
|
@import "./views/rooms/_TopUnreadMessagesBar.scss";
|
||||||
@import "./views/rooms/_WhoIsTypingTile.scss";
|
@import "./views/rooms/_WhoIsTypingTile.scss";
|
||||||
|
@import "./views/settings/_AvatarSetting.scss";
|
||||||
@import "./views/settings/_CrossSigningPanel.scss";
|
@import "./views/settings/_CrossSigningPanel.scss";
|
||||||
@import "./views/settings/_DevicesPanel.scss";
|
@import "./views/settings/_DevicesPanel.scss";
|
||||||
@import "./views/settings/_EmailAddresses.scss";
|
@import "./views/settings/_EmailAddresses.scss";
|
||||||
|
|
|
@ -42,3 +42,11 @@ limitations under the License.
|
||||||
padding-left: 40px;
|
padding-left: 40px;
|
||||||
padding-right: 80px;
|
padding-right: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// show a different AvatarSetting placeholder for RoomProfileSettings which is basically a clone of ProfileSettings
|
||||||
|
.mx_RoomSettingsDialog .mx_AvatarSetting_avatar .mx_AvatarSetting_avatarPlaceholder::before {
|
||||||
|
mask: url("$(res)/img/feather-customised/image.svg");
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-size: 36px;
|
||||||
|
mask-position: center;
|
||||||
|
}
|
||||||
|
|
87
res/css/views/settings/_AvatarSetting.scss
Normal file
87
res/css/views/settings/_AvatarSetting.scss
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.mx_AvatarSetting_avatar {
|
||||||
|
width: 88px;
|
||||||
|
height: 88px;
|
||||||
|
margin-left: 13px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
width: 88px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_AccessibleButton.mx_AccessibleButton_kind_primary {
|
||||||
|
margin-top: 8px;
|
||||||
|
|
||||||
|
div {
|
||||||
|
position: relative;
|
||||||
|
height: 12px;
|
||||||
|
width: 12px;
|
||||||
|
display: inline;
|
||||||
|
padding-right: 6px; // 0.5 * 12px
|
||||||
|
left: -6px; // 0.5 * 12px
|
||||||
|
top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
height: 12px;
|
||||||
|
width: 12px;
|
||||||
|
|
||||||
|
background-color: $button-primary-fg-color;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-size: contain;
|
||||||
|
mask-image: url('$(res)/img/feather-customised/upload.svg');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_AccessibleButton.mx_AccessibleButton_kind_link_sm {
|
||||||
|
color: $button-danger-bg-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > img {
|
||||||
|
cursor: pointer;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > img,
|
||||||
|
.mx_AvatarSetting_avatarPlaceholder {
|
||||||
|
display: block;
|
||||||
|
height: 88px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_AvatarSetting_avatarPlaceholder::before {
|
||||||
|
background-color: $settings-profile-overlay-placeholder-fg-color;
|
||||||
|
mask: url("$(res)/img/feather-customised/user.svg");
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
mask-size: 36px;
|
||||||
|
mask-position: center;
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mx_AvatarSetting_avatar .mx_AvatarSetting_avatarPlaceholder {
|
||||||
|
background-color: $settings-profile-placeholder-bg-color;
|
||||||
|
}
|
|
@ -38,95 +38,6 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ProfileSettings_avatar {
|
|
||||||
width: 88px;
|
|
||||||
height: 88px;
|
|
||||||
margin-left: 13px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_avatar > * {
|
|
||||||
display: block;
|
|
||||||
width: 88px;
|
|
||||||
height: 88px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_avatar img {
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_avatar .mx_ProfileSettings_avatarOverlay_disabled {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_avatar .mx_ProfileSettings_avatarPlaceholder {
|
|
||||||
background-color: $settings-profile-placeholder-bg-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_avatarOverlay {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: none;
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
font-size: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_avatar:hover .mx_ProfileSettings_avatarOverlay:not(.mx_ProfileSettings_avatarOverlay_disabled) {
|
|
||||||
display: inline-block;
|
|
||||||
opacity: 0.5 !important;
|
|
||||||
color: $settings-profile-overlay-fg-color !important;
|
|
||||||
background-color: $settings-profile-overlay-bg-color !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_avatarOverlay_show {
|
|
||||||
display: inline-block;
|
|
||||||
opacity: 1;
|
|
||||||
color: $settings-profile-overlay-placeholder-fg-color;
|
|
||||||
background-color: $settings-profile-overlay-placeholder-bg-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_avatarOverlayText {
|
|
||||||
display: block;
|
|
||||||
margin-top: 17px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_noAvatarText {
|
|
||||||
display: block;
|
|
||||||
margin: 34px auto auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_avatarOverlayImgContainer {
|
|
||||||
position: relative;
|
|
||||||
width: 14px;
|
|
||||||
height: 14px;
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_avatarOverlayImg::before {
|
|
||||||
background-color: $settings-profile-overlay-placeholder-fg-color;
|
|
||||||
mask: url("$(res)/img/feather-customised/upload.svg");
|
|
||||||
mask-repeat: no-repeat;
|
|
||||||
mask-size: 14px;
|
|
||||||
mask-position: center;
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_avatar:hover .mx_ProfileSettings_avatarOverlayImg::before {
|
|
||||||
background-color: $settings-profile-overlay-fg-color !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_ProfileSettings_avatarUpload {
|
.mx_ProfileSettings_avatarUpload {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
5
res/img/feather-customised/image.svg
Normal file
5
res/img/feather-customised/image.svg
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M6 8C6 6.89543 6.89543 6 8 6H40C41.1046 6 42 6.89543 42 8V40C42 41.1046 41.1046 42 40 42H8C6.89543 42 6 41.1046 6 40V8Z" stroke="#61708B" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M17 20C18.6569 20 20 18.6569 20 17C20 15.3431 18.6569 14 17 14C15.3431 14 14 15.3431 14 17C14 18.6569 15.3431 20 17 20Z" stroke="#61708B" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M42 30L32 20L10 42" stroke="#61708B" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 721 B |
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2016 OpenMarket Ltd
|
Copyright 2016 OpenMarket Ltd
|
||||||
Copyright 2017 New Vector Ltd
|
Copyright 2017 New Vector Ltd
|
||||||
|
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -15,52 +16,6 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* a selection of key codes, as used in KeyboardEvent.keyCode */
|
|
||||||
export const KeyCode = {
|
|
||||||
BACKSPACE: 8,
|
|
||||||
TAB: 9,
|
|
||||||
ENTER: 13,
|
|
||||||
SHIFT: 16,
|
|
||||||
ESCAPE: 27,
|
|
||||||
SPACE: 32,
|
|
||||||
PAGE_UP: 33,
|
|
||||||
PAGE_DOWN: 34,
|
|
||||||
END: 35,
|
|
||||||
HOME: 36,
|
|
||||||
LEFT: 37,
|
|
||||||
UP: 38,
|
|
||||||
RIGHT: 39,
|
|
||||||
DOWN: 40,
|
|
||||||
DELETE: 46,
|
|
||||||
KEY_A: 65,
|
|
||||||
KEY_B: 66,
|
|
||||||
KEY_C: 67,
|
|
||||||
KEY_D: 68,
|
|
||||||
KEY_E: 69,
|
|
||||||
KEY_F: 70,
|
|
||||||
KEY_G: 71,
|
|
||||||
KEY_H: 72,
|
|
||||||
KEY_I: 73,
|
|
||||||
KEY_J: 74,
|
|
||||||
KEY_K: 75,
|
|
||||||
KEY_L: 76,
|
|
||||||
KEY_M: 77,
|
|
||||||
KEY_N: 78,
|
|
||||||
KEY_O: 79,
|
|
||||||
KEY_P: 80,
|
|
||||||
KEY_Q: 81,
|
|
||||||
KEY_R: 82,
|
|
||||||
KEY_S: 83,
|
|
||||||
KEY_T: 84,
|
|
||||||
KEY_U: 85,
|
|
||||||
KEY_V: 86,
|
|
||||||
KEY_W: 87,
|
|
||||||
KEY_X: 88,
|
|
||||||
KEY_Y: 89,
|
|
||||||
KEY_Z: 90,
|
|
||||||
KEY_BACKTICK: 223, // DO NOT USE THIS: browsers disagree on backtick 192 vs 223
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Key = {
|
export const Key = {
|
||||||
HOME: "Home",
|
HOME: "Home",
|
||||||
END: "End",
|
END: "End",
|
||||||
|
@ -80,13 +35,35 @@ export const Key = {
|
||||||
SHIFT: "Shift",
|
SHIFT: "Shift",
|
||||||
CONTEXT_MENU: "ContextMenu",
|
CONTEXT_MENU: "ContextMenu",
|
||||||
|
|
||||||
|
COMMA: ",",
|
||||||
LESS_THAN: "<",
|
LESS_THAN: "<",
|
||||||
GREATER_THAN: ">",
|
GREATER_THAN: ">",
|
||||||
BACKTICK: "`",
|
BACKTICK: "`",
|
||||||
SPACE: " ",
|
SPACE: " ",
|
||||||
|
A: "a",
|
||||||
B: "b",
|
B: "b",
|
||||||
|
C: "c",
|
||||||
|
D: "d",
|
||||||
|
E: "e",
|
||||||
|
F: "f",
|
||||||
|
G: "g",
|
||||||
|
H: "h",
|
||||||
I: "i",
|
I: "i",
|
||||||
|
J: "j",
|
||||||
K: "k",
|
K: "k",
|
||||||
|
L: "l",
|
||||||
|
M: "m",
|
||||||
|
N: "n",
|
||||||
|
O: "o",
|
||||||
|
P: "p",
|
||||||
|
Q: "q",
|
||||||
|
R: "r",
|
||||||
|
S: "s",
|
||||||
|
T: "t",
|
||||||
|
U: "u",
|
||||||
|
V: "v",
|
||||||
|
W: "w",
|
||||||
|
X: "x",
|
||||||
Y: "y",
|
Y: "y",
|
||||||
Z: "z",
|
Z: "z",
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {Key} from "../../../Keyboard";
|
||||||
|
|
||||||
const React = require("react");
|
const React = require("react");
|
||||||
import createReactClass from 'create-react-class';
|
import createReactClass from 'create-react-class';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
@ -83,7 +85,7 @@ module.exports = createReactClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onKeyDown: function(e) {
|
onKeyDown: function(e) {
|
||||||
if (e.keyCode === 27) { // escape
|
if (e.key === Key.ESCAPE) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.onFinished(false);
|
this.props.onFinished(false);
|
||||||
|
|
|
@ -25,7 +25,7 @@ import Unread from '../../Unread';
|
||||||
import * as RoomNotifs from '../../RoomNotifs';
|
import * as RoomNotifs from '../../RoomNotifs';
|
||||||
import * as FormattingUtils from '../../utils/FormattingUtils';
|
import * as FormattingUtils from '../../utils/FormattingUtils';
|
||||||
import IndicatorScrollbar from './IndicatorScrollbar';
|
import IndicatorScrollbar from './IndicatorScrollbar';
|
||||||
import {Key, KeyCode} from '../../Keyboard';
|
import {Key} from '../../Keyboard';
|
||||||
import { Group } from 'matrix-js-sdk';
|
import { Group } from 'matrix-js-sdk';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import RoomTile from "../views/rooms/RoomTile";
|
import RoomTile from "../views/rooms/RoomTile";
|
||||||
|
@ -186,7 +186,7 @@ export default class RoomSubList extends React.PureComponent {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'view_room',
|
action: 'view_room',
|
||||||
room_id: roomId,
|
room_id: roomId,
|
||||||
clear_search: (ev && (ev.keyCode === KeyCode.ENTER || ev.keyCode === KeyCode.SPACE)),
|
clear_search: (ev && (ev.key === Key.ENTER || ev.key === Key.SPACE)),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ import ObjectUtils from '../../ObjectUtils';
|
||||||
import * as Rooms from '../../Rooms';
|
import * as Rooms from '../../Rooms';
|
||||||
import eventSearch from '../../Searching';
|
import eventSearch from '../../Searching';
|
||||||
|
|
||||||
import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard';
|
import {isOnlyCtrlOrCmdKeyEvent, Key} from '../../Keyboard';
|
||||||
|
|
||||||
import MainSplit from './MainSplit';
|
import MainSplit from './MainSplit';
|
||||||
import RightPanel from './RightPanel';
|
import RightPanel from './RightPanel';
|
||||||
|
@ -561,15 +561,15 @@ module.exports = createReactClass({
|
||||||
let handled = false;
|
let handled = false;
|
||||||
const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev);
|
const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev);
|
||||||
|
|
||||||
switch (ev.keyCode) {
|
switch (ev.key) {
|
||||||
case KeyCode.KEY_D:
|
case Key.D:
|
||||||
if (ctrlCmdOnly) {
|
if (ctrlCmdOnly) {
|
||||||
this.onMuteAudioClick();
|
this.onMuteAudioClick();
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyCode.KEY_E:
|
case Key.E:
|
||||||
if (ctrlCmdOnly) {
|
if (ctrlCmdOnly) {
|
||||||
this.onMuteVideoClick();
|
this.onMuteVideoClick();
|
||||||
handled = true;
|
handled = true;
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
import React, {createRef} from "react";
|
import React, {createRef} from "react";
|
||||||
import createReactClass from 'create-react-class';
|
import createReactClass from 'create-react-class';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { KeyCode } from '../../Keyboard';
|
import { Key } from '../../Keyboard';
|
||||||
import Timer from '../../utils/Timer';
|
import Timer from '../../utils/Timer';
|
||||||
import AutoHideScrollbar from "./AutoHideScrollbar";
|
import AutoHideScrollbar from "./AutoHideScrollbar";
|
||||||
|
|
||||||
|
@ -532,26 +532,26 @@ module.exports = createReactClass({
|
||||||
* @param {object} ev the keyboard event
|
* @param {object} ev the keyboard event
|
||||||
*/
|
*/
|
||||||
handleScrollKey: function(ev) {
|
handleScrollKey: function(ev) {
|
||||||
switch (ev.keyCode) {
|
switch (ev.key) {
|
||||||
case KeyCode.PAGE_UP:
|
case Key.PAGE_UP:
|
||||||
if (!ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
if (!ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||||
this.scrollRelative(-1);
|
this.scrollRelative(-1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyCode.PAGE_DOWN:
|
case Key.PAGE_DOWN:
|
||||||
if (!ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
if (!ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||||
this.scrollRelative(1);
|
this.scrollRelative(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyCode.HOME:
|
case Key.HOME:
|
||||||
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||||
this.scrollToTop();
|
this.scrollToTop();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case KeyCode.END:
|
case Key.END:
|
||||||
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
|
||||||
this.scrollToBottom();
|
this.scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ limitations under the License.
|
||||||
import React, {createRef} from 'react';
|
import React, {createRef} from 'react';
|
||||||
import createReactClass from 'create-react-class';
|
import createReactClass from 'create-react-class';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { KeyCode } from '../../Keyboard';
|
import { Key } from '../../Keyboard';
|
||||||
import dis from '../../dispatcher';
|
import dis from '../../dispatcher';
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'lodash';
|
||||||
import AccessibleButton from '../../components/views/elements/AccessibleButton';
|
import AccessibleButton from '../../components/views/elements/AccessibleButton';
|
||||||
|
@ -93,8 +93,8 @@ module.exports = createReactClass({
|
||||||
}, 200, {trailing: true, leading: true}),
|
}, 200, {trailing: true, leading: true}),
|
||||||
|
|
||||||
_onKeyDown: function(ev) {
|
_onKeyDown: function(ev) {
|
||||||
switch (ev.keyCode) {
|
switch (ev.key) {
|
||||||
case KeyCode.ESCAPE:
|
case Key.ESCAPE:
|
||||||
this._clearSearch("keyboard");
|
this._clearSearch("keyboard");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ const dis = require("../../dispatcher");
|
||||||
const ObjectUtils = require('../../ObjectUtils');
|
const ObjectUtils = require('../../ObjectUtils');
|
||||||
const Modal = require("../../Modal");
|
const Modal = require("../../Modal");
|
||||||
const UserActivity = require("../../UserActivity");
|
const UserActivity = require("../../UserActivity");
|
||||||
import { KeyCode } from '../../Keyboard';
|
import {Key} from '../../Keyboard';
|
||||||
import Timer from '../../utils/Timer';
|
import Timer from '../../utils/Timer';
|
||||||
import shouldHideEvent from '../../shouldHideEvent';
|
import shouldHideEvent from '../../shouldHideEvent';
|
||||||
import EditorStateTransfer from '../../utils/EditorStateTransfer';
|
import EditorStateTransfer from '../../utils/EditorStateTransfer';
|
||||||
|
@ -942,8 +942,7 @@ const TimelinePanel = createReactClass({
|
||||||
|
|
||||||
// jump to the live timeline on ctrl-end, rather than the end of the
|
// jump to the live timeline on ctrl-end, rather than the end of the
|
||||||
// timeline window.
|
// timeline window.
|
||||||
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey &&
|
if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey && ev.key === Key.END) {
|
||||||
ev.keyCode == KeyCode.END) {
|
|
||||||
this.jumpToLiveTimeline();
|
this.jumpToLiveTimeline();
|
||||||
} else {
|
} else {
|
||||||
this._messagePanel.current.handleScrollKey(ev);
|
this._messagePanel.current.handleScrollKey(ev);
|
||||||
|
|
|
@ -32,6 +32,7 @@ import IdentityAuthClient from '../../../IdentityAuthClient';
|
||||||
import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from '../../../utils/IdentityServerUtils';
|
import { getDefaultIdentityServerUrl, useDefaultIdentityServer } from '../../../utils/IdentityServerUtils';
|
||||||
import { abbreviateUrl } from '../../../utils/UrlUtils';
|
import { abbreviateUrl } from '../../../utils/UrlUtils';
|
||||||
import {sleep} from "../../../utils/promise";
|
import {sleep} from "../../../utils/promise";
|
||||||
|
import {Key} from "../../../Keyboard";
|
||||||
|
|
||||||
const TRUNCATE_QUERY_LIST = 40;
|
const TRUNCATE_QUERY_LIST = 40;
|
||||||
const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200;
|
const QUERY_USER_DIRECTORY_DEBOUNCE_MS = 200;
|
||||||
|
@ -144,27 +145,27 @@ module.exports = createReactClass({
|
||||||
onKeyDown: function(e) {
|
onKeyDown: function(e) {
|
||||||
const textInput = this._textinput.current ? this._textinput.current.value : undefined;
|
const textInput = this._textinput.current ? this._textinput.current.value : undefined;
|
||||||
|
|
||||||
if (e.keyCode === 27) { // escape
|
if (e.key === Key.ESCAPE) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.onFinished(false);
|
this.props.onFinished(false);
|
||||||
} else if (e.keyCode === 38) { // up arrow
|
} else if (e.key === Key.ARROW_UP) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (this.addressSelector) this.addressSelector.moveSelectionUp();
|
if (this.addressSelector) this.addressSelector.moveSelectionUp();
|
||||||
} else if (e.keyCode === 40) { // down arrow
|
} else if (e.key === Key.ARROW_DOWN) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (this.addressSelector) this.addressSelector.moveSelectionDown();
|
if (this.addressSelector) this.addressSelector.moveSelectionDown();
|
||||||
} else if (this.state.suggestedList.length > 0 && (e.keyCode === 188 || e.keyCode === 13 || e.keyCode === 9)) { // comma or enter or tab
|
} else if (this.state.suggestedList.length > 0 && [Key.COMMA, Key.ENTER, Key.TAB].includes(e.key)) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (this.addressSelector) this.addressSelector.chooseSelection();
|
if (this.addressSelector) this.addressSelector.chooseSelection();
|
||||||
} else if (textInput.length === 0 && this.state.selectedList.length && e.keyCode === 8) { // backspace
|
} else if (textInput.length === 0 && this.state.selectedList.length && e.key === Key.BACKSPACE) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.onDismissed(this.state.selectedList.length - 1)();
|
this.onDismissed(this.state.selectedList.length - 1)();
|
||||||
} else if (e.keyCode === 13) { // enter
|
} else if (e.key === Key.ENTER) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (textInput === '') {
|
if (textInput === '') {
|
||||||
|
@ -173,7 +174,7 @@ module.exports = createReactClass({
|
||||||
} else {
|
} else {
|
||||||
this._addAddressesToList([textInput]);
|
this._addAddressesToList([textInput]);
|
||||||
}
|
}
|
||||||
} else if (textInput && (e.keyCode === 188 || e.keyCode === 9)) { // comma or tab
|
} else if (e.key === Key.COMMA || e.key === Key.TAB) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._addAddressesToList([textInput]);
|
this._addAddressesToList([textInput]);
|
||||||
|
|
|
@ -24,7 +24,7 @@ import classNames from 'classnames';
|
||||||
|
|
||||||
import { MatrixClient } from 'matrix-js-sdk';
|
import { MatrixClient } from 'matrix-js-sdk';
|
||||||
|
|
||||||
import { KeyCode } from '../../../Keyboard';
|
import { Key } from '../../../Keyboard';
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
|
@ -102,7 +102,7 @@ export default createReactClass({
|
||||||
if (this.props.onKeyDown) {
|
if (this.props.onKeyDown) {
|
||||||
this.props.onKeyDown(e);
|
this.props.onKeyDown(e);
|
||||||
}
|
}
|
||||||
if (this.props.hasCancel && e.keyCode === KeyCode.ESCAPE) {
|
if (this.props.hasCancel && e.key === Key.ESCAPE) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.props.onFinished(false);
|
this.props.onFinished(false);
|
||||||
|
|
|
@ -21,7 +21,7 @@ import PropTypes from 'prop-types';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { KeyCode } from '../../../Keyboard';
|
import { Key } from '../../../Keyboard';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import { SAFE_LOCALPART_REGEX } from '../../../Registration';
|
import { SAFE_LOCALPART_REGEX } from '../../../Registration';
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ export default createReactClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onKeyUp: function(ev) {
|
onKeyUp: function(ev) {
|
||||||
if (ev.keyCode === KeyCode.ENTER) {
|
if (ev.key === Key.ENTER) {
|
||||||
this.onSubmit();
|
this.onSubmit();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { KeyCode } from '../../../Keyboard';
|
import {Key} from '../../../Keyboard';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AccessibleButton is a generic wrapper for any element that should be treated
|
* AccessibleButton is a generic wrapper for any element that should be treated
|
||||||
|
@ -40,23 +40,23 @@ export default function AccessibleButton(props) {
|
||||||
// Browsers handle space and enter keypresses differently and we are only adjusting to the
|
// Browsers handle space and enter keypresses differently and we are only adjusting to the
|
||||||
// inconsistencies here
|
// inconsistencies here
|
||||||
restProps.onKeyDown = function(e) {
|
restProps.onKeyDown = function(e) {
|
||||||
if (e.keyCode === KeyCode.ENTER) {
|
if (e.key === Key.ENTER) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return onClick(e);
|
return onClick(e);
|
||||||
}
|
}
|
||||||
if (e.keyCode === KeyCode.SPACE) {
|
if (e.key === Key.SPACE) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
restProps.onKeyUp = function(e) {
|
restProps.onKeyUp = function(e) {
|
||||||
if (e.keyCode === KeyCode.SPACE) {
|
if (e.key === Key.SPACE) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return onClick(e);
|
return onClick(e);
|
||||||
}
|
}
|
||||||
if (e.keyCode === KeyCode.ENTER) {
|
if (e.key === Key.ENTER) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ const AccessibleButton = require('../../../components/views/elements/AccessibleB
|
||||||
const Modal = require('../../../Modal');
|
const Modal = require('../../../Modal');
|
||||||
const sdk = require('../../../index');
|
const sdk = require('../../../index');
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
|
import {Key} from "../../../Keyboard";
|
||||||
|
|
||||||
export default class ImageView extends React.Component {
|
export default class ImageView extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -62,7 +63,7 @@ export default class ImageView extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown = (ev) => {
|
onKeyDown = (ev) => {
|
||||||
if (ev.keyCode === 27) { // escape
|
if (ev.key === Key.ESCAPE) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.props.onFinished();
|
this.props.onFinished();
|
||||||
|
|
|
@ -19,8 +19,7 @@ import PropTypes from 'prop-types';
|
||||||
import {_t} from "../../../languageHandler";
|
import {_t} from "../../../languageHandler";
|
||||||
import MatrixClientPeg from "../../../MatrixClientPeg";
|
import MatrixClientPeg from "../../../MatrixClientPeg";
|
||||||
import Field from "../elements/Field";
|
import Field from "../elements/Field";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import sdk from "../../../index";
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
// TODO: Merge with ProfileSettings?
|
// TODO: Merge with ProfileSettings?
|
||||||
export default class RoomProfileSettings extends React.Component {
|
export default class RoomProfileSettings extends React.Component {
|
||||||
|
@ -62,13 +61,20 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
this._avatarUpload = createRef();
|
this._avatarUpload = createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
_uploadAvatar = (e) => {
|
_uploadAvatar = () => {
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
this._avatarUpload.current.click();
|
this._avatarUpload.current.click();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_removeAvatar = () => {
|
||||||
|
// clear file upload field so same file can be selected
|
||||||
|
this._avatarUpload.current.value = "";
|
||||||
|
this.setState({
|
||||||
|
avatarUrl: undefined,
|
||||||
|
avatarFile: undefined,
|
||||||
|
enableProfileSave: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
_saveProfile = async (e) => {
|
_saveProfile = async (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -139,45 +145,8 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
// TODO: Why is rendering a box with an overlay so complicated? Can the DOM be reduced?
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
const AvatarSetting = sdk.getComponent('settings.AvatarSetting');
|
||||||
let showOverlayAnyways = true;
|
|
||||||
let avatarElement = <div className="mx_ProfileSettings_avatarPlaceholder" />;
|
|
||||||
if (this.state.avatarUrl) {
|
|
||||||
showOverlayAnyways = false;
|
|
||||||
avatarElement = <img src={this.state.avatarUrl}
|
|
||||||
alt={_t("Room avatar")} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const avatarOverlayClasses = classNames({
|
|
||||||
"mx_ProfileSettings_avatarOverlay": true,
|
|
||||||
"mx_ProfileSettings_avatarOverlay_show": showOverlayAnyways,
|
|
||||||
});
|
|
||||||
let avatarHoverElement = (
|
|
||||||
<div className={avatarOverlayClasses} onClick={this._uploadAvatar}>
|
|
||||||
<span className="mx_ProfileSettings_avatarOverlayText">{_t("Upload room avatar")}</span>
|
|
||||||
<div className="mx_ProfileSettings_avatarOverlayImgContainer">
|
|
||||||
<div className="mx_ProfileSettings_avatarOverlayImg" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
if (!this.state.canSetAvatar) {
|
|
||||||
if (!showOverlayAnyways) {
|
|
||||||
avatarHoverElement = null;
|
|
||||||
} else {
|
|
||||||
const disabledOverlayClasses = classNames({
|
|
||||||
"mx_ProfileSettings_avatarOverlay": true,
|
|
||||||
"mx_ProfileSettings_avatarOverlay_show": true,
|
|
||||||
"mx_ProfileSettings_avatarOverlay_disabled": true,
|
|
||||||
});
|
|
||||||
avatarHoverElement = (
|
|
||||||
<div className={disabledOverlayClasses}>
|
|
||||||
<span className="mx_ProfileSettings_noAvatarText">{_t("No room avatar")}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this._saveProfile} autoComplete="off" noValidate={true}>
|
<form onSubmit={this._saveProfile} autoComplete="off" noValidate={true}>
|
||||||
<input type="file" ref={this._avatarUpload} className="mx_ProfileSettings_avatarUpload"
|
<input type="file" ref={this._avatarUpload} className="mx_ProfileSettings_avatarUpload"
|
||||||
|
@ -191,10 +160,12 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
type="text" value={this.state.topic} autoComplete="off"
|
type="text" value={this.state.topic} autoComplete="off"
|
||||||
onChange={this._onTopicChanged} element="textarea" />
|
onChange={this._onTopicChanged} element="textarea" />
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_ProfileSettings_avatar">
|
<AvatarSetting
|
||||||
{avatarElement}
|
avatarUrl={this.state.avatarUrl}
|
||||||
{avatarHoverElement}
|
avatarName={this.state.displayName || this.props.roomId}
|
||||||
</div>
|
avatarAltText={_t("Room avatar")}
|
||||||
|
uploadAvatar={this.state.canSetAvatar ? this._uploadAvatar : undefined}
|
||||||
|
removeAvatar={this.state.canSetAvatar ? this._removeAvatar : undefined} />
|
||||||
</div>
|
</div>
|
||||||
<AccessibleButton onClick={this._saveProfile} kind="primary"
|
<AccessibleButton onClick={this._saveProfile} kind="primary"
|
||||||
disabled={!this.state.enableProfileSave}>
|
disabled={!this.state.enableProfileSave}>
|
||||||
|
|
|
@ -20,7 +20,7 @@ import PropTypes from 'prop-types';
|
||||||
import createReactClass from 'create-react-class';
|
import createReactClass from 'create-react-class';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import dis from '../../../dispatcher';
|
import dis from '../../../dispatcher';
|
||||||
import { KeyCode } from '../../../Keyboard';
|
import {Key} from '../../../Keyboard';
|
||||||
|
|
||||||
|
|
||||||
module.exports = createReactClass({
|
module.exports = createReactClass({
|
||||||
|
@ -52,8 +52,8 @@ module.exports = createReactClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
_onKeyDown: function(ev) {
|
_onKeyDown: function(ev) {
|
||||||
switch (ev.keyCode) {
|
switch (ev.key) {
|
||||||
case KeyCode.ESCAPE:
|
case Key.ESCAPE:
|
||||||
this.props.onCancelClick();
|
this.props.onCancelClick();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ import classNames from 'classnames';
|
||||||
import MatrixClientPeg from '../../../MatrixClientPeg';
|
import MatrixClientPeg from '../../../MatrixClientPeg';
|
||||||
import type {MatrixClient} from 'matrix-js-sdk/lib/matrix';
|
import type {MatrixClient} from 'matrix-js-sdk/lib/matrix';
|
||||||
import {processCommandInput} from '../../../SlashCommands';
|
import {processCommandInput} from '../../../SlashCommands';
|
||||||
import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../../Keyboard';
|
import { isOnlyCtrlOrCmdKeyEvent, Key} from '../../../Keyboard';
|
||||||
import Modal from '../../../Modal';
|
import Modal from '../../../Modal';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
|
@ -608,12 +608,12 @@ export default class MessageComposerInput extends React.Component {
|
||||||
// Navigate autocomplete list with arrow keys
|
// Navigate autocomplete list with arrow keys
|
||||||
if (this.autocomplete.countCompletions() > 0) {
|
if (this.autocomplete.countCompletions() > 0) {
|
||||||
if (!(ev.ctrlKey || ev.shiftKey || ev.altKey || ev.metaKey)) {
|
if (!(ev.ctrlKey || ev.shiftKey || ev.altKey || ev.metaKey)) {
|
||||||
switch (ev.keyCode) {
|
switch (ev.key) {
|
||||||
case KeyCode.UP:
|
case Key.ARROW_UP:
|
||||||
this.autocomplete.moveSelection(-1);
|
this.autocomplete.moveSelection(-1);
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
return true;
|
return true;
|
||||||
case KeyCode.DOWN:
|
case Key.ARROW_DOWN:
|
||||||
this.autocomplete.moveSelection(+1);
|
this.autocomplete.moveSelection(+1);
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
return true;
|
return true;
|
||||||
|
@ -623,38 +623,38 @@ export default class MessageComposerInput extends React.Component {
|
||||||
|
|
||||||
// skip void nodes - see
|
// skip void nodes - see
|
||||||
// https://github.com/ianstormtaylor/slate/issues/762#issuecomment-304855095
|
// https://github.com/ianstormtaylor/slate/issues/762#issuecomment-304855095
|
||||||
if (ev.keyCode === KeyCode.LEFT) {
|
if (ev.key === Key.ARROW_LEFT) {
|
||||||
this.direction = 'Previous';
|
this.direction = 'Previous';
|
||||||
} else if (ev.keyCode === KeyCode.RIGHT) {
|
} else if (ev.key === Key.ARROW_RIGHT) {
|
||||||
this.direction = 'Next';
|
this.direction = 'Next';
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ev.keyCode) {
|
switch (ev.key) {
|
||||||
case KeyCode.ENTER:
|
case Key.ENTER:
|
||||||
return this.handleReturn(ev, change);
|
return this.handleReturn(ev, change);
|
||||||
case KeyCode.BACKSPACE:
|
case Key.BACKSPACE:
|
||||||
return this.onBackspace(ev, change);
|
return this.onBackspace(ev, change);
|
||||||
case KeyCode.UP:
|
case Key.ARROW_UP:
|
||||||
return this.onVerticalArrow(ev, true);
|
return this.onVerticalArrow(ev, true);
|
||||||
case KeyCode.DOWN:
|
case Key.ARROW_DOWN:
|
||||||
return this.onVerticalArrow(ev, false);
|
return this.onVerticalArrow(ev, false);
|
||||||
case KeyCode.TAB:
|
case Key.TAB:
|
||||||
return this.onTab(ev);
|
return this.onTab(ev);
|
||||||
case KeyCode.ESCAPE:
|
case Key.ESCAPE:
|
||||||
return this.onEscape(ev);
|
return this.onEscape(ev);
|
||||||
case KeyCode.SPACE:
|
case Key.SPACE:
|
||||||
return this.onSpace(ev, change);
|
return this.onSpace(ev, change);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOnlyCtrlOrCmdKeyEvent(ev)) {
|
if (isOnlyCtrlOrCmdKeyEvent(ev)) {
|
||||||
const ctrlCmdCommand = {
|
const ctrlCmdCommand = {
|
||||||
// C-m => Toggles between rich text and markdown modes
|
// C-m => Toggles between rich text and markdown modes
|
||||||
[KeyCode.KEY_M]: 'toggle-mode',
|
[Key.M]: 'toggle-mode',
|
||||||
[KeyCode.KEY_B]: 'bold',
|
[Key.B]: 'bold',
|
||||||
[KeyCode.KEY_I]: 'italic',
|
[Key.I]: 'italic',
|
||||||
[KeyCode.KEY_U]: 'underlined',
|
[Key.U]: 'underlined',
|
||||||
[KeyCode.KEY_J]: 'inline-code',
|
[Key.J]: 'inline-code',
|
||||||
}[ev.keyCode];
|
}[ev.key];
|
||||||
|
|
||||||
if (ctrlCmdCommand) {
|
if (ctrlCmdCommand) {
|
||||||
ev.preventDefault(); // to prevent clashing with Mac's minimize window
|
ev.preventDefault(); // to prevent clashing with Mac's minimize window
|
||||||
|
|
|
@ -19,6 +19,7 @@ import createReactClass from 'create-react-class';
|
||||||
const classNames = require('classnames');
|
const classNames = require('classnames');
|
||||||
const AccessibleButton = require('../../../components/views/elements/AccessibleButton');
|
const AccessibleButton = require('../../../components/views/elements/AccessibleButton');
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
|
import {Key} from "../../../Keyboard";
|
||||||
|
|
||||||
module.exports = createReactClass({
|
module.exports = createReactClass({
|
||||||
displayName: 'SearchBar',
|
displayName: 'SearchBar',
|
||||||
|
@ -42,11 +43,13 @@ module.exports = createReactClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onSearchChange: function(e) {
|
onSearchChange: function(e) {
|
||||||
if (e.keyCode === 13) { // on enter...
|
switch (e.key) {
|
||||||
|
case Key.ENTER:
|
||||||
this.onSearch();
|
this.onSearch();
|
||||||
}
|
break;
|
||||||
if (e.keyCode === 27) { // escape...
|
case Key.ESCAPE:
|
||||||
this.props.onCancelClick();
|
this.props.onCancelClick();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
78
src/components/views/settings/AvatarSetting.js
Normal file
78
src/components/views/settings/AvatarSetting.js
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, {useCallback} from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
import sdk from "../../../index";
|
||||||
|
import {_t} from "../../../languageHandler";
|
||||||
|
import Modal from "../../../Modal";
|
||||||
|
|
||||||
|
const AvatarSetting = ({avatarUrl, avatarAltText, avatarName, uploadAvatar, removeAvatar}) => {
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
|
||||||
|
const openImageView = useCallback(() => {
|
||||||
|
const ImageView = sdk.getComponent("elements.ImageView");
|
||||||
|
Modal.createDialog(ImageView, {
|
||||||
|
src: avatarUrl,
|
||||||
|
name: avatarName,
|
||||||
|
}, "mx_Dialog_lightbox");
|
||||||
|
}, [avatarUrl, avatarName]);
|
||||||
|
|
||||||
|
let avatarElement = <div className="mx_AvatarSetting_avatarPlaceholder" />;
|
||||||
|
if (avatarUrl) {
|
||||||
|
avatarElement = (
|
||||||
|
<AccessibleButton
|
||||||
|
element="img"
|
||||||
|
src={avatarUrl}
|
||||||
|
alt={avatarAltText}
|
||||||
|
aria-label={avatarAltText}
|
||||||
|
onClick={openImageView} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let uploadAvatarBtn;
|
||||||
|
if (uploadAvatar) {
|
||||||
|
// insert an empty div to be the host for a css mask containing the upload.svg
|
||||||
|
uploadAvatarBtn = <AccessibleButton onClick={uploadAvatar} kind="primary">
|
||||||
|
<div> </div>
|
||||||
|
{_t("Upload")}
|
||||||
|
</AccessibleButton>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let removeAvatarBtn;
|
||||||
|
if (avatarUrl && removeAvatar) {
|
||||||
|
removeAvatarBtn = <AccessibleButton onClick={removeAvatar} kind="link_sm">
|
||||||
|
{_t("Remove")}
|
||||||
|
</AccessibleButton>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div className="mx_AvatarSetting_avatar">
|
||||||
|
{ avatarElement }
|
||||||
|
{ uploadAvatarBtn }
|
||||||
|
{ removeAvatarBtn }
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
AvatarSetting.propTypes = {
|
||||||
|
avatarUrl: PropTypes.string,
|
||||||
|
avatarName: PropTypes.string.isRequired, // name of user/room the avatar belongs to
|
||||||
|
uploadAvatar: PropTypes.func,
|
||||||
|
removeAvatar: PropTypes.func,
|
||||||
|
avatarAltText: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AvatarSetting;
|
|
@ -20,6 +20,7 @@ import PropTypes from 'prop-types';
|
||||||
import sdk from '../../../index';
|
import sdk from '../../../index';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import dis from '../../../dispatcher';
|
import dis from '../../../dispatcher';
|
||||||
|
import {Key} from "../../../Keyboard";
|
||||||
|
|
||||||
export default class IntegrationManager extends React.Component {
|
export default class IntegrationManager extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -52,7 +53,7 @@ export default class IntegrationManager extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown = (ev) => {
|
onKeyDown = (ev) => {
|
||||||
if (ev.keyCode === 27) { // escape
|
if (ev.key === Key.ESCAPE) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.props.onFinished();
|
this.props.onFinished();
|
||||||
|
|
|
@ -18,10 +18,9 @@ import React, {createRef} from 'react';
|
||||||
import {_t} from "../../../languageHandler";
|
import {_t} from "../../../languageHandler";
|
||||||
import MatrixClientPeg from "../../../MatrixClientPeg";
|
import MatrixClientPeg from "../../../MatrixClientPeg";
|
||||||
import Field from "../elements/Field";
|
import Field from "../elements/Field";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import {User} from "matrix-js-sdk";
|
import {User} from "matrix-js-sdk";
|
||||||
import { getHostingLink } from '../../../utils/HostingLink';
|
import { getHostingLink } from '../../../utils/HostingLink';
|
||||||
|
import sdk from "../../../index";
|
||||||
|
|
||||||
export default class ProfileSettings extends React.Component {
|
export default class ProfileSettings extends React.Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -52,13 +51,20 @@ export default class ProfileSettings extends React.Component {
|
||||||
this._avatarUpload = createRef();
|
this._avatarUpload = createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
_uploadAvatar = (e) => {
|
_uploadAvatar = () => {
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
this._avatarUpload.current.click();
|
this._avatarUpload.current.click();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_removeAvatar = () => {
|
||||||
|
// clear file upload field so same file can be selected
|
||||||
|
this._avatarUpload.current.value = "";
|
||||||
|
this.setState({
|
||||||
|
avatarUrl: undefined,
|
||||||
|
avatarFile: undefined,
|
||||||
|
enableProfileSave: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
_saveProfile = async (e) => {
|
_saveProfile = async (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
@ -117,29 +123,6 @@ export default class ProfileSettings extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
// TODO: Why is rendering a box with an overlay so complicated? Can the DOM be reduced?
|
|
||||||
|
|
||||||
let showOverlayAnyways = true;
|
|
||||||
let avatarElement = <div className="mx_ProfileSettings_avatarPlaceholder" />;
|
|
||||||
if (this.state.avatarUrl) {
|
|
||||||
showOverlayAnyways = false;
|
|
||||||
avatarElement = <img src={this.state.avatarUrl}
|
|
||||||
alt={_t("Profile picture")} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const avatarOverlayClasses = classNames({
|
|
||||||
"mx_ProfileSettings_avatarOverlay": true,
|
|
||||||
"mx_ProfileSettings_avatarOverlay_show": showOverlayAnyways,
|
|
||||||
});
|
|
||||||
const avatarHoverElement = (
|
|
||||||
<div className={avatarOverlayClasses} onClick={this._uploadAvatar}>
|
|
||||||
<span className="mx_ProfileSettings_avatarOverlayText">{_t("Upload profile picture")}</span>
|
|
||||||
<div className="mx_ProfileSettings_avatarOverlayImgContainer">
|
|
||||||
<div className="mx_ProfileSettings_avatarOverlayImg" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const hostingSignupLink = getHostingLink('user-settings');
|
const hostingSignupLink = getHostingLink('user-settings');
|
||||||
let hostingSignup = null;
|
let hostingSignup = null;
|
||||||
if (hostingSignupLink) {
|
if (hostingSignupLink) {
|
||||||
|
@ -156,6 +139,8 @@ export default class ProfileSettings extends React.Component {
|
||||||
</span>;
|
</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
|
const AvatarSetting = sdk.getComponent('settings.AvatarSetting');
|
||||||
return (
|
return (
|
||||||
<form onSubmit={this._saveProfile} autoComplete="off" noValidate={true}>
|
<form onSubmit={this._saveProfile} autoComplete="off" noValidate={true}>
|
||||||
<input type="file" ref={this._avatarUpload} className="mx_ProfileSettings_avatarUpload"
|
<input type="file" ref={this._avatarUpload} className="mx_ProfileSettings_avatarUpload"
|
||||||
|
@ -170,10 +155,12 @@ export default class ProfileSettings extends React.Component {
|
||||||
type="text" value={this.state.displayName} autoComplete="off"
|
type="text" value={this.state.displayName} autoComplete="off"
|
||||||
onChange={this._onDisplayNameChanged} />
|
onChange={this._onDisplayNameChanged} />
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_ProfileSettings_avatar">
|
<AvatarSetting
|
||||||
{avatarElement}
|
avatarUrl={this.state.avatarUrl}
|
||||||
{avatarHoverElement}
|
avatarName={this.state.displayName || this.state.userId}
|
||||||
</div>
|
avatarAltText={_t("Profile picture")}
|
||||||
|
uploadAvatar={this._uploadAvatar}
|
||||||
|
removeAvatar={this._removeAvatar} />
|
||||||
</div>
|
</div>
|
||||||
<AccessibleButton onClick={this._saveProfile} kind="primary"
|
<AccessibleButton onClick={this._saveProfile} kind="primary"
|
||||||
disabled={!this.state.enableProfileSave}>
|
disabled={!this.state.enableProfileSave}>
|
||||||
|
|
|
@ -499,6 +499,8 @@
|
||||||
"Pin": "Pin",
|
"Pin": "Pin",
|
||||||
"Decline (%(counter)s)": "Decline (%(counter)s)",
|
"Decline (%(counter)s)": "Decline (%(counter)s)",
|
||||||
"Accept <policyLink /> to continue:": "Accept <policyLink /> to continue:",
|
"Accept <policyLink /> to continue:": "Accept <policyLink /> to continue:",
|
||||||
|
"Upload": "Upload",
|
||||||
|
"Remove": "Remove",
|
||||||
"Failed to upload profile picture!": "Failed to upload profile picture!",
|
"Failed to upload profile picture!": "Failed to upload profile picture!",
|
||||||
"Upload new:": "Upload new:",
|
"Upload new:": "Upload new:",
|
||||||
"No display name": "No display name",
|
"No display name": "No display name",
|
||||||
|
@ -597,10 +599,9 @@
|
||||||
"Off": "Off",
|
"Off": "Off",
|
||||||
"On": "On",
|
"On": "On",
|
||||||
"Noisy": "Noisy",
|
"Noisy": "Noisy",
|
||||||
"Profile picture": "Profile picture",
|
|
||||||
"Upload profile picture": "Upload profile picture",
|
|
||||||
"<a>Upgrade</a> to your own domain": "<a>Upgrade</a> to your own domain",
|
"<a>Upgrade</a> to your own domain": "<a>Upgrade</a> to your own domain",
|
||||||
"Display Name": "Display Name",
|
"Display Name": "Display Name",
|
||||||
|
"Profile picture": "Profile picture",
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Identity Server URL must be HTTPS": "Identity Server URL must be HTTPS",
|
"Identity Server URL must be HTTPS": "Identity Server URL must be HTTPS",
|
||||||
"Not a valid Identity Server (status code %(code)s)": "Not a valid Identity Server (status code %(code)s)",
|
"Not a valid Identity Server (status code %(code)s)": "Not a valid Identity Server (status code %(code)s)",
|
||||||
|
@ -691,7 +692,6 @@
|
||||||
"User rules": "User rules",
|
"User rules": "User rules",
|
||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"You have not ignored anyone.": "You have not ignored anyone.",
|
"You have not ignored anyone.": "You have not ignored anyone.",
|
||||||
"Remove": "Remove",
|
|
||||||
"You are currently ignoring:": "You are currently ignoring:",
|
"You are currently ignoring:": "You are currently ignoring:",
|
||||||
"You are not subscribed to any lists": "You are not subscribed to any lists",
|
"You are not subscribed to any lists": "You are not subscribed to any lists",
|
||||||
"Unsubscribe": "Unsubscribe",
|
"Unsubscribe": "Unsubscribe",
|
||||||
|
@ -1097,11 +1097,9 @@
|
||||||
"Showing flair for these communities:": "Showing flair for these communities:",
|
"Showing flair for these communities:": "Showing flair for these communities:",
|
||||||
"This room is not showing flair for any communities": "This room is not showing flair for any communities",
|
"This room is not showing flair for any communities": "This room is not showing flair for any communities",
|
||||||
"New community ID (e.g. +foo:%(localDomain)s)": "New community ID (e.g. +foo:%(localDomain)s)",
|
"New community ID (e.g. +foo:%(localDomain)s)": "New community ID (e.g. +foo:%(localDomain)s)",
|
||||||
"Room avatar": "Room avatar",
|
|
||||||
"Upload room avatar": "Upload room avatar",
|
|
||||||
"No room avatar": "No room avatar",
|
|
||||||
"Room Name": "Room Name",
|
"Room Name": "Room Name",
|
||||||
"Room Topic": "Room Topic",
|
"Room Topic": "Room Topic",
|
||||||
|
"Room avatar": "Room avatar",
|
||||||
"You have <a>enabled</a> URL previews by default.": "You have <a>enabled</a> URL previews by default.",
|
"You have <a>enabled</a> URL previews by default.": "You have <a>enabled</a> URL previews by default.",
|
||||||
"You have <a>disabled</a> URL previews by default.": "You have <a>disabled</a> URL previews by default.",
|
"You have <a>disabled</a> URL previews by default.": "You have <a>disabled</a> URL previews by default.",
|
||||||
"URL previews are enabled by default for participants in this room.": "URL previews are enabled by default for participants in this room.",
|
"URL previews are enabled by default for participants in this room.": "URL previews are enabled by default for participants in this room.",
|
||||||
|
@ -1545,7 +1543,6 @@
|
||||||
"Upload files (%(current)s of %(total)s)": "Upload files (%(current)s of %(total)s)",
|
"Upload files (%(current)s of %(total)s)": "Upload files (%(current)s of %(total)s)",
|
||||||
"Upload files": "Upload files",
|
"Upload files": "Upload files",
|
||||||
"Upload all": "Upload all",
|
"Upload all": "Upload all",
|
||||||
"Upload": "Upload",
|
|
||||||
"This file is <b>too large</b> to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.": "This file is <b>too large</b> to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.",
|
"This file is <b>too large</b> to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.": "This file is <b>too large</b> to upload. The file size limit is %(limit)s but this file is %(sizeOfThisFile)s.",
|
||||||
"These files are <b>too large</b> to upload. The file size limit is %(limit)s.": "These files are <b>too large</b> to upload. The file size limit is %(limit)s.",
|
"These files are <b>too large</b> to upload. The file size limit is %(limit)s.": "These files are <b>too large</b> to upload. The file size limit is %(limit)s.",
|
||||||
"Some files are <b>too large</b> to be uploaded. The file size limit is %(limit)s.": "Some files are <b>too large</b> to be uploaded. The file size limit is %(limit)s.",
|
"Some files are <b>too large</b> to be uploaded. The file size limit is %(limit)s.": "Some files are <b>too large</b> to be uploaded. The file size limit is %(limit)s.",
|
||||||
|
|
Loading…
Reference in a new issue