diff --git a/docs/settings.md b/docs/settings.md index cdba01e04a..9762e7a73e 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -131,6 +131,32 @@ SettingsStore.getValue(...); // this will return the value set in `setValue` abo ``` +## Watching for changes + +Most use cases do not need to set up a watcher because they are able to react to changes as they are made, or the changes which are made are not significant enough for it to matter. Watchers are intended to be used in scenarios where it is important to react to changes made by other logged in devices. Typically, this would be done within the component itself, however the component should not be aware of the intricacies of setting inversion or remapping to particular data structures. Instead, a generic watcher interface is provided on `SettingsStore` to watch (and subsequently unwatch) for changes in a setting. + +An example of a watcher in action would be: + +```javascript +class MyComponent extends React.Component { + + settingWatcherRef = null; + + componentWillMount() { + this.settingWatcherRef = SettingsStore.watchSetting("roomColor", "!example:matrix.org", (settingName, roomId, level, newVal) => { + // Always re-read the setting value from the store to avoid reacting to changes which do not have a consequence. For example, the + // room color could have been changed at the device level, but an account override prevents that change from making a difference. + const actualVal = SettingsStore.getValue(settingName, "!example:matrix.org"); + if (actualVal !== this.state.color) this.setState({color: actualVal}); + }); + } + + componentWillUnmount() { + SettingsStore.unwatchSetting(this.settingWatcherRef); + } +} +``` + # Maintainers Reference @@ -159,3 +185,10 @@ Features automatically get considered as `disabled` if they are not listed in th ``` If `enableLabs` is true in the configuration, the default for features becomes `"labs"`. + +### Watchers + +Watchers can appear complicated under the hood: the request to watch a setting is actually forked off to individual handlers for watching. This means that the handlers need to track their changes and listen for remote changes where possible, but also makes it much easier for the `SettingsStore` to react to changes. The handler is going to know the best things to listen for (specific events, account data, etc) and thus it is left as a responsibility for the handler to track changes. + +In practice, handlers which rely on remote changes (account data, room events, etc) will always attach a listener to the `MatrixClient`. They then watch for changes to events they care about and send off appropriate updates to the generalized `WatchManager` - a class specifically designed to deduplicate the logic of managing watchers. The handlers which are localized to the local client (device) generally just trigger the `WatchManager` when they manipulate the setting themselves as there's nothing to really 'watch'. + \ No newline at end of file diff --git a/package.json b/package.json index fba17bb9c9..84d5632023 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "gemini-scrollbar": "github:matrix-org/gemini-scrollbar#b302279", "gfm.css": "^1.1.1", "glob": "^5.0.14", - "highlight.js": "^9.13.0", + "highlight.js": "9.14.2", "is-ip": "^2.0.0", "isomorphic-fetch": "^2.2.1", "linkifyjs": "^2.1.6", diff --git a/res/css/_common.scss b/res/css/_common.scss index fd93c8c967..4e327ab28d 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -249,12 +249,6 @@ textarea { box-shadow: none; } -/* View Source Dialog overide */ -.mx_Dialog_wrapper.mx_Dialog_viewsource .mx_Dialog { - padding-left: 10px; - padding-right: 10px; -} - .mx_Dialog { background-color: $primary-bg-color; color: $light-fg-color; diff --git a/res/css/_components.scss b/res/css/_components.scss index 6aed78a627..f3b07255ae 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -150,16 +150,16 @@ @import "./views/settings/_Notifications.scss"; @import "./views/settings/_PhoneNumbers.scss"; @import "./views/settings/_ProfileSettings.scss"; -@import "./views/settings/tabs/_GeneralRoomSettingsTab.scss"; -@import "./views/settings/tabs/_GeneralUserSettingsTab.scss"; -@import "./views/settings/tabs/_HelpSettingsTab.scss"; -@import "./views/settings/tabs/_NotificationSettingsTab.scss"; -@import "./views/settings/tabs/_PreferencesSettingsTab.scss"; -@import "./views/settings/tabs/_RolesRoomSettingsTab.scss"; -@import "./views/settings/tabs/_SecurityRoomSettingsTab.scss"; -@import "./views/settings/tabs/_SecuritySettingsTab.scss"; @import "./views/settings/tabs/_SettingsTab.scss"; -@import "./views/settings/tabs/_VoiceSettingsTab.scss"; +@import "./views/settings/tabs/room/_GeneralRoomSettingsTab.scss"; +@import "./views/settings/tabs/room/_RolesRoomSettingsTab.scss"; +@import "./views/settings/tabs/room/_SecurityRoomSettingsTab.scss"; +@import "./views/settings/tabs/user/_GeneralUserSettingsTab.scss"; +@import "./views/settings/tabs/user/_HelpUserSettingsTab.scss"; +@import "./views/settings/tabs/user/_NotificationUserSettingsTab.scss"; +@import "./views/settings/tabs/user/_PreferencesUserSettingsTab.scss"; +@import "./views/settings/tabs/user/_SecurityUserSettingsTab.scss"; +@import "./views/settings/tabs/user/_VoiceUserSettingsTab.scss"; @import "./views/verification/_VerificationShowSas.scss"; @import "./views/voip/_CallView.scss"; @import "./views/voip/_IncomingCallbox.scss"; diff --git a/res/css/structures/_ViewSource.scss b/res/css/structures/_ViewSource.scss index a4c7dcf58a..b908861c6f 100644 --- a/res/css/structures/_ViewSource.scss +++ b/res/css/structures/_ViewSource.scss @@ -14,6 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ +.mx_ViewSource_label_left { + float: left; +} + +.mx_ViewSource_label_right { + float: right; +} + +.mx_ViewSource_label_bottom { + clear: both; + border-bottom: 1px solid #e5e5e5; +} + .mx_ViewSource pre { text-align: left; font-size: 12px; diff --git a/res/css/views/auth/_AuthBody.scss b/res/css/views/auth/_AuthBody.scss index 6216bdd4b8..778f5f6a4d 100644 --- a/res/css/views/auth/_AuthBody.scss +++ b/res/css/views/auth/_AuthBody.scss @@ -58,6 +58,10 @@ limitations under the License. background-color: $authpage-body-bg-color; } +.mx_AuthBody input.error { + color: $warning-color; +} + .mx_AuthBody_editServerDetails { padding-left: 1em; font-size: 12px; diff --git a/res/css/views/dialogs/_DevtoolsDialog.scss b/res/css/views/dialogs/_DevtoolsDialog.scss index 572d6ee8c7..815e8408b5 100644 --- a/res/css/views/dialogs/_DevtoolsDialog.scss +++ b/res/css/views/dialogs/_DevtoolsDialog.scss @@ -67,12 +67,20 @@ limitations under the License. .mx_DevTools_textarea { font-size: 12px; - max-width: 624px; + max-width: 684px; min-height: 250px; padding: 10px; width: 100%; } +.mx_DevTools_content .mx_Field_input { + display: inline-block; +} + +.mx_DevTools_content .mx_Field_input + .mx_Field_input { + margin-left: 42px; +} + .mx_DevTools_tgl { display: none; diff --git a/res/css/views/dialogs/_RoomSettingsDialog.scss b/res/css/views/dialogs/_RoomSettingsDialog.scss index de675abe32..e2a0238756 100644 --- a/res/css/views/dialogs/_RoomSettingsDialog.scss +++ b/res/css/views/dialogs/_RoomSettingsDialog.scss @@ -32,3 +32,13 @@ limitations under the License. .mx_RoomSettingsDialog_warningIcon:before { mask-image: url('$(res)/img/feather-icons/warning-triangle.svg'); } + +.mx_RoomSettingsDialog .mx_Dialog_title { + -ms-text-overflow: ellipsis; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + margin: 0 auto; + padding-left: 40px; + padding-right: 80px; +} diff --git a/res/css/views/rooms/_RoomTile.scss b/res/css/views/rooms/_RoomTile.scss index f2557f7849..97b2c48236 100644 --- a/res/css/views/rooms/_RoomTile.scss +++ b/res/css/views/rooms/_RoomTile.scss @@ -102,7 +102,6 @@ limitations under the License. .mx_RoomTile_name { font-size: 14px; - font-weight: 600; padding: 0 6px; color: $roomtile-name-color; white-space: nowrap; @@ -155,7 +154,7 @@ limitations under the License. .mx_RoomTile_unread, .mx_RoomTile_highlight { .mx_RoomTile_name { - // font-weight: 700; // bold is too loud in the end + font-weight: 600; color: $roomtile-selected-color; } } diff --git a/res/css/views/rooms/_WhoIsTypingTile.scss b/res/css/views/rooms/_WhoIsTypingTile.scss index eb51595858..ef20c24c84 100644 --- a/res/css/views/rooms/_WhoIsTypingTile.scss +++ b/res/css/views/rooms/_WhoIsTypingTile.scss @@ -40,6 +40,7 @@ limitations under the License. } .mx_WhoIsTypingTile_remainingAvatarPlaceholder { + position: relative; display: inline-block; color: #acacac; background-color: #ddd; diff --git a/res/css/views/settings/tabs/_GeneralRoomSettingsTab.scss b/res/css/views/settings/tabs/room/_GeneralRoomSettingsTab.scss similarity index 100% rename from res/css/views/settings/tabs/_GeneralRoomSettingsTab.scss rename to res/css/views/settings/tabs/room/_GeneralRoomSettingsTab.scss diff --git a/res/css/views/settings/tabs/_RolesRoomSettingsTab.scss b/res/css/views/settings/tabs/room/_RolesRoomSettingsTab.scss similarity index 100% rename from res/css/views/settings/tabs/_RolesRoomSettingsTab.scss rename to res/css/views/settings/tabs/room/_RolesRoomSettingsTab.scss diff --git a/res/css/views/settings/tabs/_SecurityRoomSettingsTab.scss b/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss similarity index 100% rename from res/css/views/settings/tabs/_SecurityRoomSettingsTab.scss rename to res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss diff --git a/res/css/views/settings/tabs/_GeneralUserSettingsTab.scss b/res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss similarity index 100% rename from res/css/views/settings/tabs/_GeneralUserSettingsTab.scss rename to res/css/views/settings/tabs/user/_GeneralUserSettingsTab.scss diff --git a/res/css/views/settings/tabs/_HelpSettingsTab.scss b/res/css/views/settings/tabs/user/_HelpUserSettingsTab.scss similarity index 87% rename from res/css/views/settings/tabs/_HelpSettingsTab.scss rename to res/css/views/settings/tabs/user/_HelpUserSettingsTab.scss index 249f06ca95..fa0d0edeb7 100644 --- a/res/css/views/settings/tabs/_HelpSettingsTab.scss +++ b/res/css/views/settings/tabs/user/_HelpUserSettingsTab.scss @@ -14,11 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_HelpSettingsTab_debugButton { +.mx_HelpUserSettingsTab_debugButton { margin-bottom: 5px; margin-top: 5px; } -.mx_HelpSettingsTab span.mx_AccessibleButton { +.mx_HelpUserSettingsTab span.mx_AccessibleButton { word-break: break-word; } \ No newline at end of file diff --git a/res/css/views/settings/tabs/_NotificationSettingsTab.scss b/res/css/views/settings/tabs/user/_NotificationUserSettingsTab.scss similarity index 91% rename from res/css/views/settings/tabs/_NotificationSettingsTab.scss rename to res/css/views/settings/tabs/user/_NotificationUserSettingsTab.scss index 8fdb688496..3cebd2958e 100644 --- a/res/css/views/settings/tabs/_NotificationSettingsTab.scss +++ b/res/css/views/settings/tabs/user/_NotificationUserSettingsTab.scss @@ -14,6 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_NotificationSettingsTab .mx_SettingsTab_heading { +.mx_NotificationUserSettingsTab .mx_SettingsTab_heading { margin-bottom: 10px; // Give some spacing between the title and the first elements } \ No newline at end of file diff --git a/res/css/views/settings/tabs/_PreferencesSettingsTab.scss b/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.scss similarity index 89% rename from res/css/views/settings/tabs/_PreferencesSettingsTab.scss rename to res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.scss index b59b69e63b..f447221b7a 100644 --- a/res/css/views/settings/tabs/_PreferencesSettingsTab.scss +++ b/res/css/views/settings/tabs/user/_PreferencesUserSettingsTab.scss @@ -14,11 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_PreferencesSettingsTab .mx_Field { +.mx_PreferencesUserSettingsTab .mx_Field { margin-right: 100px; // Align with the rest of the controls } -.mx_PreferencesSettingsTab .mx_Field input { +.mx_PreferencesUserSettingsTab .mx_Field input { display: block; // Subtract 10px padding on left and right diff --git a/res/css/views/settings/tabs/_SecuritySettingsTab.scss b/res/css/views/settings/tabs/user/_SecurityUserSettingsTab.scss similarity index 67% rename from res/css/views/settings/tabs/_SecuritySettingsTab.scss rename to res/css/views/settings/tabs/user/_SecurityUserSettingsTab.scss index ba357f16c3..4835640904 100644 --- a/res/css/views/settings/tabs/_SecuritySettingsTab.scss +++ b/res/css/views/settings/tabs/user/_SecurityUserSettingsTab.scss @@ -14,40 +14,40 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_SecuritySettingsTab .mx_DevicesPanel { +.mx_SecurityUserSettingsTab .mx_DevicesPanel { // Normally the panel is 880px, however this can easily overflow the container. // TODO: Fix the table to not be squishy width: auto; max-width: 880px; } -.mx_SecuritySettingsTab_deviceInfo { +.mx_SecurityUserSettingsTab_deviceInfo { display: table; padding-left: 0; } -.mx_SecuritySettingsTab_deviceInfo > li { +.mx_SecurityUserSettingsTab_deviceInfo > li { display: table-row; } -.mx_SecuritySettingsTab_deviceInfo > li > label, -.mx_SecuritySettingsTab_deviceInfo > li > span { +.mx_SecurityUserSettingsTab_deviceInfo > li > label, +.mx_SecurityUserSettingsTab_deviceInfo > li > span { display: table-cell; padding-right: 1em; } -.mx_SecuritySettingsTab_importExportButtons .mx_AccessibleButton { +.mx_SecurityUserSettingsTab_importExportButtons .mx_AccessibleButton { margin-right: 10px; } -.mx_SecuritySettingsTab_importExportButtons { +.mx_SecurityUserSettingsTab_importExportButtons { margin-bottom: 15px; } -.mx_SecuritySettingsTab_ignoredUser { +.mx_SecurityUserSettingsTab_ignoredUser { margin-bottom: 5px; } -.mx_SecuritySettingsTab_ignoredUser .mx_AccessibleButton { +.mx_SecurityUserSettingsTab_ignoredUser .mx_AccessibleButton { margin-right: 10px; } \ No newline at end of file diff --git a/res/css/views/settings/tabs/_VoiceSettingsTab.scss b/res/css/views/settings/tabs/user/_VoiceUserSettingsTab.scss similarity index 84% rename from res/css/views/settings/tabs/_VoiceSettingsTab.scss rename to res/css/views/settings/tabs/user/_VoiceUserSettingsTab.scss index 5ddd57b0e2..f5dba9831e 100644 --- a/res/css/views/settings/tabs/_VoiceSettingsTab.scss +++ b/res/css/views/settings/tabs/user/_VoiceUserSettingsTab.scss @@ -14,15 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_VoiceSettingsTab .mx_Field select { +.mx_VoiceUserSettingsTab .mx_Field select { width: 100%; max-width: 100%; } -.mx_VoiceSettingsTab .mx_Field { +.mx_VoiceUserSettingsTab .mx_Field { margin-right: 100px; // align with the rest of the fields } -.mx_VoiceSettingsTab_missingMediaPermissions { +.mx_VoiceUserSettingsTab_missingMediaPermissions { margin-bottom: 15px; } diff --git a/src/BasePlatform.js b/src/BasePlatform.js index 79f0d69e2c..54310d1849 100644 --- a/src/BasePlatform.js +++ b/src/BasePlatform.js @@ -113,4 +113,29 @@ export default class BasePlatform { reload() { throw new Error("reload not implemented!"); } + + supportsAutoLaunch(): boolean { + return false; + } + + // XXX: Surely this should be a setting like any other? + async getAutoLaunchEnabled(): boolean { + return false; + } + + async setAutoLaunchEnabled(enabled: boolean): void { + throw new Error("Unimplemented"); + } + + supportsMinimizeToTray(): boolean { + return false; + } + + async getMinimizeToTrayEnabled(): boolean { + return false; + } + + async setMinimizeToTrayEnabled(enabled: boolean): void { + throw new Error("Unimplemented"); + } } diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index e36034c69d..1cf29c3e82 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -30,6 +30,7 @@ import MatrixActionCreators from './actions/MatrixActionCreators'; import {phasedRollOutExpiredForUser} from "./PhasedRollOut"; import Modal from './Modal'; import {verificationMethods} from 'matrix-js-sdk/lib/crypto'; +import MatrixClientBackedSettingsHandler from "./settings/handlers/MatrixClientBackedSettingsHandler"; interface MatrixClientCreds { homeserverUrl: string, @@ -137,8 +138,9 @@ class MatrixClientPeg { opts.pendingEventOrdering = "detached"; opts.lazyLoadMembers = true; - // Connect the matrix client to the dispatcher + // Connect the matrix client to the dispatcher and setting handlers MatrixActionCreators.start(this.matrixClient); + MatrixClientBackedSettingsHandler.matrixClient = this.matrixClient; console.log(`MatrixClientPeg: really starting MatrixClient`); await this.get().startClient(opts); diff --git a/src/SdkConfig.js b/src/SdkConfig.js index 65982bd6f2..78dd050a1e 100644 --- a/src/SdkConfig.js +++ b/src/SdkConfig.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -const DEFAULTS = { +export const DEFAULTS = { // URL to a page we show in an iframe to configure integrations integrations_ui_url: "https://scalar.vector.im/", // Base URL to the REST interface of the integrations server diff --git a/src/SlashCommands.js b/src/SlashCommands.js index 115cf0e018..e20340bf28 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -110,6 +110,24 @@ export const CommandMap = { }, }), + roomnick: new Command({ + name: 'roomnick', + args: '', + description: _td('Changes your display nickname in the current room only'), + runFn: function(roomId, args) { + if (args) { + const cli = MatrixClientPeg.get(); + const ev = cli.getRoom(roomId).currentState.getStateEvents('m.room.member', cli.getUserId()); + const content = { + ...ev ? ev.getContent() : { membership: 'join' }, + displayname: args, + }; + return success(cli.sendStateEvent(roomId, 'm.room.member', content, cli.getUserId())); + } + return reject(this.getUsage()); + }, + }), + tint: new Command({ name: 'tint', args: ' []', diff --git a/src/components/structures/GroupView.js b/src/components/structures/GroupView.js index 89fce9c718..b80f49d051 100644 --- a/src/components/structures/GroupView.js +++ b/src/components/structures/GroupView.js @@ -34,6 +34,7 @@ import GroupStore from '../../stores/GroupStore'; import FlairStore from '../../stores/FlairStore'; import { showGroupAddRoomDialog } from '../../GroupAddressPicker'; import {makeGroupPermalink, makeUserPermalink} from "../../matrix-to"; +import {Group} from "matrix-js-sdk"; const LONG_DESC_PLACEHOLDER = _td( `

