Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Weblate 2017-12-01 12:04:25 +00:00
commit b8d7881663
11 changed files with 84 additions and 35 deletions

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2016 OpenMarket Ltd Copyright 2016 OpenMarket Ltd
Copyright 2017 New Vector Ltd
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,7 +16,7 @@ limitations under the License.
*/ */
/* a selection of key codes, as used in KeyboardEvent.keyCode */ /* a selection of key codes, as used in KeyboardEvent.keyCode */
module.exports = { export const KeyCode = {
BACKSPACE: 8, BACKSPACE: 8,
TAB: 9, TAB: 9,
ENTER: 13, ENTER: 13,
@ -58,3 +59,12 @@ module.exports = {
KEY_Y: 89, KEY_Y: 89,
KEY_Z: 90, KEY_Z: 90,
}; };
export function isOnlyCtrlOrCmdKeyEvent(ev) {
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
if (isMac) {
return ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey;
} else {
return ev.ctrlKey && !ev.altKey && !ev.metaKey && !ev.shiftKey;
}
}

View file

@ -19,7 +19,7 @@ limitations under the License.
import * as Matrix from 'matrix-js-sdk'; import * as Matrix from 'matrix-js-sdk';
import React from 'react'; import React from 'react';
import KeyCode from '../../KeyCode'; import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard';
import Notifier from '../../Notifier'; import Notifier from '../../Notifier';
import PageTypes from '../../PageTypes'; import PageTypes from '../../PageTypes';
import CallMediaHandler from '../../CallMediaHandler'; import CallMediaHandler from '../../CallMediaHandler';
@ -153,13 +153,7 @@ export default React.createClass({
*/ */
let handled = false; let handled = false;
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev);
let ctrlCmdOnly;
if (isMac) {
ctrlCmdOnly = ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey;
} else {
ctrlCmdOnly = ev.ctrlKey && !ev.altKey && !ev.metaKey && !ev.shiftKey;
}
switch (ev.keyCode) { switch (ev.keyCode) {
case KeyCode.UP: case KeyCode.UP:

View file

@ -41,7 +41,7 @@ const rate_limited_func = require('../../ratelimitedfunc');
const ObjectUtils = require('../../ObjectUtils'); const ObjectUtils = require('../../ObjectUtils');
const Rooms = require('../../Rooms'); const Rooms = require('../../Rooms');
import KeyCode from '../../KeyCode'; import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard';
import RoomViewStore from '../../stores/RoomViewStore'; import RoomViewStore from '../../stores/RoomViewStore';
import RoomScrollStateStore from '../../stores/RoomScrollStateStore'; import RoomScrollStateStore from '../../stores/RoomScrollStateStore';
@ -433,13 +433,7 @@ module.exports = React.createClass({
onKeyDown: function(ev) { onKeyDown: function(ev) {
let handled = false; let handled = false;
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev);
let ctrlCmdOnly;
if (isMac) {
ctrlCmdOnly = ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey;
} else {
ctrlCmdOnly = ev.ctrlKey && !ev.altKey && !ev.metaKey && !ev.shiftKey;
}
switch (ev.keyCode) { switch (ev.keyCode) {
case KeyCode.KEY_D: case KeyCode.KEY_D:

View file

@ -18,7 +18,7 @@ const React = require("react");
const ReactDOM = require("react-dom"); const ReactDOM = require("react-dom");
const GeminiScrollbar = require('react-gemini-scrollbar'); const GeminiScrollbar = require('react-gemini-scrollbar');
import Promise from 'bluebird'; import Promise from 'bluebird';
const KeyCode = require('../../KeyCode'); import { KeyCode } from '../../Keyboard';
const DEBUG_SCROLL = false; const DEBUG_SCROLL = false;
// var DEBUG_SCROLL = true; // var DEBUG_SCROLL = true;

View file

@ -22,6 +22,7 @@ import FilterStore from '../../stores/FilterStore';
import FlairStore from '../../stores/FlairStore'; import FlairStore from '../../stores/FlairStore';
import sdk from '../../index'; import sdk from '../../index';
import dis from '../../dispatcher'; import dis from '../../dispatcher';
import { isOnlyCtrlOrCmdKeyEvent } from '../../Keyboard';
const TagTile = React.createClass({ const TagTile = React.createClass({
displayName: 'TagTile', displayName: 'TagTile',
@ -46,6 +47,8 @@ const TagTile = React.createClass({
dis.dispatch({ dis.dispatch({
action: 'select_tag', action: 'select_tag',
tag: this.props.groupProfile.groupId, tag: this.props.groupProfile.groupId,
ctrlOrCmdKey: isOnlyCtrlOrCmdKeyEvent(e),
shiftKey: e.shiftKey,
}); });
}, },
@ -144,6 +147,10 @@ export default React.createClass({
const joinedGroupProfiles = await Promise.all(joinedGroupIds.map( const joinedGroupProfiles = await Promise.all(joinedGroupIds.map(
(groupId) => FlairStore.getGroupProfileCached(this.context.matrixClient, groupId), (groupId) => FlairStore.getGroupProfileCached(this.context.matrixClient, groupId),
)); ));
dis.dispatch({
action: 'all_tags',
tags: joinedGroupIds,
});
this.setState({joinedGroupProfiles}); this.setState({joinedGroupProfiles});
}, },

View file

@ -31,7 +31,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");
const KeyCode = require('../../KeyCode'); import { KeyCode } from '../../Keyboard';
const PAGINATE_SIZE = 20; const PAGINATE_SIZE = 20;
const INITIAL_SIZE = 20; const INITIAL_SIZE = 20;

View file

@ -16,7 +16,7 @@ limitations under the License.
import React from 'react'; import React from 'react';
import * as KeyCode from '../../../KeyCode'; import { KeyCode } from '../../../Keyboard';
import AccessibleButton from '../elements/AccessibleButton'; import AccessibleButton from '../elements/AccessibleButton';
import sdk from '../../../index'; import sdk from '../../../index';

View file

@ -20,7 +20,7 @@ import React from 'react';
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 '../../../KeyCode'; import { KeyCode } from '../../../Keyboard';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
// The amount of time to wait for further changes to the input username before // The amount of time to wait for further changes to the input username before

View file

@ -18,7 +18,7 @@
import React from 'react'; import React from 'react';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import dis from '../../../dispatcher'; import dis from '../../../dispatcher';
import KeyCode from '../../../KeyCode'; import { KeyCode } from '../../../Keyboard';
module.exports = React.createClass({ module.exports = React.createClass({

View file

@ -28,7 +28,7 @@ import Promise from 'bluebird';
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 SlashCommands from '../../../SlashCommands'; import SlashCommands from '../../../SlashCommands';
import KeyCode from '../../../KeyCode'; import { KeyCode, isOnlyCtrlOrCmdKeyEvent } from '../../../Keyboard';
import Modal from '../../../Modal'; import Modal from '../../../Modal';
import sdk from '../../../index'; import sdk from '../../../index';
import { _t, _td } from '../../../languageHandler'; import { _t, _td } from '../../../languageHandler';
@ -105,13 +105,7 @@ export default class MessageComposerInput extends React.Component {
}; };
static getKeyBinding(ev: SyntheticKeyboardEvent): string { static getKeyBinding(ev: SyntheticKeyboardEvent): string {
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; const ctrlCmdOnly = isOnlyCtrlOrCmdKeyEvent(ev);
let ctrlCmdOnly;
if (isMac) {
ctrlCmdOnly = ev.metaKey && !ev.altKey && !ev.ctrlKey && !ev.shiftKey;
} else {
ctrlCmdOnly = ev.ctrlKey && !ev.altKey && !ev.metaKey && !ev.shiftKey;
}
// Restrict a subset of key bindings to ONLY having ctrl/meta* pressed and // Restrict a subset of key bindings to ONLY having ctrl/meta* pressed and
// importantly NOT having alt, shift, meta/ctrl* pressed. draft-js does not // importantly NOT having alt, shift, meta/ctrl* pressed. draft-js does not

View file

@ -18,7 +18,10 @@ import dis from '../dispatcher';
import Analytics from '../Analytics'; import Analytics from '../Analytics';
const INITIAL_STATE = { const INITIAL_STATE = {
tags: [], allTags: [],
selectedTags: [],
// Last selected tag when shift was not being pressed
anchorTag: null,
}; };
/** /**
@ -39,15 +42,62 @@ class FilterStore extends Store {
__onDispatch(payload) { __onDispatch(payload) {
switch (payload.action) { switch (payload.action) {
case 'select_tag': case 'all_tags' :
this._setState({ this._setState({
tags: [payload.tag], allTags: payload.tags,
}); });
break;
case 'select_tag': {
let newTags = [];
// Shift-click semantics
if (payload.shiftKey) {
// Select range of tags
let start = this._state.allTags.indexOf(this._state.anchorTag);
let end = this._state.allTags.indexOf(payload.tag);
if (start === -1) {
start = end;
}
if (start > end) {
const temp = start;
start = end;
end = temp;
}
newTags = payload.ctrlOrCmdKey ? this._state.selectedTags : [];
newTags = [...new Set(
this._state.allTags.slice(start, end + 1).concat(newTags),
)];
} else {
if (payload.ctrlOrCmdKey) {
// Toggle individual tag
if (this._state.selectedTags.includes(payload.tag)) {
newTags = this._state.selectedTags.filter((t) => t !== payload.tag);
} else {
newTags = [...this._state.selectedTags, payload.tag];
}
} else {
// Select individual tag
newTags = [payload.tag];
}
// Only set the anchor tag if the tag was previously unselected, otherwise
// the next range starts with an unselected tag.
if (!this._state.selectedTags.includes(payload.tag)) {
this._setState({
anchorTag: payload.tag,
});
}
}
this._setState({
selectedTags: newTags,
});
Analytics.trackEvent('FilterStore', 'select_tag'); Analytics.trackEvent('FilterStore', 'select_tag');
}
break; break;
case 'deselect_tags': case 'deselect_tags':
this._setState({ this._setState({
tags: [], selectedTags: [],
}); });
Analytics.trackEvent('FilterStore', 'deselect_tags'); Analytics.trackEvent('FilterStore', 'deselect_tags');
break; break;
@ -55,7 +105,7 @@ class FilterStore extends Store {
} }
getSelectedTags() { getSelectedTags() {
return this._state.tags; return this._state.selectedTags;
} }
} }