diff --git a/src/components/structures/login/Login.js b/src/components/structures/login/Login.js index 59d8c74022..8848a33deb 100644 --- a/src/components/structures/login/Login.js +++ b/src/components/structures/login/Login.js @@ -18,7 +18,7 @@ limitations under the License. 'use strict'; import React from 'react'; -import { _t } from '../../../languageHandler'; +import { _t, _tJsx } from '../../../languageHandler'; import ReactDOM from 'react-dom'; import sdk from '../../../index'; import Login from '../../../Login'; diff --git a/src/components/views/elements/LanguageDropdown.js b/src/components/views/elements/LanguageDropdown.js index 25a920d2e0..49f89aa469 100644 --- a/src/components/views/elements/LanguageDropdown.js +++ b/src/components/views/elements/LanguageDropdown.js @@ -40,14 +40,7 @@ export default class LanguageDropdown extends React.Component { } componentWillMount() { - languageHandler.getAllLanguageKeysFromJson().then((langKeys) => { - const langs = []; - langKeys.forEach((languageKey) => { - langs.push({ - value: languageKey, - label: _t(languageKey) - }); - }); + languageHandler.getAllLanguagesFromJson().then((langs) => { langs.sort(function(a, b){ if(a.label < b.label) return -1; if(a.label > b.label) return 1; diff --git a/src/components/views/elements/PowerSelector.js b/src/components/views/elements/PowerSelector.js index f12ef3ac9d..a4a117b9cb 100644 --- a/src/components/views/elements/PowerSelector.js +++ b/src/components/views/elements/PowerSelector.js @@ -118,7 +118,7 @@ module.exports = React.createClass({ }); options.push({ value: "Custom", text: "Custom level" }); options = options.map((op) => { - return ; + return ; }); select = diff --git a/src/components/views/messages/RoomAvatarEvent.js b/src/components/views/messages/RoomAvatarEvent.js new file mode 100644 index 0000000000..525f7b81ee --- /dev/null +++ b/src/components/views/messages/RoomAvatarEvent.js @@ -0,0 +1,92 @@ +/* +Copyright 2017 Vector Creations Ltd + +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 from 'react'; +import MatrixClientPeg from '../../../MatrixClientPeg'; +import { ContentRepo } from 'matrix-js-sdk'; +import { _t, _tJsx } from '../../../languageHandler'; +import sdk from '../../../index'; +import Modal from '../../../Modal'; +import AccessibleButton from '../elements/AccessibleButton'; + +module.exports = React.createClass({ + displayName: 'RoomAvatarEvent', + + propTypes: { + /* the MatrixEvent to show */ + mxEvent: React.PropTypes.object.isRequired, + }, + + onAvatarClick: function(name) { + var httpUrl = MatrixClientPeg.get().mxcUrlToHttp(this.props.mxEvent.getContent().url); + var ImageView = sdk.getComponent("elements.ImageView"); + var params = { + src: httpUrl, + name: name, + }; + Modal.createDialog(ImageView, params, "mx_Dialog_lightbox"); + }, + + render: function() { + var ev = this.props.mxEvent; + var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); + var BaseAvatar = sdk.getComponent("avatars.BaseAvatar"); + + var room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId()); + var name = _t('%(senderDisplayName)s changed the avatar for %(roomName)s', { + senderDisplayName: senderDisplayName, + roomName: room ? room.name : '', + }); + + if (!ev.getContent().url || ev.getContent().url.trim().length === 0) { + return ( +
+ { _t('%(senderDisplayName)s removed the room avatar.', {senderDisplayName: senderDisplayName}) } +
+ ); + } + + var url = ContentRepo.getHttpUriForMxc( + MatrixClientPeg.get().getHomeserverUrl(), + ev.getContent().url, + 14 * window.devicePixelRatio, + 14 * window.devicePixelRatio, + 'crop' + ); + + // it sucks that _tJsx doesn't support normal _t substitutions :(( + return ( +
+ { _tJsx('$senderDisplayName changed the room avatar to ', + [ + /\$senderDisplayName/, + //, + ], + [ + (sub) => senderDisplayName, + (sub) => + + + , + ] + ) + } +
+ ); + }, +}); diff --git a/src/components/views/messages/TextualEvent.js b/src/components/views/messages/TextualEvent.js index 8319dbd434..088f7cbbc6 100644 --- a/src/components/views/messages/TextualEvent.js +++ b/src/components/views/messages/TextualEvent.js @@ -24,6 +24,11 @@ import sdk from '../../../index'; module.exports = React.createClass({ displayName: 'TextualEvent', + propTypes: { + /* the MatrixEvent to show */ + mxEvent: React.PropTypes.object.isRequired, + }, + render: function() { const EmojiText = sdk.getComponent('elements.EmojiText'); var text = TextForEvent.textForEvent(this.props.mxEvent); diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index d9a6925793..e527f53170 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -38,6 +38,7 @@ var eventTileTypes = { 'm.call.answer' : 'messages.TextualEvent', 'm.call.hangup' : 'messages.TextualEvent', 'm.room.name' : 'messages.TextualEvent', + 'm.room.avatar' : 'messages.RoomAvatarEvent', 'm.room.topic' : 'messages.TextualEvent', 'm.room.third_party_invite' : 'messages.TextualEvent', 'm.room.history_visibility' : 'messages.TextualEvent', diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 15aa3916bc..95baf1f50e 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -776,5 +776,8 @@ "Online": "Online", "Idle": "Idle", "Offline": "Offline", - "Disable URL previews for this room (affects only you)": "Disable URL previews for this room (affects only you)" + "Disable URL previews for this room (affects only you)": "Disable URL previews for this room (affects only you)", + "$senderDisplayName changed the room avatar to ": "$senderDisplayName changed the room avatar to ", + "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removed the room avatar.", + "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s" } diff --git a/src/languageHandler.js b/src/languageHandler.js index 1c3acab082..ab29dd926e 100644 --- a/src/languageHandler.js +++ b/src/languageHandler.js @@ -133,7 +133,7 @@ export function setLanguage(preferredLangs) { throw new Error("Unable to find an appropriate language"); } - return getLanguage(i18nFolder + availLangs[langToUse]); + return getLanguage(i18nFolder + availLangs[langToUse].fileName); }).then((langData) => { counterpart.registerTranslations(langToUse, langData); counterpart.setLocale(langToUse); @@ -142,16 +142,25 @@ export function setLanguage(preferredLangs) { // Set 'en' as fallback language: if (langToUse != "en") { - return getLanguage(i18nFolder + availLangs['en']); + return getLanguage(i18nFolder + availLangs['en'].fileName); } }).then((langData) => { if (langData) counterpart.registerTranslations('en', langData); }); }; -export function getAllLanguageKeysFromJson() { - return getLangsJson().then((langs) => { - return Object.keys(langs); +export function getAllLanguagesFromJson() { + return getLangsJson().then((langsObject) => { + var langs = []; + for (var langKey in langsObject) { + if (langsObject.hasOwnProperty(langKey)) { + langs.push({ + 'value': langKey, + 'label': langsObject[langKey].label + }); + } + } + return langs; }); }