diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index 50350f983a..f66d2c69d3 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -1,10 +1,7 @@ # autogenerated file: run scripts/generate-eslint-error-ignore-file to update. -src/async-components/views/dialogs/EncryptedEventDialog.js src/autocomplete/AutocompleteProvider.js src/autocomplete/Autocompleter.js -src/autocomplete/Components.js -src/autocomplete/DuckDuckGoProvider.js src/autocomplete/EmojiProvider.js src/autocomplete/UserProvider.js src/CallHandler.js @@ -12,11 +9,9 @@ src/component-index.js src/components/structures/ContextualMenu.js src/components/structures/CreateRoom.js src/components/structures/FilePanel.js -src/components/structures/InteractiveAuth.js src/components/structures/LoggedInView.js src/components/structures/login/ForgotPassword.js src/components/structures/login/Login.js -src/components/structures/login/PostRegistration.js src/components/structures/login/Registration.js src/components/structures/MessagePanel.js src/components/structures/NotificationPanel.js @@ -27,51 +22,32 @@ src/components/structures/TimelinePanel.js src/components/structures/UploadBar.js src/components/views/avatars/BaseAvatar.js src/components/views/avatars/MemberAvatar.js -src/components/views/avatars/RoomAvatar.js -src/components/views/create_room/CreateRoomButton.js -src/components/views/create_room/Presets.js src/components/views/create_room/RoomAlias.js src/components/views/dialogs/ChatCreateOrReuseDialog.js src/components/views/dialogs/DeactivateAccountDialog.js -src/components/views/dialogs/InteractiveAuthDialog.js src/components/views/dialogs/UnknownDeviceDialog.js -src/components/views/elements/AccessibleButton.js -src/components/views/elements/ActionButton.js src/components/views/elements/AddressSelector.js -src/components/views/elements/AddressTile.js src/components/views/elements/CreateRoomButton.js src/components/views/elements/DeviceVerifyButtons.js src/components/views/elements/DirectorySearchBox.js -src/components/views/elements/Dropdown.js src/components/views/elements/EditableText.js -src/components/views/elements/EditableTextContainer.js src/components/views/elements/HomeButton.js -src/components/views/elements/LanguageDropdown.js src/components/views/elements/MemberEventListSummary.js src/components/views/elements/PowerSelector.js -src/components/views/elements/ProgressBar.js src/components/views/elements/RoomDirectoryButton.js src/components/views/elements/SettingsButton.js src/components/views/elements/StartChatButton.js src/components/views/elements/TintableSvg.js src/components/views/elements/UserSelector.js -src/components/views/login/CaptchaForm.js -src/components/views/login/CasLogin.js src/components/views/login/CountryDropdown.js -src/components/views/login/CustomServerDialog.js src/components/views/login/InteractiveAuthEntryComponents.js -src/components/views/login/LoginHeader.js src/components/views/login/PasswordLogin.js src/components/views/login/RegistrationForm.js src/components/views/login/ServerConfig.js -src/components/views/messages/MAudioBody.js -src/components/views/messages/MessageEvent.js src/components/views/messages/MFileBody.js src/components/views/messages/MImageBody.js -src/components/views/messages/MVideoBody.js src/components/views/messages/RoomAvatarEvent.js src/components/views/messages/TextualBody.js -src/components/views/messages/TextualEvent.js src/components/views/room_settings/AliasSettings.js src/components/views/room_settings/ColorSettings.js src/components/views/room_settings/UrlPreviewSettings.js @@ -86,14 +62,11 @@ src/components/views/rooms/MemberList.js src/components/views/rooms/MemberTile.js src/components/views/rooms/MessageComposer.js src/components/views/rooms/MessageComposerInput.js -src/components/views/rooms/PresenceLabel.js src/components/views/rooms/ReadReceiptMarker.js src/components/views/rooms/RoomList.js -src/components/views/rooms/RoomNameEditor.js src/components/views/rooms/RoomPreviewBar.js src/components/views/rooms/RoomSettings.js src/components/views/rooms/RoomTile.js -src/components/views/rooms/RoomTopicEditor.js src/components/views/rooms/SearchableEntityList.js src/components/views/rooms/SearchResultTile.js src/components/views/rooms/TopUnreadMessagesBar.js @@ -103,8 +76,6 @@ src/components/views/settings/ChangeAvatar.js src/components/views/settings/ChangeDisplayName.js src/components/views/settings/ChangePassword.js src/components/views/settings/DevicesPanel.js -src/components/views/settings/DevicesPanelEntry.js -src/components/views/settings/EnableNotificationsButton.js src/ContentMessages.js src/HtmlUtils.js src/ImageUtils.js @@ -122,7 +93,6 @@ src/RichText.js src/Roles.js src/Rooms.js src/ScalarAuthClient.js -src/ScalarMessaging.js src/Tinter.js src/UiEffects.js src/Unread.js @@ -135,17 +105,13 @@ src/Velociraptor.js src/VelocityBounce.js src/WhoIsTyping.js src/wrappers/withMatrixClient.js -test/all-tests.js test/components/structures/login/Registration-test.js test/components/structures/MessagePanel-test.js test/components/structures/ScrollPanel-test.js test/components/structures/TimelinePanel-test.js -test/components/stub-component.js test/components/views/dialogs/InteractiveAuthDialog-test.js test/components/views/elements/MemberEventListSummary-test.js test/components/views/login/RegistrationForm-test.js test/components/views/rooms/MessageComposerInput-test.js test/mock-clock.js -test/skinned-sdk.js test/stores/RoomViewStore-test.js -test/test-utils.js diff --git a/src/CallHandler.js b/src/CallHandler.js index 8331d579df..a9539d40e1 100644 --- a/src/CallHandler.js +++ b/src/CallHandler.js @@ -63,23 +63,22 @@ import dis from './dispatcher'; global.mxCalls = { //room_id: MatrixCall }; -var calls = global.mxCalls; -var ConferenceHandler = null; +const calls = global.mxCalls; +let ConferenceHandler = null; -var audioPromises = {}; +const audioPromises = {}; function play(audioId) { // TODO: Attach an invisible element for this instead // which listens? - var audio = document.getElementById(audioId); + const audio = document.getElementById(audioId); if (audio) { if (audioPromises[audioId]) { audioPromises[audioId] = audioPromises[audioId].then(()=>{ audio.load(); return audio.play(); }); - } - else { + } else { audioPromises[audioId] = audio.play(); } } @@ -88,12 +87,11 @@ function play(audioId) { function pause(audioId) { // TODO: Attach an invisible element for this instead // which listens? - var audio = document.getElementById(audioId); + const audio = document.getElementById(audioId); if (audio) { if (audioPromises[audioId]) { audioPromises[audioId] = audioPromises[audioId].then(()=>audio.pause()); - } - else { + } else { // pause doesn't actually return a promise, but might as well do this for symmetry with play(); audioPromises[audioId] = audio.pause(); } @@ -125,38 +123,32 @@ function _setCallListeners(call) { if (newState === "ringing") { _setCallState(call, call.roomId, "ringing"); pause("ringbackAudio"); - } - else if (newState === "invite_sent") { + } else if (newState === "invite_sent") { _setCallState(call, call.roomId, "ringback"); play("ringbackAudio"); - } - else if (newState === "ended" && oldState === "connected") { + } else if (newState === "ended" && oldState === "connected") { _setCallState(undefined, call.roomId, "ended"); pause("ringbackAudio"); play("callendAudio"); - } - else if (newState === "ended" && oldState === "invite_sent" && + } else if (newState === "ended" && oldState === "invite_sent" && (call.hangupParty === "remote" || (call.hangupParty === "local" && call.hangupReason === "invite_timeout") )) { _setCallState(call, call.roomId, "busy"); pause("ringbackAudio"); play("busyAudio"); - var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Call Handler', 'Call Timeout', ErrorDialog, { title: _t('Call Timeout'), description: _t('The remote side failed to pick up') + '.', }); - } - else if (oldState === "invite_sent") { + } else if (oldState === "invite_sent") { _setCallState(call, call.roomId, "stop_ringback"); pause("ringbackAudio"); - } - else if (oldState === "ringing") { + } else if (oldState === "ringing") { _setCallState(call, call.roomId, "stop_ringing"); pause("ringbackAudio"); - } - else if (newState === "connected") { + } else if (newState === "connected") { _setCallState(call, call.roomId, "connected"); pause("ringbackAudio"); } @@ -165,14 +157,13 @@ function _setCallListeners(call) { function _setCallState(call, roomId, status) { console.log( - "Call state in %s changed to %s (%s)", roomId, status, (call ? call.call_state : "-") + "Call state in %s changed to %s (%s)", roomId, status, (call ? call.call_state : "-"), ); calls[roomId] = call; if (status === "ringing") { play("ringAudio"); - } - else if (call && call.call_state === "ringing") { + } else if (call && call.call_state === "ringing") { pause("ringAudio"); } @@ -192,14 +183,12 @@ function _onAction(payload) { _setCallState(newCall, newCall.roomId, "ringback"); if (payload.type === 'voice') { newCall.placeVoiceCall(); - } - else if (payload.type === 'video') { + } else if (payload.type === 'video') { newCall.placeVideoCall( payload.remote_element, - payload.local_element + payload.local_element, ); - } - else if (payload.type === 'screensharing') { + } else if (payload.type === 'screensharing') { const screenCapErrorString = PlatformPeg.get().screenCaptureErrorString(); if (screenCapErrorString) { _setCallState(undefined, newCall.roomId, "ended"); @@ -213,10 +202,9 @@ function _onAction(payload) { } newCall.placeScreenSharingCall( payload.remote_element, - payload.local_element + payload.local_element, ); - } - else { + } else { console.error("Unknown conf call type: %s", payload.type); } } @@ -255,21 +243,19 @@ function _onAction(payload) { description: _t('You cannot place a call with yourself.'), }); return; - } - else if (members.length === 2) { + } else if (members.length === 2) { console.log("Place %s call in %s", payload.type, payload.room_id); const call = Matrix.createNewMatrixCall(MatrixClientPeg.get(), payload.room_id, { forceTURN: UserSettingsStore.getLocalSetting('webRtcForceTURN', false), }); placeCall(call); - } - else { // > 2 + } else { // > 2 dis.dispatch({ action: "place_conference_call", room_id: payload.room_id, type: payload.type, remote_element: payload.remote_element, - local_element: payload.local_element + local_element: payload.local_element, }); } break; @@ -280,15 +266,13 @@ function _onAction(payload) { Modal.createTrackedDialog('Call Handler', 'Conference call unsupported client', ErrorDialog, { description: _t('Conference calls are not supported in this client'), }); - } - else if (!MatrixClientPeg.get().supportsVoip()) { + } else if (!MatrixClientPeg.get().supportsVoip()) { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Call Handler', 'VoIP is unsupported', ErrorDialog, { title: _t('VoIP is unsupported'), description: _t('You cannot place VoIP calls in this browser.'), }); - } - else if (MatrixClientPeg.get().isRoomEncrypted(payload.room_id)) { + } else if (MatrixClientPeg.get().isRoomEncrypted(payload.room_id)) { // Conference calls are implemented by sending the media to central // server which combines the audio from all the participants together // into a single stream. This is incompatible with end-to-end encryption @@ -299,16 +283,15 @@ function _onAction(payload) { Modal.createTrackedDialog('Call Handler', 'Conference calls unsupported e2e', ErrorDialog, { description: _t('Conference calls are not supported in encrypted rooms'), }); - } - else { - var QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); + } else { + const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); Modal.createTrackedDialog('Call Handler', 'Conference calling in development', QuestionDialog, { title: _t('Warning!'), description: _t('Conference calling is in development and may not be reliable.'), - onFinished: confirm=>{ + onFinished: (confirm)=>{ if (confirm) { ConferenceHandler.createNewMatrixCall( - MatrixClientPeg.get(), payload.room_id + MatrixClientPeg.get(), payload.room_id, ).done(function(call) { placeCall(call); }, function(err) { @@ -357,7 +340,7 @@ function _onAction(payload) { _setCallState(calls[payload.room_id], payload.room_id, "connected"); dis.dispatch({ action: "view_room", - room_id: payload.room_id + room_id: payload.room_id, }); break; } @@ -368,9 +351,9 @@ if (!global.mxCallHandler) { dis.register(_onAction); } -var callHandler = { +const callHandler = { getCallForRoom: function(roomId) { - var call = module.exports.getCall(roomId); + let call = module.exports.getCall(roomId); if (call) return call; if (ConferenceHandler) { @@ -386,8 +369,8 @@ var callHandler = { }, getAnyActiveCall: function() { - var roomsWithCalls = Object.keys(calls); - for (var i = 0; i < roomsWithCalls.length; i++) { + const roomsWithCalls = Object.keys(calls); + for (let i = 0; i < roomsWithCalls.length; i++) { if (calls[roomsWithCalls[i]] && calls[roomsWithCalls[i]].call_state !== "ended") { return calls[roomsWithCalls[i]]; @@ -402,7 +385,7 @@ var callHandler = { getConferenceHandler: function() { return ConferenceHandler; - } + }, }; // Only things in here which actually need to be global are the // calls list (done separately) and making sure we only register diff --git a/src/ContentMessages.js b/src/ContentMessages.js index 93057fafed..00728061a2 100644 --- a/src/ContentMessages.js +++ b/src/ContentMessages.js @@ -17,14 +17,14 @@ limitations under the License. 'use strict'; import Promise from 'bluebird'; -var extend = require('./extend'); -var dis = require('./dispatcher'); -var MatrixClientPeg = require('./MatrixClientPeg'); -var sdk = require('./index'); +const extend = require('./extend'); +const dis = require('./dispatcher'); +const MatrixClientPeg = require('./MatrixClientPeg'); +const sdk = require('./index'); import { _t } from './languageHandler'; -var Modal = require('./Modal'); +const Modal = require('./Modal'); -var encrypt = require("browser-encrypt-attachment"); +const encrypt = require("browser-encrypt-attachment"); // Polyfill for Canvas.toBlob API using Canvas.toDataURL require("blueimp-canvas-to-blob"); @@ -54,8 +54,8 @@ const MAX_HEIGHT = 600; function createThumbnail(element, inputWidth, inputHeight, mimeType) { const deferred = Promise.defer(); - var targetWidth = inputWidth; - var targetHeight = inputHeight; + let targetWidth = inputWidth; + let targetHeight = inputHeight; if (targetHeight > MAX_HEIGHT) { targetWidth = Math.floor(targetWidth * (MAX_HEIGHT / targetHeight)); targetHeight = MAX_HEIGHT; @@ -81,7 +81,7 @@ function createThumbnail(element, inputWidth, inputHeight, mimeType) { w: inputWidth, h: inputHeight, }, - thumbnail: thumbnail + thumbnail: thumbnail, }); }, mimeType); @@ -129,12 +129,12 @@ function loadImageElement(imageFile) { * @return {Promise} A promise that resolves with the attachment info. */ function infoForImageFile(matrixClient, roomId, imageFile) { - var thumbnailType = "image/png"; + let thumbnailType = "image/png"; if (imageFile.type == "image/jpeg") { thumbnailType = "image/jpeg"; } - var imageInfo; + let imageInfo; return loadImageElement(imageFile).then(function(img) { return createThumbnail(img, img.width, img.height, thumbnailType); }).then(function(result) { @@ -191,7 +191,7 @@ function loadVideoElement(videoFile) { function infoForVideoFile(matrixClient, roomId, videoFile) { const thumbnailType = "image/jpeg"; - var videoInfo; + let videoInfo; return loadVideoElement(videoFile).then(function(video) { return createThumbnail(video, video.videoWidth, video.videoHeight, thumbnailType); }).then(function(result) { @@ -286,7 +286,7 @@ class ContentMessages { body: file.name || 'Attachment', info: { size: file.size, - } + }, }; // if we have a mime type for the file, add it to the message metadata @@ -297,10 +297,10 @@ class ContentMessages { const def = Promise.defer(); if (file.type.indexOf('image/') == 0) { content.msgtype = 'm.image'; - infoForImageFile(matrixClient, roomId, file).then(imageInfo=>{ + infoForImageFile(matrixClient, roomId, file).then((imageInfo)=>{ extend(content.info, imageInfo); def.resolve(); - }, error=>{ + }, (error)=>{ console.error(error); content.msgtype = 'm.file'; def.resolve(); @@ -310,10 +310,10 @@ class ContentMessages { def.resolve(); } else if (file.type.indexOf('video/') == 0) { content.msgtype = 'm.video'; - infoForVideoFile(matrixClient, roomId, file).then(videoInfo=>{ + infoForVideoFile(matrixClient, roomId, file).then((videoInfo)=>{ extend(content.info, videoInfo); def.resolve(); - }, error=>{ + }, (error)=>{ content.msgtype = 'm.file'; def.resolve(); }); @@ -331,7 +331,7 @@ class ContentMessages { this.inprogress.push(upload); dis.dispatch({action: 'upload_started'}); - var error; + let error; function onProgress(ev) { upload.total = ev.total; @@ -355,11 +355,11 @@ class ContentMessages { }, function(err) { error = err; if (!upload.canceled) { - var desc = _t('The file \'%(fileName)s\' failed to upload', {fileName: upload.fileName}) + '.'; + let desc = _t('The file \'%(fileName)s\' failed to upload', {fileName: upload.fileName}) + '.'; if (err.http_status == 413) { desc = _t('The file \'%(fileName)s\' exceeds this home server\'s size limit for uploads', {fileName: upload.fileName}); } - var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Upload failed', '', ErrorDialog, { title: _t('Upload Failed'), description: desc, @@ -367,8 +367,8 @@ class ContentMessages { } }).finally(() => { const inprogressKeys = Object.keys(this.inprogress); - for (var i = 0; i < this.inprogress.length; ++i) { - var k = inprogressKeys[i]; + for (let i = 0; i < this.inprogress.length; ++i) { + const k = inprogressKeys[i]; if (this.inprogress[k].promise === upload.promise) { this.inprogress.splice(k, 1); break; @@ -376,8 +376,7 @@ class ContentMessages { } if (error) { dis.dispatch({action: 'upload_failed', upload: upload}); - } - else { + } else { dis.dispatch({action: 'upload_finished', upload: upload}); } }); @@ -389,9 +388,9 @@ class ContentMessages { cancelUpload(promise) { const inprogressKeys = Object.keys(this.inprogress); - var upload; - for (var i = 0; i < this.inprogress.length; ++i) { - var k = inprogressKeys[i]; + let upload; + for (let i = 0; i < this.inprogress.length; ++i) { + const k = inprogressKeys[i]; if (this.inprogress[k].promise === promise) { upload = this.inprogress[k]; break; diff --git a/src/GroupAddressPicker.js b/src/GroupAddressPicker.js index 00eed78f76..ca495de16d 100644 --- a/src/GroupAddressPicker.js +++ b/src/GroupAddressPicker.js @@ -19,6 +19,7 @@ import sdk from './'; import MultiInviter from './utils/MultiInviter'; import { _t } from './languageHandler'; import MatrixClientPeg from './MatrixClientPeg'; +import GroupStoreCache from './stores/GroupStoreCache'; export function showGroupInviteDialog(groupId) { const AddressPickerDialog = sdk.getComponent("dialogs.AddressPickerDialog"); @@ -75,6 +76,13 @@ function _onGroupInviteFinished(groupId, addrs) { title: _t("Failed to invite the following users to %(groupId)s:", {groupId: groupId}), description: errorList.join(", "), }); + } else { + const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); + Modal.createTrackedDialog('Group invitations sent', '', QuestionDialog, { + title: _t("Invites sent"), + description: _t("Your group invitations have been sent."), + hasCancelButton: false, + }); } }).catch((err) => { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); @@ -86,10 +94,11 @@ function _onGroupInviteFinished(groupId, addrs) { } function _onGroupAddRoomFinished(groupId, addrs) { + const groupStore = GroupStoreCache.getGroupStore(MatrixClientPeg.get(), groupId); const errorList = []; return Promise.all(addrs.map((addr) => { - return MatrixClientPeg.get() - .addRoomToGroup(groupId, addr.address) + return groupStore + .addRoomToGroup(addr.address) .catch(() => { errorList.push(addr.address); }) .reflect(); })).then(() => { diff --git a/src/HtmlUtils.js b/src/HtmlUtils.js index ee2bcd2b0f..b8a1c63dfb 100644 --- a/src/HtmlUtils.js +++ b/src/HtmlUtils.js @@ -17,10 +17,10 @@ limitations under the License. 'use strict'; -var React = require('react'); -var sanitizeHtml = require('sanitize-html'); -var highlight = require('highlight.js'); -var linkifyMatrix = require('./linkify-matrix'); +const React = require('react'); +const sanitizeHtml = require('sanitize-html'); +const highlight = require('highlight.js'); +const linkifyMatrix = require('./linkify-matrix'); import escape from 'lodash/escape'; import emojione from 'emojione'; import classNames from 'classnames'; @@ -66,8 +66,7 @@ function unicodeToImage(str) { if ( (typeof unicodeChar === 'undefined') || (unicodeChar === '') || (!(unicodeChar in emojione.jsEscapeMap)) ) { // if the unicodeChar doesnt exist just return the entire match return unicodeChar; - } - else { + } else { // get the unicode codepoint from the actual char unicode = emojione.jsEscapeMap[unicodeChar]; @@ -183,21 +182,19 @@ const sanitizeHtmlParams = { if (attribs.href) { attribs.target = '_blank'; // by default - var m; + let m; // FIXME: horrible duplication with linkify-matrix m = attribs.href.match(linkifyMatrix.VECTOR_URL_PATTERN); if (m) { attribs.href = m[1]; delete attribs.target; - } - else { + } else { m = attribs.href.match(linkifyMatrix.MATRIXTO_URL_PATTERN); if (m) { - var entity = m[1]; + const entity = m[1]; if (entity[0] === '@') { attribs.href = '#/user/' + entity; - } - else if (entity[0] === '#' || entity[0] === '!') { + } else if (entity[0] === '#' || entity[0] === '!') { attribs.href = '#/room/' + entity; } delete attribs.target; @@ -205,7 +202,7 @@ const sanitizeHtmlParams = { } } attribs.rel = 'noopener'; // https://mathiasbynens.github.io/rel-noopener/ - return { tagName: tagName, attribs : attribs }; + return { tagName: tagName, attribs: attribs }; }, 'img': function(tagName, attribs) { // Strip out imgs that aren't `mxc` here instead of using allowedSchemesByTag @@ -224,7 +221,7 @@ const sanitizeHtmlParams = { 'code': function(tagName, attribs) { if (typeof attribs.class !== 'undefined') { // Filter out all classes other than ones starting with language- for syntax highlighting. - let classes = attribs.class.split(/\s+/).filter(function(cl) { + const classes = attribs.class.split(/\s+/).filter(function(cl) { return cl.startsWith('language-'); }); attribs.class = classes.join(' '); @@ -287,11 +284,11 @@ class BaseHighlighter { * TextHighlighter). */ applyHighlights(safeSnippet, safeHighlights) { - var lastOffset = 0; - var offset; - var nodes = []; + let lastOffset = 0; + let offset; + let nodes = []; - var safeHighlight = safeHighlights[0]; + const safeHighlight = safeHighlights[0]; while ((offset = safeSnippet.toLowerCase().indexOf(safeHighlight.toLowerCase(), lastOffset)) >= 0) { // handle preamble if (offset > lastOffset) { @@ -301,7 +298,7 @@ class BaseHighlighter { // do highlight. use the original string rather than safeHighlight // to preserve the original casing. - var endOffset = offset + safeHighlight.length; + const endOffset = offset + safeHighlight.length; nodes.push(this._processSnippet(safeSnippet.substring(offset, endOffset), true)); lastOffset = endOffset; @@ -319,8 +316,7 @@ class BaseHighlighter { if (safeHighlights[1]) { // recurse into this range to check for the next set of highlight matches return this.applyHighlights(safeSnippet, safeHighlights.slice(1)); - } - else { + } else { // no more highlights to be found, just return the unhighlighted string return [this._processSnippet(safeSnippet, false)]; } @@ -341,7 +337,7 @@ class HtmlHighlighter extends BaseHighlighter { return snippet; } - var span = "" + let span = "" + snippet + ""; if (this.highlightLink) { @@ -366,15 +362,15 @@ class TextHighlighter extends BaseHighlighter { * returns a React node */ _processSnippet(snippet, highlight) { - var key = this._key++; + const key = this._key++; - var node = - + let node = + { snippet } ; if (highlight && this.highlightLink) { - node = {node}; + node = { node }; } return node; @@ -389,24 +385,23 @@ class TextHighlighter extends BaseHighlighter { * highlights: optional list of words to highlight, ordered by longest word first * * opts.highlightLink: optional href to add to highlighted words + * opts.disableBigEmoji: optional argument to disable the big emoji class. */ -export function bodyToHtml(content, highlights, opts) { - opts = opts || {}; - - var isHtml = (content.format === "org.matrix.custom.html"); - let body = isHtml ? content.formatted_body : escape(content.body); +export function bodyToHtml(content, highlights, opts={}) { + const isHtml = (content.format === "org.matrix.custom.html"); + const body = isHtml ? content.formatted_body : escape(content.body); let bodyHasEmoji = false; - var safeBody; + let safeBody; // XXX: We sanitize the HTML whilst also highlighting its text nodes, to avoid accidentally trying // to highlight HTML tags themselves. However, this does mean that we don't highlight textnodes which // are interrupted by HTML tags (not that we did before) - e.g. foobar won't get highlighted // by an attempt to search for 'foobar'. Then again, the search query probably wouldn't work either try { if (highlights && highlights.length > 0) { - var highlighter = new HtmlHighlighter("mx_EventTile_searchHighlight", opts.highlightLink); - var safeHighlights = highlights.map(function(highlight) { + const highlighter = new HtmlHighlighter("mx_EventTile_searchHighlight", opts.highlightLink); + const safeHighlights = highlights.map(function(highlight) { return sanitizeHtml(highlight, sanitizeHtmlParams); }); // XXX: hacky bodge to temporarily apply a textFilter to the sanitizeHtmlParams structure. @@ -417,16 +412,15 @@ export function bodyToHtml(content, highlights, opts) { safeBody = sanitizeHtml(body, sanitizeHtmlParams); bodyHasEmoji = containsEmoji(body); if (bodyHasEmoji) safeBody = unicodeToImage(safeBody); - } - finally { + } finally { delete sanitizeHtmlParams.textFilter; } let emojiBody = false; - if (bodyHasEmoji) { + if (!opts.disableBigEmoji && bodyHasEmoji) { EMOJI_REGEX.lastIndex = 0; - let contentBodyTrimmed = content.body !== undefined ? content.body.trim() : ''; - let match = EMOJI_REGEX.exec(contentBodyTrimmed); + const contentBodyTrimmed = content.body !== undefined ? content.body.trim() : ''; + const match = EMOJI_REGEX.exec(contentBodyTrimmed); emojiBody = match && match[0] && match[0].length === contentBodyTrimmed.length; } diff --git a/src/ImageUtils.js b/src/ImageUtils.js index 3744241874..a83d94a633 100644 --- a/src/ImageUtils.js +++ b/src/ImageUtils.js @@ -42,13 +42,12 @@ module.exports = { // no scaling needs to be applied return fullHeight; } - var widthMulti = thumbWidth / fullWidth; - var heightMulti = thumbHeight / fullHeight; + const widthMulti = thumbWidth / fullWidth; + const heightMulti = thumbHeight / fullHeight; if (widthMulti < heightMulti) { // width is the dominant dimension so scaling will be fixed on that return Math.floor(widthMulti * fullHeight); - } - else { + } else { // height is the dominant dimension so scaling will be fixed on that return Math.floor(heightMulti * fullHeight); } diff --git a/src/Login.js b/src/Login.js index 049b79c2f4..0eff94ce60 100644 --- a/src/Login.js +++ b/src/Login.js @@ -59,8 +59,8 @@ export default class Login { } getFlows() { - var self = this; - var client = this._createTemporaryClient(); + const self = this; + const client = this._createTemporaryClient(); return client.loginFlows().then(function(result) { self._flows = result.flows; self._currentFlowIndex = 0; @@ -77,12 +77,12 @@ export default class Login { getCurrentFlowStep() { // technically the flow can have multiple steps, but no one does this // for login so we can ignore it. - var flowStep = this._flows[this._currentFlowIndex]; + const flowStep = this._flows[this._currentFlowIndex]; return flowStep ? flowStep.type : null; } loginAsGuest() { - var client = this._createTemporaryClient(); + const client = this._createTemporaryClient(); return client.registerGuest({ body: { initial_device_display_name: this._defaultDeviceDisplayName, @@ -94,7 +94,7 @@ export default class Login { accessToken: creds.access_token, homeserverUrl: this._hsUrl, identityServerUrl: this._isUrl, - guest: true + guest: true, }; }, (error) => { throw error; @@ -149,12 +149,12 @@ export default class Login { identityServerUrl: self._isUrl, userId: data.user_id, deviceId: data.device_id, - accessToken: data.access_token + accessToken: data.access_token, }); }, function(error) { if (error.httpStatus === 403) { if (self._fallbackHsUrl) { - var fbClient = Matrix.createClient({ + const fbClient = Matrix.createClient({ baseUrl: self._fallbackHsUrl, idBaseUrl: this._isUrl, }); @@ -165,7 +165,7 @@ export default class Login { identityServerUrl: self._isUrl, userId: data.user_id, deviceId: data.device_id, - accessToken: data.access_token + accessToken: data.access_token, }); }, function(fallback_error) { // throw the original error diff --git a/src/Markdown.js b/src/Markdown.js index 455d5e95bd..e05f163ba5 100644 --- a/src/Markdown.js +++ b/src/Markdown.js @@ -48,7 +48,7 @@ function html_if_tag_allowed(node) { * or false if it is only a single line. */ function is_multi_line(node) { - var par = node; + let par = node; while (par.parent) { par = par.parent; } @@ -143,7 +143,7 @@ export default class Markdown { if (isMultiLine) this.cr(); html_if_tag_allowed.call(this, node); if (isMultiLine) this.cr(); - } + }; return renderer.render(this.parsed); } @@ -178,7 +178,7 @@ export default class Markdown { renderer.html_block = function(node) { this.lit(node.literal); if (is_multi_line(node) && node.next) this.lit('\n\n'); - } + }; return renderer.render(this.parsed); } diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index 4264828c7b..0c3d5b3775 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -95,7 +95,7 @@ class MatrixClientPeg { opts.pendingEventOrdering = "detached"; try { - let promise = this.matrixClient.store.startup(); + const promise = this.matrixClient.store.startup(); console.log(`MatrixClientPeg: waiting for MatrixClient store to initialise`); await promise; } catch(err) { @@ -136,7 +136,7 @@ class MatrixClientPeg { } _createClient(creds: MatrixClientCreds) { - var opts = { + const opts = { baseUrl: creds.homeserverUrl, idBaseUrl: creds.identityServerUrl, accessToken: creds.accessToken, @@ -153,8 +153,8 @@ class MatrixClientPeg { this.matrixClient.setGuest(Boolean(creds.guest)); - var notifTimelineSet = new EventTimelineSet(null, { - timelineSupport: true + const notifTimelineSet = new EventTimelineSet(null, { + timelineSupport: true, }); // XXX: what is our initial pagination token?! it somehow needs to be synchronised with /sync. notifTimelineSet.getLiveTimeline().setPaginationToken("", EventTimeline.BACKWARDS); diff --git a/src/Modal.js b/src/Modal.js index 056b6d8bf2..68d75d1ff1 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -17,8 +17,8 @@ limitations under the License. 'use strict'; -var React = require('react'); -var ReactDOM = require('react-dom'); +const React = require('react'); +const ReactDOM = require('react-dom'); import Analytics from './Analytics'; import sdk from './index'; @@ -137,15 +137,15 @@ class ModalManager { * @param {String} className CSS class to apply to the modal wrapper */ createDialogAsync(loader, props, className) { - var self = this; + const self = this; const modal = {}; // never call this from onFinished() otherwise it will loop // // nb explicit function() rather than arrow function, to get `arguments` - var closeDialog = function() { + const closeDialog = function() { if (props && props.onFinished) props.onFinished.apply(null, arguments); - var i = self._modals.indexOf(modal); + const i = self._modals.indexOf(modal); if (i >= 0) { self._modals.splice(i, 1); } @@ -160,7 +160,7 @@ class ModalManager { // property set here so you can't close the dialog from a button click! modal.elem = ( + onFinished={closeDialog} /> ); modal.onFinished = props ? props.onFinished : null; modal.className = className; @@ -191,13 +191,13 @@ class ModalManager { return; } - var modal = this._modals[0]; - var dialog = ( -
+ const modal = this._modals[0]; + const dialog = ( +
- {modal.elem} + { modal.elem }
-
+
); diff --git a/src/Notifier.js b/src/Notifier.js index 155564dcdf..a2e80353e1 100644 --- a/src/Notifier.js +++ b/src/Notifier.js @@ -81,7 +81,7 @@ const Notifier = { } const avatarUrl = ev.sender ? Avatar.avatarUrlForMember( - ev.sender, 40, 40, 'crop' + ev.sender, 40, 40, 'crop', ) : null; const notif = plaf.displayNotification(title, msg, avatarUrl, room); @@ -303,7 +303,7 @@ const Notifier = { this._playAudioNotification(ev, room); } } - } + }, }; if (!global.mxNotifier) { diff --git a/src/Presence.js b/src/Presence.js index c45d571217..fab518e1cb 100644 --- a/src/Presence.js +++ b/src/Presence.js @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -var MatrixClientPeg = require("./MatrixClientPeg"); -var dis = require("./dispatcher"); +const MatrixClientPeg = require("./MatrixClientPeg"); +const dis = require("./dispatcher"); // Time in ms after that a user is considered as unavailable/away -var UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins -var PRESENCE_STATES = ["online", "offline", "unavailable"]; +const UNAVAILABLE_TIME_MS = 3 * 60 * 1000; // 3 mins +const PRESENCE_STATES = ["online", "offline", "unavailable"]; class Presence { @@ -71,14 +71,14 @@ class Presence { if (!this.running) { return; } - var old_state = this.state; + const old_state = this.state; this.state = newState; if (MatrixClientPeg.get().isGuest()) { return; // don't try to set presence when a guest; it won't work. } - var self = this; + const self = this; MatrixClientPeg.get().setPresence(this.state).done(function() { console.log("Presence: %s", newState); }, function(err) { @@ -104,7 +104,7 @@ class Presence { * @private */ _resetTimer() { - var self = this; + const self = this; this.setState("online"); // Re-arm the timer clearTimeout(this.timer); diff --git a/src/RichText.js b/src/RichText.js index cbd3b9ae18..b61ba0b9a4 100644 --- a/src/RichText.js +++ b/src/RichText.js @@ -44,9 +44,9 @@ export const contentStateToHTML = (contentState: ContentState) => { return stateToHTML(contentState, { inlineStyles: { UNDERLINE: { - element: 'u' - } - } + element: 'u', + }, + }, }); }; @@ -59,7 +59,7 @@ function unicodeToEmojiUri(str) { let replaceWith, unicode, alt; if ((!emojione.unicodeAlt) || (emojione.sprites)) { // if we are using the shortname as the alt tag then we need a reversed array to map unicode code point to shortnames - let mappedUnicode = emojione.mapUnicodeToShort(); + const mappedUnicode = emojione.mapUnicodeToShort(); } str = str.replace(emojione.regUnicode, function(unicodeChar) { @@ -67,8 +67,14 @@ function unicodeToEmojiUri(str) { // if the unicodeChar doesnt exist just return the entire match return unicodeChar; } else { + // Remove variant selector VS16 (explicitly emoji) as it is unnecessary and leads to an incorrect URL below + if(unicodeChar.length == 2 && unicodeChar[1] == '\ufe0f') { + unicodeChar = unicodeChar[0]; + } + // get the unicode codepoint from the actual char unicode = emojione.jsEscapeMap[unicodeChar]; + return emojione.imagePathSVG+unicode+'.svg'+emojione.cacheBustParam; } }); @@ -90,14 +96,14 @@ function findWithRegex(regex, contentBlock: ContentBlock, callback: (start: numb } // Workaround for https://github.com/facebook/draft-js/issues/414 -let emojiDecorator = { +const emojiDecorator = { strategy: (contentState, contentBlock, callback) => { findWithRegex(EMOJI_REGEX, contentBlock, callback); }, component: (props) => { - let uri = unicodeToEmojiUri(props.children[0].props.text); - let shortname = emojione.toShort(props.children[0].props.text); - let style = { + const uri = unicodeToEmojiUri(props.children[0].props.text); + const shortname = emojione.toShort(props.children[0].props.text); + const style = { display: 'inline-block', width: '1em', maxHeight: '1em', @@ -106,7 +112,7 @@ let emojiDecorator = { backgroundPosition: 'center center', overflow: 'hidden', }; - return ({props.children}); + return ({ props.children }); }, }; @@ -118,16 +124,16 @@ export function getScopedRTDecorators(scope: any): CompositeDecorator { } export function getScopedMDDecorators(scope: any): CompositeDecorator { - let markdownDecorators = ['HR', 'BOLD', 'ITALIC', 'CODE', 'STRIKETHROUGH'].map( + const markdownDecorators = ['HR', 'BOLD', 'ITALIC', 'CODE', 'STRIKETHROUGH'].map( (style) => ({ strategy: (contentState, contentBlock, callback) => { return findWithRegex(MARKDOWN_REGEX[style], contentBlock, callback); }, component: (props) => ( - {props.children} + { props.children } - ) + ), })); markdownDecorators.push({ @@ -136,9 +142,9 @@ export function getScopedMDDecorators(scope: any): CompositeDecorator { }, component: (props) => ( - {props.children} + { props.children } - ) + ), }); // markdownDecorators.push(emojiDecorator); // TODO Consider renabling "syntax highlighting" when we can do it properly @@ -161,7 +167,7 @@ export function modifyText(contentState: ContentState, rangeToReplace: Selection for (let currentKey = startKey; currentKey && currentKey !== endKey; currentKey = contentState.getKeyAfter(currentKey)) { - let blockText = getText(currentKey); + const blockText = getText(currentKey); text += blockText.substring(startOffset, blockText.length); // from now on, we'll take whole blocks @@ -182,7 +188,7 @@ export function modifyText(contentState: ContentState, rangeToReplace: Selection export function selectionStateToTextOffsets(selectionState: SelectionState, contentBlocks: Array): {start: number, end: number} { let offset = 0, start = 0, end = 0; - for (let block of contentBlocks) { + for (const block of contentBlocks) { if (selectionState.getStartKey() === block.getKey()) { start = offset + selectionState.getStartOffset(); } @@ -259,7 +265,7 @@ export function attachImmutableEntitiesToEmoji(editorState: EditorState): Editor .set('focusOffset', end); const emojiText = plainText.substring(start, end); newContentState = newContentState.createEntity( - 'emoji', 'IMMUTABLE', { emojiUnicode: emojiText } + 'emoji', 'IMMUTABLE', { emojiUnicode: emojiText }, ); const entityKey = newContentState.getLastCreatedEntityKey(); newContentState = Modifier.replaceText( diff --git a/src/Rooms.js b/src/Rooms.js index 2e3f4457f0..6cc2d867a6 100644 --- a/src/Rooms.js +++ b/src/Rooms.js @@ -62,8 +62,7 @@ export function isConfCallRoom(room, me, conferenceHandler) { export function looksLikeDirectMessageRoom(room, me) { if (me.membership == "join" || me.membership === "ban" || - (me.membership === "leave" && me.events.member.getSender() !== me.events.member.getStateKey())) - { + (me.membership === "leave" && me.events.member.getSender() !== me.events.member.getStateKey())) { // Used to split rooms via tags const tagNames = Object.keys(room.tags); // Used for 1:1 direct chats diff --git a/src/ScalarAuthClient.js b/src/ScalarAuthClient.js index 0b753cf3ab..c9d056f88e 100644 --- a/src/ScalarAuthClient.js +++ b/src/ScalarAuthClient.js @@ -15,10 +15,10 @@ limitations under the License. */ import Promise from 'bluebird'; -var request = require('browser-request'); +const request = require('browser-request'); -var SdkConfig = require('./SdkConfig'); -var MatrixClientPeg = require('./MatrixClientPeg'); +const SdkConfig = require('./SdkConfig'); +const MatrixClientPeg = require('./MatrixClientPeg'); class ScalarAuthClient { @@ -38,7 +38,7 @@ class ScalarAuthClient { // Returns a scalar_token string getScalarToken() { - var tok = window.localStorage.getItem("mx_scalar_token"); + const tok = window.localStorage.getItem("mx_scalar_token"); if (tok) return Promise.resolve(tok); // No saved token, so do the dance to get one. First, we @@ -53,9 +53,9 @@ class ScalarAuthClient { } exchangeForScalarToken(openid_token_object) { - var defer = Promise.defer(); + const defer = Promise.defer(); - var scalar_rest_url = SdkConfig.get().integrations_rest_url; + const scalar_rest_url = SdkConfig.get().integrations_rest_url; request({ method: 'POST', uri: scalar_rest_url+'/register', @@ -77,7 +77,7 @@ class ScalarAuthClient { } getScalarInterfaceUrlForRoom(roomId, screen, id) { - var url = SdkConfig.get().integrations_ui_url; + let url = SdkConfig.get().integrations_ui_url; url += "?scalar_token=" + encodeURIComponent(this.scalarToken); url += "&room_id=" + encodeURIComponent(roomId); if (id) { diff --git a/src/ScalarMessaging.js b/src/ScalarMessaging.js index d14d439d66..7698829647 100644 --- a/src/ScalarMessaging.js +++ b/src/ScalarMessaging.js @@ -356,12 +356,12 @@ function getWidgets(event, roomId) { } const stateEvents = room.currentState.getStateEvents("im.vector.modular.widgets"); // Only return widgets which have required fields - let widgetStateEvents = []; + const widgetStateEvents = []; stateEvents.forEach((ev) => { if (ev.getContent().type && ev.getContent().url) { widgetStateEvents.push(ev.event); // return the raw event } - }) + }); sendResponse(event, widgetStateEvents); } @@ -376,7 +376,7 @@ function setPlumbingState(event, roomId, status) { sendError(event, _t('You need to be logged in.')); return; } - client.sendStateEvent(roomId, "m.room.plumbing", { status : status }).done(() => { + client.sendStateEvent(roomId, "m.room.plumbing", { status: status }).done(() => { sendResponse(event, { success: true, }); @@ -415,11 +415,11 @@ function setBotPower(event, roomId, userId, level) { } client.getStateEvent(roomId, "m.room.power_levels", "").then((powerLevels) => { - let powerEvent = new MatrixEvent( + const powerEvent = new MatrixEvent( { type: "m.room.power_levels", content: powerLevels, - } + }, ); client.setPowerLevel(roomId, userId, level, powerEvent).done(() => { @@ -485,8 +485,7 @@ function canSendEvent(event, roomId) { let canSend = false; if (isState) { canSend = room.currentState.maySendStateEvent(evType, me); - } - else { + } else { canSend = room.currentState.maySendEvent(evType, me); } @@ -517,8 +516,8 @@ function returnStateEvent(event, roomId, eventType, stateKey) { sendResponse(event, stateEvent.getContent()); } -var currentRoomId = null; -var currentRoomAlias = null; +let currentRoomId = null; +let currentRoomAlias = null; // Listen for when a room is viewed dis.register(onAction); @@ -542,7 +541,7 @@ const onMessage = function(event) { // // All strings start with the empty string, so for sanity return if the length // of the event origin is 0. - let 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) { return; // don't log this - debugging APIs like to spam postMessage which floods the log otherwise } @@ -647,7 +646,7 @@ module.exports = { // Make an error so we get a stack trace const e = new Error( "ScalarMessaging: mismatched startListening / stopListening detected." + - " Negative count" + " Negative count", ); console.error(e); } diff --git a/src/TextForEvent.js b/src/TextForEvent.js index 06b847c19a..51e3eb8dc9 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -243,7 +243,7 @@ function textForPowerEvent(event) { if (to !== from) { diff.push( _t('%(userId)s from %(fromPowerLevel)s to %(toPowerLevel)s', { - userId: userId, + userId, fromPowerLevel: Roles.textualPowerLevel(from, userDefault), toPowerLevel: Roles.textualPowerLevel(to, userDefault), }), @@ -254,7 +254,7 @@ function textForPowerEvent(event) { return ''; } return _t('%(senderName)s changed the power level of %(powerLevelDiffText)s.', { - senderName: senderName, + senderName, powerLevelDiffText: diff.join(", "), }); } @@ -296,12 +296,15 @@ function textForWidgetEvent(event) { const handlers = { 'm.room.message': textForMessageEvent, - 'm.room.name': textForRoomNameEvent, - 'm.room.topic': textForTopicEvent, - 'm.room.member': textForMemberEvent, 'm.call.invite': textForCallInviteEvent, 'm.call.answer': textForCallAnswerEvent, 'm.call.hangup': textForCallHangupEvent, +}; + +const stateHandlers = { + 'm.room.name': textForRoomNameEvent, + 'm.room.topic': textForTopicEvent, + 'm.room.member': textForMemberEvent, 'm.room.third_party_invite': textForThreePidInviteEvent, 'm.room.history_visibility': textForHistoryVisibilityEvent, 'm.room.encryption': textForEncryptionEvent, @@ -313,8 +316,8 @@ const handlers = { module.exports = { textForEvent: function(ev) { - const hdlr = handlers[ev.getType()]; - if (!hdlr) return ''; - return hdlr(ev); + const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()]; + if (handler) return handler(ev); + return ''; }, }; diff --git a/src/Tinter.js b/src/Tinter.js index 5bf13e6d4a..6b23df8c9b 100644 --- a/src/Tinter.js +++ b/src/Tinter.js @@ -18,10 +18,10 @@ limitations under the License. // module.exports otherwise this will break when included by both // react-sdk and apps layered on top. -var DEBUG = 0; +const DEBUG = 0; // The colour keys to be replaced as referred to in CSS -var keyRgb = [ +const keyRgb = [ "rgb(118, 207, 166)", // Vector Green "rgb(234, 245, 240)", // Vector Light Green "rgb(211, 239, 225)", // BottomLeftMenu overlay (20% Vector Green) @@ -35,7 +35,7 @@ var keyRgb = [ // x = (255 - 234) / (255 - 118) = 0.16 // The colour keys to be replaced as referred to in SVGs -var keyHex = [ +const keyHex = [ "#76CFA6", // Vector Green "#EAF5F0", // Vector Light Green "#D3EFE1", // BottomLeftMenu overlay (20% Vector Green overlaid on Vector Light Green) @@ -44,14 +44,14 @@ var keyHex = [ // cache of our replacement colours // defaults to our keys. -var colors = [ +const colors = [ keyHex[0], keyHex[1], keyHex[2], keyHex[3], ]; -var cssFixups = [ +const cssFixups = [ // { // style: a style object that should be fixed up taken from a stylesheet // attr: name of the attribute to be clobbered, e.g. 'color' @@ -60,7 +60,7 @@ var cssFixups = [ ]; // CSS attributes to be fixed up -var cssAttrs = [ +const cssAttrs = [ "color", "backgroundColor", "borderColor", @@ -69,17 +69,17 @@ var cssAttrs = [ "borderLeftColor", ]; -var svgAttrs = [ +const svgAttrs = [ "fill", "stroke", ]; -var cached = false; +let cached = false; function calcCssFixups() { if (DEBUG) console.log("calcSvgFixups start"); - for (var i = 0; i < document.styleSheets.length; i++) { - var ss = document.styleSheets[i]; + for (let i = 0; i < document.styleSheets.length; i++) { + const ss = document.styleSheets[i]; if (!ss) continue; // well done safari >:( // Chromium apparently sometimes returns null here; unsure why. // see $14534907369972FRXBx:matrix.org in HQ @@ -104,12 +104,12 @@ function calcCssFixups() { if (ss.href && !ss.href.match(/\/bundle.*\.css$/)) continue; if (!ss.cssRules) continue; - for (var j = 0; j < ss.cssRules.length; j++) { - var rule = ss.cssRules[j]; + for (let j = 0; j < ss.cssRules.length; j++) { + const rule = ss.cssRules[j]; if (!rule.style) continue; - for (var k = 0; k < cssAttrs.length; k++) { - var attr = cssAttrs[k]; - for (var l = 0; l < keyRgb.length; l++) { + for (let k = 0; k < cssAttrs.length; k++) { + const attr = cssAttrs[k]; + for (let l = 0; l < keyRgb.length; l++) { if (rule.style[attr] === keyRgb[l]) { cssFixups.push({ style: rule.style, @@ -126,8 +126,8 @@ function calcCssFixups() { function applyCssFixups() { if (DEBUG) console.log("applyCssFixups start"); - for (var i = 0; i < cssFixups.length; i++) { - var cssFixup = cssFixups[i]; + for (let i = 0; i < cssFixups.length; i++) { + const cssFixup = cssFixups[i]; cssFixup.style[cssFixup.attr] = colors[cssFixup.index]; } if (DEBUG) console.log("applyCssFixups end"); @@ -140,15 +140,15 @@ function hexToRgb(color) { color[1] + color[1] + color[2] + color[2]; } - var val = parseInt(color, 16); - var r = (val >> 16) & 255; - var g = (val >> 8) & 255; - var b = val & 255; + const val = parseInt(color, 16); + const r = (val >> 16) & 255; + const g = (val >> 8) & 255; + const b = val & 255; return [r, g, b]; } function rgbToHex(rgb) { - var val = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2]; + const val = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2]; return '#' + (0x1000000 + val).toString(16).slice(1); } @@ -167,12 +167,11 @@ module.exports = { * * @param {Function} tintable Function to call when the tint changes. */ - registerTintable : function(tintable) { + registerTintable: function(tintable) { tintables.push(tintable); }, tint: function(primaryColor, secondaryColor, tertiaryColor) { - if (!cached) { calcCssFixups(); cached = true; @@ -185,7 +184,7 @@ module.exports = { if (!secondaryColor) { const x = 0.16; // average weighting factor calculated from vector green & light green - var rgb = hexToRgb(primaryColor); + const rgb = hexToRgb(primaryColor); rgb[0] = x * rgb[0] + (1 - x) * 255; rgb[1] = x * rgb[1] + (1 - x) * 255; rgb[2] = x * rgb[2] + (1 - x) * 255; @@ -194,8 +193,8 @@ module.exports = { if (!tertiaryColor) { const x = 0.19; - var rgb1 = hexToRgb(primaryColor); - var rgb2 = hexToRgb(secondaryColor); + const rgb1 = hexToRgb(primaryColor); + const rgb2 = hexToRgb(secondaryColor); rgb1[0] = x * rgb1[0] + (1 - x) * rgb2[0]; rgb1[1] = x * rgb1[1] + (1 - x) * rgb2[1]; rgb1[2] = x * rgb1[2] + (1 - x) * rgb2[2]; @@ -204,8 +203,7 @@ module.exports = { if (colors[0] === primaryColor && colors[1] === secondaryColor && - colors[2] === tertiaryColor) - { + colors[2] === tertiaryColor) { return; } @@ -248,14 +246,13 @@ module.exports = { // key colour; cache the element and apply. if (DEBUG) console.log("calcSvgFixups start for " + svgs); - var fixups = []; - for (var i = 0; i < svgs.length; i++) { + const fixups = []; + for (let i = 0; i < svgs.length; i++) { var svgDoc; try { svgDoc = svgs[i].contentDocument; - } - catch(e) { - var msg = 'Failed to get svg.contentDocument of ' + svgs[i].toString(); + } catch(e) { + let msg = 'Failed to get svg.contentDocument of ' + svgs[i].toString(); if (e.message) { msg += e.message; } @@ -265,12 +262,12 @@ module.exports = { console.error(e); } if (!svgDoc) continue; - var tags = svgDoc.getElementsByTagName("*"); - for (var j = 0; j < tags.length; j++) { - var tag = tags[j]; - for (var k = 0; k < svgAttrs.length; k++) { - var attr = svgAttrs[k]; - for (var l = 0; l < keyHex.length; l++) { + const tags = svgDoc.getElementsByTagName("*"); + for (let j = 0; j < tags.length; j++) { + const tag = tags[j]; + for (let k = 0; k < svgAttrs.length; k++) { + const attr = svgAttrs[k]; + for (let l = 0; l < keyHex.length; l++) { if (tag.getAttribute(attr) && tag.getAttribute(attr).toUpperCase() === keyHex[l]) { fixups.push({ node: tag, @@ -289,10 +286,10 @@ module.exports = { applySvgFixups: function(fixups) { if (DEBUG) console.log("applySvgFixups start for " + fixups); - for (var i = 0; i < fixups.length; i++) { - var svgFixup = fixups[i]; + for (let i = 0; i < fixups.length; i++) { + const svgFixup = fixups[i]; svgFixup.node.setAttribute(svgFixup.attr, colors[svgFixup.index]); } if (DEBUG) console.log("applySvgFixups end"); - } + }, }; diff --git a/src/Unread.js b/src/Unread.js index 8fffc2a429..20e876ad88 100644 --- a/src/Unread.js +++ b/src/Unread.js @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -var MatrixClientPeg = require('./MatrixClientPeg'); +const MatrixClientPeg = require('./MatrixClientPeg'); import UserSettingsStore from './UserSettingsStore'; import shouldHideEvent from './shouldHideEvent'; -var sdk = require('./index'); +const sdk = require('./index'); module.exports = { /** @@ -34,17 +34,17 @@ module.exports = { } else if (ev.getType == 'm.room.message' && ev.getContent().msgtype == 'm.notify') { return false; } - var EventTile = sdk.getComponent('rooms.EventTile'); + const EventTile = sdk.getComponent('rooms.EventTile'); return EventTile.haveTileForEvent(ev); }, doesRoomHaveUnreadMessages: function(room) { - var myUserId = MatrixClientPeg.get().credentials.userId; + const myUserId = MatrixClientPeg.get().credentials.userId; // get the most recent read receipt sent by our account. // N.B. this is NOT a read marker (RM, aka "read up to marker"), // despite the name of the method :(( - var readUpToId = room.getEventReadUpTo(myUserId); + const readUpToId = room.getEventReadUpTo(myUserId); // as we don't send RRs for our own messages, make sure we special case that // if *we* sent the last message into the room, we consider it not unread! @@ -54,8 +54,7 @@ module.exports = { // https://github.com/vector-im/riot-web/issues/3363 if (room.timeline.length && room.timeline[room.timeline.length - 1].sender && - room.timeline[room.timeline.length - 1].sender.userId === myUserId) - { + room.timeline[room.timeline.length - 1].sender.userId === myUserId) { return false; } @@ -67,8 +66,8 @@ module.exports = { const syncedSettings = UserSettingsStore.getSyncedSettings(); // Loop through messages, starting with the most recent... - for (var i = room.timeline.length - 1; i >= 0; --i) { - var ev = room.timeline[i]; + for (let i = room.timeline.length - 1; i >= 0; --i) { + const ev = room.timeline[i]; if (ev.getId() == readUpToId) { // If we've read up to this event, there's nothing more recents @@ -86,5 +85,5 @@ module.exports = { // is unread on the theory that false positives are better than // false negatives here. return true; - } + }, }; diff --git a/src/UserSettingsStore.js b/src/UserSettingsStore.js index 9b7554bda2..6f689735a7 100644 --- a/src/UserSettingsStore.js +++ b/src/UserSettingsStore.js @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2017 New Vector Ltd Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,33 +18,51 @@ limitations under the License. import Promise from 'bluebird'; import MatrixClientPeg from './MatrixClientPeg'; import Notifier from './Notifier'; -import { _t } from './languageHandler'; +import { _t, _td } from './languageHandler'; +import SdkConfig from './SdkConfig'; /* * TODO: Make things use this. This is all WIP - see UserSettings.js for usage. */ +const FEATURES = [ + { + id: 'feature_groups', + name: _td("Groups"), + }, +]; + export default { - LABS_FEATURES: [ - { - name: "-", - id: 'matrix_apps', - default: true, + getLabsFeatures() { + const featuresConfig = SdkConfig.get()['features'] || {}; - // XXX: Always use default, ignore localStorage and remove from labs - override: true, - }, - { - name: "-", - id: 'feature_groups', - default: false, - }, - ], + // The old flag: honourned for backwards compat + const enableLabs = SdkConfig.get()['enableLabs']; - // horrible but it works. The locality makes this somewhat more palatable. - doTranslations: function() { - this.LABS_FEATURES[0].name = _t("Matrix Apps"); - this.LABS_FEATURES[1].name = _t("Groups"); + let labsFeatures; + if (enableLabs) { + labsFeatures = FEATURES; + } else { + labsFeatures = FEATURES.filter((f) => { + const sdkConfigValue = featuresConfig[f.id]; + if (sdkConfigValue === 'labs') { + return true; + } + }); + } + return labsFeatures.map((f) => { + return f.id; + }); + }, + + translatedNameForFeature(featureId) { + const feature = FEATURES.filter((f) => { + return f.id === featureId; + })[0]; + + if (feature === undefined) return null; + + return _t(feature.name); }, loadProfileInfo: function() { @@ -180,33 +199,33 @@ export default { localStorage.setItem('mx_local_settings', JSON.stringify(settings)); }, - getFeatureById(feature: string) { - for (let i = 0; i < this.LABS_FEATURES.length; i++) { - const f = this.LABS_FEATURES[i]; - if (f.id === feature) { - return f; - } - } - return null; - }, - isFeatureEnabled: function(featureId: string): boolean { - // Disable labs for guests. - if (MatrixClientPeg.get().isGuest()) return false; + const featuresConfig = SdkConfig.get()['features']; - const feature = this.getFeatureById(featureId); - if (!feature) { - console.warn(`Unknown feature "${featureId}"`); + // The old flag: honourned for backwards compat + const enableLabs = SdkConfig.get()['enableLabs']; + + let sdkConfigValue = enableLabs ? 'labs' : 'disable'; + if (featuresConfig && featuresConfig[featureId] !== undefined) { + sdkConfigValue = featuresConfig[featureId]; + } + + if (sdkConfigValue === 'enable') { + return true; + } else if (sdkConfigValue === 'disable') { + return false; + } else if (sdkConfigValue === 'labs') { + if (!MatrixClientPeg.get().isGuest()) { + // Make it explicit that guests get the defaults (although they shouldn't + // have been able to ever toggle the flags anyway) + const userValue = localStorage.getItem(`mx_labs_feature_${featureId}`); + return userValue === 'true'; + } + return false; + } else { + console.warn(`Unknown features config for ${featureId}: ${sdkConfigValue}`); return false; } - // Return the default if this feature has an override to be the default value or - // if the feature has never been toggled and is therefore not in localStorage - if (Object.keys(feature).includes('override') || - localStorage.getItem(`mx_labs_feature_${featureId}`) === null - ) { - return feature.default; - } - return localStorage.getItem(`mx_labs_feature_${featureId}`) === 'true'; }, setFeatureEnabled: function(featureId: string, enabled: boolean) { diff --git a/src/Velociraptor.js b/src/Velociraptor.js index 9c85bafca0..9a674d4f09 100644 --- a/src/Velociraptor.js +++ b/src/Velociraptor.js @@ -1,6 +1,6 @@ -var React = require('react'); -var ReactDom = require('react-dom'); -var Velocity = require('velocity-vector'); +const React = require('react'); +const ReactDom = require('react-dom'); +const Velocity = require('velocity-vector'); /** * The Velociraptor contains components and animates transitions with velocity. @@ -46,13 +46,13 @@ module.exports = React.createClass({ * update `this.children` according to the new list of children given */ _updateChildren: function(newChildren) { - var self = this; - var oldChildren = this.children || {}; + const self = this; + const oldChildren = this.children || {}; this.children = {}; React.Children.toArray(newChildren).forEach(function(c) { if (oldChildren[c.key]) { - var old = oldChildren[c.key]; - var oldNode = ReactDom.findDOMNode(self.nodes[old.key]); + const old = oldChildren[c.key]; + const oldNode = ReactDom.findDOMNode(self.nodes[old.key]); if (oldNode && oldNode.style.left != c.props.style.left) { Velocity(oldNode, { left: c.props.style.left }, self.props.transition).then(function() { @@ -71,18 +71,18 @@ module.exports = React.createClass({ } else { // new element. If we have a startStyle, use that as the style and go through // the enter animations - var newProps = {}; - var restingStyle = c.props.style; + const newProps = {}; + const restingStyle = c.props.style; - var startStyles = self.props.startStyles; + const startStyles = self.props.startStyles; if (startStyles.length > 0) { - var startStyle = startStyles[0]; + const startStyle = startStyles[0]; newProps.style = startStyle; // console.log("mounted@startstyle0: "+JSON.stringify(startStyle)); } - newProps.ref = (n => self._collectNode( - c.key, n, restingStyle + newProps.ref = ((n) => self._collectNode( + c.key, n, restingStyle, )); self.children[c.key] = React.cloneElement(c, newProps); @@ -103,8 +103,8 @@ module.exports = React.createClass({ this.nodes[k] === undefined && this.props.startStyles.length > 0 ) { - var startStyles = this.props.startStyles; - var transitionOpts = this.props.enterTransitionOpts; + const startStyles = this.props.startStyles; + const transitionOpts = this.props.enterTransitionOpts; const domNode = ReactDom.findDOMNode(node); // start from startStyle 1: 0 is the one we gave it // to start with, so now we animate 1 etc. @@ -154,7 +154,7 @@ module.exports = React.createClass({ render: function() { return ( - {Object.values(this.children)} + { Object.values(this.children) } ); }, diff --git a/src/VelocityBounce.js b/src/VelocityBounce.js index 3ad7d207a9..2141b05325 100644 --- a/src/VelocityBounce.js +++ b/src/VelocityBounce.js @@ -1,9 +1,9 @@ -var Velocity = require('velocity-vector'); +const Velocity = require('velocity-vector'); // courtesy of https://github.com/julianshapiro/velocity/issues/283 // We only use easeOutBounce (easeInBounce is just sort of nonsensical) function bounce( p ) { - var pow2, + let pow2, bounce = 4; while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) { diff --git a/src/WhoIsTyping.js b/src/WhoIsTyping.js index 2a12703a27..6bea2cbb92 100644 --- a/src/WhoIsTyping.js +++ b/src/WhoIsTyping.js @@ -14,19 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ -var MatrixClientPeg = require("./MatrixClientPeg"); +const MatrixClientPeg = require("./MatrixClientPeg"); import { _t } from './languageHandler'; module.exports = { usersTypingApartFromMeAndIgnored: function(room) { return this.usersTyping( - room, [MatrixClientPeg.get().credentials.userId].concat(MatrixClientPeg.get().getIgnoredUsers()) + room, [MatrixClientPeg.get().credentials.userId].concat(MatrixClientPeg.get().getIgnoredUsers()), ); }, usersTypingApartFromMe: function(room) { return this.usersTyping( - room, [MatrixClientPeg.get().credentials.userId] + room, [MatrixClientPeg.get().credentials.userId], ); }, @@ -35,15 +35,15 @@ module.exports = { * to exclude, return a list of user objects who are typing. */ usersTyping: function(room, exclude) { - var whoIsTyping = []; + const whoIsTyping = []; if (exclude === undefined) { exclude = []; } - var memberKeys = Object.keys(room.currentState.members); - for (var i = 0; i < memberKeys.length; ++i) { - var userId = memberKeys[i]; + const memberKeys = Object.keys(room.currentState.members); + for (let i = 0; i < memberKeys.length; ++i) { + const userId = memberKeys[i]; if (room.currentState.members[userId].typing) { if (exclude.indexOf(userId) == -1) { @@ -76,5 +76,5 @@ module.exports = { const lastPerson = names.pop(); return _t('%(names)s and %(lastPerson)s are typing', {names: names.join(', '), lastPerson: lastPerson}); } - } + }, }; diff --git a/src/async-components/views/dialogs/EncryptedEventDialog.js b/src/async-components/views/dialogs/EncryptedEventDialog.js index cec2f05de2..a8f588d39a 100644 --- a/src/async-components/views/dialogs/EncryptedEventDialog.js +++ b/src/async-components/views/dialogs/EncryptedEventDialog.js @@ -14,10 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. */ -var React = require("react"); +const React = require("react"); import { _t } from '../../../languageHandler'; -var sdk = require('../../../index'); -var MatrixClientPeg = require("../../../MatrixClientPeg"); +const sdk = require('../../../index'); +const MatrixClientPeg = require("../../../MatrixClientPeg"); module.exports = React.createClass({ displayName: 'EncryptedEventDialog', @@ -33,7 +33,7 @@ module.exports = React.createClass({ componentWillMount: function() { this._unmounted = false; - var client = MatrixClientPeg.get(); + const client = MatrixClientPeg.get(); // first try to load the device from our store. // @@ -60,7 +60,7 @@ module.exports = React.createClass({ componentWillUnmount: function() { this._unmounted = true; - var client = MatrixClientPeg.get(); + const client = MatrixClientPeg.get(); if (client) { client.removeListener("deviceVerificationChanged", this.onDeviceVerificationChanged); } @@ -89,12 +89,12 @@ module.exports = React.createClass({ }, _renderDeviceInfo: function() { - var device = this.state.device; + const device = this.state.device; if (!device) { return ({ _t('unknown device') }); } - var verificationStatus = ({ _t('NOT verified') }); + let verificationStatus = ({ _t('NOT verified') }); if (device.isBlocked()) { verificationStatus = ({ _t('Blacklisted') }); } else if (device.isVerified()) { @@ -118,7 +118,7 @@ module.exports = React.createClass({ { _t('Ed25519 fingerprint') } - {device.getFingerprint()} + { device.getFingerprint() } @@ -126,7 +126,7 @@ module.exports = React.createClass({ }, _renderEventInfo: function() { - var event = this.props.event; + const event = this.props.event; return ( @@ -165,36 +165,36 @@ module.exports = React.createClass({ }, render: function() { - var DeviceVerifyButtons = sdk.getComponent('elements.DeviceVerifyButtons'); + const DeviceVerifyButtons = sdk.getComponent('elements.DeviceVerifyButtons'); - var buttons = null; + let buttons = null; if (this.state.device) { buttons = ( - ); } return ( -
+
{ _t('End-to-end encryption information') }

{ _t('Event information') }

- {this._renderEventInfo()} + { this._renderEventInfo() }

{ _t('Sender device information') }

- {this._renderDeviceInfo()} + { this._renderDeviceInfo() }
- - {buttons} + { buttons }
); - } + }, }); diff --git a/src/autocomplete/Autocompleter.js b/src/autocomplete/Autocompleter.js index 7a64fb154c..5b10110f04 100644 --- a/src/autocomplete/Autocompleter.js +++ b/src/autocomplete/Autocompleter.js @@ -45,7 +45,7 @@ const PROVIDERS = [ EmojiProvider, CommandProvider, DuckDuckGoProvider, -].map(completer => completer.getInstance()); +].map((completer) => completer.getInstance()); // Providers will get rejected if they take longer than this. const PROVIDER_COMPLETION_TIMEOUT = 3000; diff --git a/src/autocomplete/CommandProvider.js b/src/autocomplete/CommandProvider.js index eda05ef514..e85457e6aa 100644 --- a/src/autocomplete/CommandProvider.js +++ b/src/autocomplete/CommandProvider.js @@ -16,7 +16,7 @@ limitations under the License. */ import React from 'react'; -import { _t } from '../languageHandler'; +import { _t, _td } from '../languageHandler'; import AutocompleteProvider from './AutocompleteProvider'; import FuzzyMatcher from './FuzzyMatcher'; import {TextualCompletion} from './Components'; @@ -27,82 +27,82 @@ const COMMANDS = [ { command: '/me', args: '', - description: 'Displays action', + description: _td('Displays action'), }, { command: '/ban', args: ' [reason]', - description: 'Bans user with given id', + description: _td('Bans user with given id'), }, { command: '/unban', args: '', - description: 'Unbans user with given id', + description: _td('Unbans user with given id'), }, { command: '/op', args: ' []', - description: 'Define the power level of a user', + description: _td('Define the power level of a user'), }, { command: '/deop', args: '', - description: 'Deops user with given id', + description: _td('Deops user with given id'), }, { command: '/invite', args: '', - description: 'Invites user with given id to current room', + description: _td('Invites user with given id to current room'), }, { command: '/join', args: '', - description: 'Joins room with given alias', + description: _td('Joins room with given alias'), }, { command: '/part', args: '[]', - description: 'Leave room', + description: _td('Leave room'), }, { command: '/topic', args: '', - description: 'Sets the room topic', + description: _td('Sets the room topic'), }, { command: '/kick', args: ' [reason]', - description: 'Kicks user with given id', + description: _td('Kicks user with given id'), }, { command: '/nick', args: '', - description: 'Changes your display nickname', + description: _td('Changes your display nickname'), }, { command: '/ddg', args: '', - description: 'Searches DuckDuckGo for results', + description: _td('Searches DuckDuckGo for results'), }, { command: '/tint', args: ' []', - description: 'Changes colour scheme of current room', + description: _td('Changes colour scheme of current room'), }, { command: '/verify', args: ' ', - description: 'Verifies a user, device, and pubkey tuple', + description: _td('Verifies a user, device, and pubkey tuple'), }, { command: '/ignore', args: '', - description: 'Ignores a user, hiding their messages from you', + description: _td('Ignores a user, hiding their messages from you'), }, { command: '/unignore', args: '', - description: 'Stops ignoring a user, showing their messages going forward', + description: _td('Stops ignoring a user, showing their messages going forward'), }, // Omitting `/markdown` as it only seems to apply to OldComposer ]; diff --git a/src/autocomplete/Components.js b/src/autocomplete/Components.js index 0f0399cf7d..a27533f7c2 100644 --- a/src/autocomplete/Components.js +++ b/src/autocomplete/Components.js @@ -30,13 +30,13 @@ export class TextualCompletion extends React.Component { subtitle, description, className, - ...restProps, + ...restProps } = this.props; return (
- {title} - {subtitle} - {description} + { title } + { subtitle } + { description }
); } @@ -56,14 +56,14 @@ export class PillCompletion extends React.Component { description, initialComponent, className, - ...restProps, + ...restProps } = this.props; return (
- {initialComponent} - {title} - {subtitle} - {description} + { initialComponent } + { title } + { subtitle } + { description }
); } diff --git a/src/autocomplete/DuckDuckGoProvider.js b/src/autocomplete/DuckDuckGoProvider.js index 9c996bb1cc..b2e85c4668 100644 --- a/src/autocomplete/DuckDuckGoProvider.js +++ b/src/autocomplete/DuckDuckGoProvider.js @@ -38,7 +38,7 @@ export default class DuckDuckGoProvider extends AutocompleteProvider { } async getCompletions(query: string, selection: {start: number, end: number}) { - let {command, range} = this.getCurrentCommand(query, selection); + const {command, range} = this.getCurrentCommand(query, selection); if (!query || !command) { return []; } @@ -47,7 +47,7 @@ export default class DuckDuckGoProvider extends AutocompleteProvider { method: 'GET', }); const json = await response.json(); - let results = json.Results.map(result => { + const results = json.Results.map((result) => { return { completion: result.Text, component: ( @@ -105,7 +105,7 @@ export default class DuckDuckGoProvider extends AutocompleteProvider { renderCompletions(completions: [React.Component]): ?React.Component { return
- {completions} + { completions }
; } } diff --git a/src/autocomplete/EmojiProvider.js b/src/autocomplete/EmojiProvider.js index 35a2ee6b53..a5b80e3b0e 100644 --- a/src/autocomplete/EmojiProvider.js +++ b/src/autocomplete/EmojiProvider.js @@ -138,7 +138,7 @@ export default class EmojiProvider extends AutocompleteProvider { return { completion: unicode, component: ( - {unicode}} /> + { unicode }} /> ), range, }; @@ -152,14 +152,13 @@ export default class EmojiProvider extends AutocompleteProvider { } static getInstance() { - if (instance == null) - {instance = new EmojiProvider();} + if (instance == null) {instance = new EmojiProvider();} return instance; } renderCompletions(completions: [React.Component]): ?React.Component { return
- {completions} + { completions }
; } } diff --git a/src/autocomplete/UserProvider.js b/src/autocomplete/UserProvider.js index 26b30a3d27..296399c06c 100644 --- a/src/autocomplete/UserProvider.js +++ b/src/autocomplete/UserProvider.js @@ -59,7 +59,7 @@ export default class UserProvider extends AutocompleteProvider { if (this.users === null) this._makeUsers(); let completions = []; - let {command, range} = this.getCurrentCommand(query, selection, force); + const {command, range} = this.getCurrentCommand(query, selection, force); if (command) { completions = this.matcher.match(command[0]).map((user) => { const displayName = (user.name || user.userId || '').replace(' (IRC)', ''); // FIXME when groups are done @@ -71,7 +71,7 @@ export default class UserProvider extends AutocompleteProvider { href: 'https://matrix.to/#/' + user.userId, component: ( } + initialComponent={} title={displayName} description={user.userId} /> ), @@ -132,7 +132,7 @@ export default class UserProvider extends AutocompleteProvider { renderCompletions(completions: [React.Component]): ?React.Component { return
- {completions} + { completions }
; } diff --git a/src/components/structures/ContextualMenu.js b/src/components/structures/ContextualMenu.js index e5a62b8345..c3ad7f9cd1 100644 --- a/src/components/structures/ContextualMenu.js +++ b/src/components/structures/ContextualMenu.js @@ -17,9 +17,9 @@ limitations under the License. 'use strict'; -var classNames = require('classnames'); -var React = require('react'); -var ReactDOM = require('react-dom'); +const classNames = require('classnames'); +const React = require('react'); +const ReactDOM = require('react-dom'); // Shamelessly ripped off Modal.js. There's probably a better way // of doing reusable widgets like dialog boxes & menus where we go and @@ -36,7 +36,7 @@ module.exports = { }, getOrCreateContainer: function() { - var container = document.getElementById(this.ContextualMenuContainerId); + let container = document.getElementById(this.ContextualMenuContainerId); if (!container) { container = document.createElement("div"); @@ -48,9 +48,9 @@ module.exports = { }, createMenu: function(Element, props) { - var self = this; + const self = this; - var closeMenu = function() { + const closeMenu = function() { ReactDOM.unmountComponentAtNode(self.getOrCreateContainer()); if (props && props.onFinished) { @@ -58,17 +58,17 @@ module.exports = { } }; - var position = { + const position = { top: props.top, }; - var chevronOffset = {}; + const chevronOffset = {}; if (props.chevronOffset) { chevronOffset.top = props.chevronOffset; } // To override the default chevron colour, if it's been set - var chevronCSS = ""; + let chevronCSS = ""; if (props.menuColour) { chevronCSS = ` .mx_ContextualMenu_chevron_left:after { @@ -81,7 +81,7 @@ module.exports = { `; } - var chevron = null; + let chevron = null; if (props.left) { chevron =
; position.left = props.left; @@ -90,15 +90,15 @@ module.exports = { position.right = props.right; } - var className = 'mx_ContextualMenu_wrapper'; + const className = 'mx_ContextualMenu_wrapper'; - var menuClasses = classNames({ + const menuClasses = classNames({ 'mx_ContextualMenu': true, 'mx_ContextualMenu_left': props.left, 'mx_ContextualMenu_right': !props.left, }); - var menuStyle = {}; + const menuStyle = {}; if (props.menuWidth) { menuStyle.width = props.menuWidth; } @@ -113,14 +113,14 @@ module.exports = { // FIXME: If a menu uses getDefaultProps it clobbers the onFinished // property set here so you can't close the menu from a button click! - var menu = ( + const menu = (
- {chevron} - + { chevron } +
- +
); diff --git a/src/components/structures/CreateRoom.js b/src/components/structures/CreateRoom.js index 7ecc315ba7..26454c5ea6 100644 --- a/src/components/structures/CreateRoom.js +++ b/src/components/structures/CreateRoom.js @@ -61,7 +61,7 @@ module.exports = React.createClass({ }, onCreateRoom: function() { - var options = {}; + const options = {}; if (this.state.room_name) { options.name = this.state.room_name; @@ -79,14 +79,14 @@ module.exports = React.createClass({ { type: "m.room.join_rules", content: { - "join_rule": this.state.is_private ? "invite" : "public" - } + "join_rule": this.state.is_private ? "invite" : "public", + }, }, { type: "m.room.history_visibility", content: { - "history_visibility": this.state.share_history ? "shared" : "invited" - } + "history_visibility": this.state.share_history ? "shared" : "invited", + }, }, ]; } @@ -94,19 +94,19 @@ module.exports = React.createClass({ options.invite = this.state.invited_users; - var alias = this.getAliasLocalpart(); + const alias = this.getAliasLocalpart(); if (alias) { options.room_alias_name = alias; } - var cli = MatrixClientPeg.get(); + const cli = MatrixClientPeg.get(); if (!cli) { // TODO: Error. console.error("Cannot create room: No matrix client."); return; } - var deferred = cli.createRoom(options); + const deferred = cli.createRoom(options); if (this.state.encrypt) { // TODO @@ -116,7 +116,7 @@ module.exports = React.createClass({ phase: this.phases.CREATING, }); - var self = this; + const self = this; deferred.then(function(resp) { self.setState({ @@ -209,7 +209,7 @@ module.exports = React.createClass({ onAliasChanged: function(alias) { this.setState({ - alias: alias + alias: alias, }); }, @@ -220,64 +220,64 @@ module.exports = React.createClass({ }, render: function() { - var curr_phase = this.state.phase; + const curr_phase = this.state.phase; if (curr_phase == this.phases.CREATING) { - var Loader = sdk.getComponent("elements.Spinner"); + const Loader = sdk.getComponent("elements.Spinner"); return ( - + ); } else { - var error_box = ""; + let error_box = ""; if (curr_phase == this.phases.ERROR) { error_box = (
- {_t('An error occurred: %(error_string)s', {error_string: this.state.error_string})} + { _t('An error occurred: %(error_string)s', {error_string: this.state.error_string}) }
); } - var CreateRoomButton = sdk.getComponent("create_room.CreateRoomButton"); - var RoomAlias = sdk.getComponent("create_room.RoomAlias"); - var Presets = sdk.getComponent("create_room.Presets"); - var UserSelector = sdk.getComponent("elements.UserSelector"); - var SimpleRoomHeader = sdk.getComponent("rooms.SimpleRoomHeader"); + const CreateRoomButton = sdk.getComponent("create_room.CreateRoomButton"); + const RoomAlias = sdk.getComponent("create_room.RoomAlias"); + const Presets = sdk.getComponent("create_room.Presets"); + const UserSelector = sdk.getComponent("elements.UserSelector"); + const SimpleRoomHeader = sdk.getComponent("rooms.SimpleRoomHeader"); - var domain = MatrixClientPeg.get().getDomain(); + const domain = MatrixClientPeg.get().getDomain(); return (
- +
-
-