HTML for your community's page

@@ -569,7 +570,7 @@ export default React.createClass({ _onShareClick: function() { const ShareDialog = sdk.getComponent("dialogs.ShareDialog"); Modal.createTrackedDialog('share community dialog', '', ShareDialog, { - target: this._matrixClient.getGroup(this.props.groupId), + target: this._matrixClient.getGroup(this.props.groupId) || new Group(this.props.groupId), }); }, diff --git a/src/components/structures/LeftPanel.js b/src/components/structures/LeftPanel.js index 000195d349..7088347ff4 100644 --- a/src/components/structures/LeftPanel.js +++ b/src/components/structures/LeftPanel.js @@ -26,6 +26,7 @@ import dis from '../../dispatcher'; import VectorConferenceHandler from '../../VectorConferenceHandler'; import TagPanelButtons from './TagPanelButtons'; import SettingsStore from '../../settings/SettingsStore'; +import {_t} from "../../languageHandler"; const LeftPanel = React.createClass({ @@ -212,6 +213,7 @@ const LeftPanel = React.createClass({ ); const searchBox = (); diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js index dd3d92913c..185af4cd6d 100644 --- a/src/components/structures/MessagePanel.js +++ b/src/components/structures/MessagePanel.js @@ -525,6 +525,7 @@ module.exports = React.createClass({ eventSendStatus={mxEv.status} tileShape={this.props.tileShape} isTwelveHour={this.props.isTwelveHour} + permalinkCreator={this.props.permalinkCreator} last={last} isSelectedEvent={highlight} /> , ); diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 8e32802d0a..8d55715dbf 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -30,6 +30,7 @@ import Promise from 'bluebird'; import filesize from 'filesize'; const classNames = require("classnames"); import { _t } from '../../languageHandler'; +import {RoomPermalinkCreator} from "../../matrix-to"; const MatrixClientPeg = require("../../MatrixClientPeg"); const ContentMessages = require("../../ContentMessages"); @@ -441,6 +442,11 @@ module.exports = React.createClass({ RoomScrollStateStore.setScrollState(this.state.roomId, this._getScrollState()); } + // stop tracking room changes to format permalinks + if (this.state.permalinkCreator) { + this.state.permalinkCreator.stop(); + } + if (this.refs.roomView) { // disconnect the D&D event listeners from the room view. This // is really just for hygiene - we're going to be @@ -537,12 +543,12 @@ module.exports = React.createClass({ case 'picture_snapshot': this.uploadFile(payload.file); break; - case 'notifier_enabled': case 'upload_failed': // 413: File was too big or upset the server in some way. - if(payload.error.http_status === 413) { + if (payload.error && payload.error.http_status === 413) { this._fetchMediaConfig(true); } + case 'notifier_enabled': case 'upload_started': case 'upload_finished': this.forceUpdate(); @@ -652,6 +658,11 @@ module.exports = React.createClass({ this._loadMembersIfJoined(room); this._calculateRecommendedVersion(room); this._updateE2EStatus(room); + if (!this.state.permalinkCreator) { + const permalinkCreator = new RoomPermalinkCreator(room); + permalinkCreator.start(); + this.setState({permalinkCreator}); + } }, _calculateRecommendedVersion: async function(room) { @@ -1219,6 +1230,7 @@ module.exports = React.createClass({ searchResult={result} searchHighlights={this.state.searchHighlights} resultLink={resultLink} + permalinkCreator={this.state.permalinkCreator} onWidgetLoad={onWidgetLoad} />); } return ret; @@ -1305,7 +1317,10 @@ module.exports = React.createClass({ }, onSearchClick: function() { - this.setState({ searching: true, showingPinned: false }); + this.setState({ + searching: !this.state.searching, + showingPinned: false, + }); }, onCancelSearchClick: function() { @@ -1722,6 +1737,7 @@ module.exports = React.createClass({ showApps={this.state.showApps} uploadAllowed={this.isFileUploadAllowed} e2eStatus={this.state.e2eStatus} + permalinkCreator={this.state.permalinkCreator} />; } @@ -1823,6 +1839,7 @@ module.exports = React.createClass({ showUrlPreview = {this.state.showUrlPreview} className="mx_RoomView_messagePanel" membersLoaded={this.state.membersLoaded} + permalinkCreator={this.state.permalinkCreator} />); let topUnreadMessagesBar = null; diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js index 10628ccd13..3f9d954f9f 100644 --- a/src/components/structures/SearchBox.js +++ b/src/components/structures/SearchBox.js @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,12 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. */ -'use strict'; - import React from 'react'; -import { _t } from '../../languageHandler'; +import PropTypes from 'prop-types'; import { KeyCode } from '../../Keyboard'; -import sdk from '../../index'; import dis from '../../dispatcher'; import { throttle } from 'lodash'; import AccessibleButton from '../../components/views/elements/AccessibleButton'; @@ -28,8 +26,10 @@ module.exports = React.createClass({ displayName: 'SearchBox', propTypes: { - onSearch: React.PropTypes.func, - onCleared: React.PropTypes.func, + onSearch: PropTypes.func, + onCleared: PropTypes.func, + className: PropTypes.string, + placeholder: PropTypes.string.isRequired, }, getInitialState: function() { @@ -102,21 +102,22 @@ module.exports = React.createClass({ const clearButton = this.state.searchTerm.length > 0 ? ( {this._clearSearch("button")} }> - ) : undefined; + onClick={ () => {this._clearSearch("button"); } }> + ) : undefined; + const className = this.props.className || ""; return (
{ clearButton }
diff --git a/src/components/structures/TimelinePanel.js b/src/components/structures/TimelinePanel.js index 9fe83c2c2d..8890c26d42 100644 --- a/src/components/structures/TimelinePanel.js +++ b/src/components/structures/TimelinePanel.js @@ -1202,6 +1202,7 @@ var TimelinePanel = React.createClass({ return (