Merge branch 'develop' into luke/fix-room-list-group-store-leak

This commit is contained in:
lukebarnard 2018-01-02 16:19:37 +00:00
commit 874a7bf1de
8 changed files with 68 additions and 33 deletions

View file

@ -15,6 +15,7 @@ limitations under the License.
*/ */
import Promise from 'bluebird'; import Promise from 'bluebird';
import SettingsStore from "./settings/SettingsStore";
const request = require('browser-request'); const request = require('browser-request');
const SdkConfig = require('./SdkConfig'); const SdkConfig = require('./SdkConfig');
@ -109,6 +110,7 @@ class ScalarAuthClient {
let url = SdkConfig.get().integrations_ui_url; let url = SdkConfig.get().integrations_ui_url;
url += "?scalar_token=" + encodeURIComponent(this.scalarToken); url += "?scalar_token=" + encodeURIComponent(this.scalarToken);
url += "&room_id=" + encodeURIComponent(roomId); url += "&room_id=" + encodeURIComponent(roomId);
url += "&theme=" + encodeURIComponent(SettingsStore.getValue("theme"));
if (id) { if (id) {
url += '&integ_id=' + encodeURIComponent(id); url += '&integ_id=' + encodeURIComponent(id);
} }

View file

@ -557,8 +557,16 @@ const onMessage = function(event) {
// //
// All strings start with the empty string, so for sanity return if the length // All strings start with the empty string, so for sanity return if the length
// of the event origin is 0. // of the event origin is 0.
//
// TODO -- Scalar postMessage API should be namespaced with event.data.api field
// Fix following "if" statement to respond only to specific API messages.
const url = SdkConfig.get().integrations_ui_url; const url = SdkConfig.get().integrations_ui_url;
if (event.origin.length === 0 || !url.startsWith(event.origin) || !event.data.action) { if (
event.origin.length === 0 ||
!url.startsWith(event.origin) ||
!event.data.action ||
event.data.api // Ignore messages with specific API set
) {
return; // don't log this - debugging APIs like to spam postMessage which floods the log otherwise return; // don't log this - debugging APIs like to spam postMessage which floods the log otherwise
} }

View file

@ -1068,7 +1068,7 @@ export default React.createClass({
if (!self._loggedInView) { if (!self._loggedInView) {
return true; return true;
} }
return self._loggedInView.canResetTimelineInRoom(roomId); return self._loggedInView.getDecoratedComponentInstance().canResetTimelineInRoom(roomId);
}); });
cli.on('sync', function(state, prevState) { cli.on('sync', function(state, prevState) {

View file

@ -854,9 +854,13 @@ module.exports = React.createClass({
ev.dataTransfer.dropEffect = 'none'; ev.dataTransfer.dropEffect = 'none';
const items = ev.dataTransfer.items; const items = [...ev.dataTransfer.items];
if (items.length == 1) { if (items.length >= 1) {
if (items[0].kind == 'file') { const isDraggingFiles = items.every(function(item) {
return item.kind == 'file';
});
if (isDraggingFiles) {
this.setState({ draggingFile: true }); this.setState({ draggingFile: true });
ev.dataTransfer.dropEffect = 'copy'; ev.dataTransfer.dropEffect = 'copy';
} }
@ -867,10 +871,8 @@ module.exports = React.createClass({
ev.stopPropagation(); ev.stopPropagation();
ev.preventDefault(); ev.preventDefault();
this.setState({ draggingFile: false }); this.setState({ draggingFile: false });
const files = ev.dataTransfer.files; const files = [...ev.dataTransfer.files];
if (files.length == 1) { files.forEach(this.uploadFile);
this.uploadFile(files[0]);
}
}, },
onDragLeaveOrEnd: function(ev) { onDragLeaveOrEnd: function(ev) {

View file

@ -374,7 +374,7 @@ export const MsisdnAuthEntry = React.createClass({
return ( return (
<div> <div>
<p>{ _t("A text message has been sent to %(msisdn)s", <p>{ _t("A text message has been sent to %(msisdn)s",
{ msisdn: <i>this._msisdn</i> }, { msisdn: <i>{ this._msisdn }</i> },
) } ) }
</p> </p>
<p>{ _t("Please enter the code it contains:") }</p> <p>{ _t("Please enter the code it contains:") }</p>

View file

@ -27,6 +27,7 @@ import ScalarAuthClient from '../../../ScalarAuthClient';
import ScalarMessaging from '../../../ScalarMessaging'; import ScalarMessaging from '../../../ScalarMessaging';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import WidgetUtils from '../../../WidgetUtils'; import WidgetUtils from '../../../WidgetUtils';
import SettingsStore from "../../../settings/SettingsStore";
// The maximum number of widgets that can be added in a room // The maximum number of widgets that can be added in a room
const MAX_WIDGETS = 2; const MAX_WIDGETS = 2;
@ -131,6 +132,9 @@ module.exports = React.createClass({
'$matrix_room_id': this.props.room.roomId, '$matrix_room_id': this.props.room.roomId,
'$matrix_display_name': user ? user.displayName : this.props.userId, '$matrix_display_name': user ? user.displayName : this.props.userId,
'$matrix_avatar_url': user ? MatrixClientPeg.get().mxcUrlToHttp(user.avatarUrl) : '', '$matrix_avatar_url': user ? MatrixClientPeg.get().mxcUrlToHttp(user.avatarUrl) : '',
// TODO: Namespace themes through some standard
'$theme': SettingsStore.getValue("theme"),
}; };
app.id = appId; app.id = appId;

View file

@ -89,11 +89,11 @@ module.exports = React.createClass({
this._groupStoreTokens = []; this._groupStoreTokens = [];
// A map between tags which are group IDs and the room IDs of rooms that should be kept // A map between tags which are group IDs and the room IDs of rooms that should be kept
// in the room list when filtering by that tag. // in the room list when filtering by that tag.
this._selectedTagsRoomIdsForGroup = { this._visibleRoomsForGroup = {
// $groupId: [$roomId1, $roomId2, ...], // $groupId: [$roomId1, $roomId2, ...],
}; };
// All rooms that should be kept in the room list when filtering // All rooms that should be kept in the room list when filtering
this._selectedTagsRoomIds = []; this._visibleRooms = [];
// When the selected tags are changed, initialise a group store if necessary // When the selected tags are changed, initialise a group store if necessary
this._filterStoreToken = FilterStore.addListener(() => { this._filterStoreToken = FilterStore.addListener(() => {
FilterStore.getSelectedTags().forEach((tag) => { FilterStore.getSelectedTags().forEach((tag) => {
@ -109,7 +109,7 @@ module.exports = React.createClass({
); );
}); });
// Filters themselves have changed, refresh the selected tags // Filters themselves have changed, refresh the selected tags
this.updateSelectedTagsRooms(dmRoomMap, FilterStore.getSelectedTags()); this.updateVisibleRooms();
}); });
this.refreshRoomList(); this.refreshRoomList();
@ -276,29 +276,30 @@ module.exports = React.createClass({
this.refreshRoomList(); this.refreshRoomList();
}, 500), }, 500),
// Update which rooms and users should appear in RoomList as dictated by selected tags // Update which rooms and users should appear in RoomList for a given group tag
updateSelectedTagsRooms: function(dmRoomMap, updatedTags) { updateVisibleRoomsForTag: function(dmRoomMap, tag) {
if (!this.mounted) return; if (!this.mounted) return;
updatedTags.forEach((tag) => { // For now, only handle group tags
// For now, only handle group tags const store = this._groupStores[tag];
const store = this._groupStores[tag]; if (!store) return;
if (!store) return;
this._selectedTagsRoomIdsForGroup[tag] = []; this._visibleRoomsForGroup[tag] = [];
store.getGroupRooms().forEach((room) => this._selectedTagsRoomIdsForGroup[tag].push(room.roomId)); store.getGroupRooms().forEach((room) => this._visibleRoomsForGroup[tag].push(room.roomId));
store.getGroupMembers().forEach((member) => { store.getGroupMembers().forEach((member) => {
if (member.userId === MatrixClientPeg.get().credentials.userId) return; if (member.userId === MatrixClientPeg.get().credentials.userId) return;
dmRoomMap.getDMRoomsForUserId(member.userId).forEach( dmRoomMap.getDMRoomsForUserId(member.userId).forEach(
(roomId) => this._selectedTagsRoomIdsForGroup[tag].push(roomId), (roomId) => this._visibleRoomsForGroup[tag].push(roomId),
); );
});
// TODO: Check if room has been tagged to the group by the user
}); });
// TODO: Check if room has been tagged to the group by the user
},
this._selectedTagsRoomIds = []; // Update which rooms and users should appear according to which tags are selected
updateVisibleRooms: function() {
this._visibleRooms = [];
FilterStore.getSelectedTags().forEach((tag) => { FilterStore.getSelectedTags().forEach((tag) => {
(this._selectedTagsRoomIdsForGroup[tag] || []).forEach( (this._visibleRoomsForGroup[tag] || []).forEach(
(roomId) => this._selectedTagsRoomIds.push(roomId), (roomId) => this._visibleRooms.push(roomId),
); );
}); });
@ -311,7 +312,7 @@ module.exports = React.createClass({
isRoomInSelectedTags: function(room) { isRoomInSelectedTags: function(room) {
// No selected tags = every room is visible in the list // No selected tags = every room is visible in the list
return this.state.selectedTags.length === 0 || this._selectedTagsRoomIds.includes(room.roomId); return this.state.selectedTags.length === 0 || this._visibleRooms.includes(room.roomId);
}, },
refreshRoomList: function() { refreshRoomList: function() {

View file

@ -23,6 +23,10 @@ import SettingsStore, {SettingLevel} from "./settings/SettingsStore";
const i18nFolder = 'i18n/'; const i18nFolder = 'i18n/';
// Control whether to also return original, untranslated strings
// Useful for debugging and testing
const ANNOTATE_STRINGS = false;
// We use english strings as keys, some of which contain full stops // We use english strings as keys, some of which contain full stops
counterpart.setSeparator('|'); counterpart.setSeparator('|');
// Fall back to English // Fall back to English
@ -84,7 +88,21 @@ export function _t(text, variables, tags) {
// The translation returns text so there's no XSS vector here (no unsafe HTML, no code execution) // The translation returns text so there's no XSS vector here (no unsafe HTML, no code execution)
const translated = safeCounterpartTranslate(text, args); const translated = safeCounterpartTranslate(text, args);
return substitute(translated, variables, tags); let substituted = substitute(translated, variables, tags);
// For development/testing purposes it is useful to also output the original string
// Don't do that for release versions
if (ANNOTATE_STRINGS) {
if (typeof substituted === 'string') {
return `@@${text}##${substituted}@@`
}
else {
return <span className='translated-string' data-orig-string={text}>{substituted}</span>;
}
}
else {
return substituted;
}
} }
/* /*