diff --git a/src/DateUtils.js b/src/DateUtils.js deleted file mode 100644 index fe363586ab..0000000000 --- a/src/DateUtils.js +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; -var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; - -module.exports = { - formatDate: function(date) { - // date.toLocaleTimeString is completely system dependent. - // just go 24h for now - function pad(n) { - return (n < 10 ? '0' : '') + n; - } - - var now = new Date(); - if (date.toDateString() === now.toDateString()) { - return pad(date.getHours()) + ':' + pad(date.getMinutes()); - } - else if (now.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) { - return days[date.getDay()] + " " + pad(date.getHours()) + ':' + pad(date.getMinutes()); - } - else if (now.getFullYear() === date.getFullYear()) { - return days[date.getDay()] + ", " + months[date.getMonth()] + " " + (date.getDay()+1) + " " + pad(date.getHours()) + ':' + pad(date.getMinutes()); - } - else { - return days[date.getDay()] + ", " + months[date.getMonth()] + " " + (date.getDay()+1) + " " + date.getFullYear() + " " + pad(date.getHours()) + ':' + pad(date.getMinutes()); - } - } -} - diff --git a/src/Resend.js b/src/Resend.js deleted file mode 100644 index 52b7c93654..0000000000 --- a/src/Resend.js +++ /dev/null @@ -1,24 +0,0 @@ -var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); -var dis = require('matrix-react-sdk/lib/dispatcher'); - -module.exports = { - resend: function(event) { - MatrixClientPeg.get().resendEvent( - event, MatrixClientPeg.get().getRoom(event.getRoomId()) - ).done(function() { - dis.dispatch({ - action: 'message_sent', - event: event - }); - }, function() { - dis.dispatch({ - action: 'message_send_failed', - event: event - }); - }); - dis.dispatch({ - action: 'message_resend_started', - event: event - }); - }, -}; \ No newline at end of file diff --git a/src/modules/VectorConferenceHandler.js b/src/VectorConferenceHandler.js similarity index 100% rename from src/modules/VectorConferenceHandler.js rename to src/VectorConferenceHandler.js diff --git a/src/components/structures/login/Login.js b/src/components/structures/login/Login.js deleted file mode 100644 index bcf0656f9a..0000000000 --- a/src/components/structures/login/Login.js +++ /dev/null @@ -1,199 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -var React = require('react'); -var ReactDOM = require('react-dom'); -var sdk = require('matrix-react-sdk'); -var Signup = require("matrix-react-sdk/lib/Signup"); -var PasswordLogin = require("matrix-react-sdk/lib/components/views/login/PasswordLogin"); -var CasLogin = require("matrix-react-sdk/lib/components/views/login/CasLogin"); -var ServerConfig = require("../../views/login/ServerConfig"); - -/** - * A wire component which glues together login UI components and Signup logic - */ -module.exports = React.createClass({displayName: 'Login', - propTypes: { - onLoggedIn: React.PropTypes.func.isRequired, - homeserverUrl: React.PropTypes.string, - identityServerUrl: React.PropTypes.string, - // login shouldn't know or care how registration is done. - onRegisterClick: React.PropTypes.func.isRequired - }, - - getDefaultProps: function() { - return { - homeserverUrl: 'https://matrix.org/', - identityServerUrl: 'https://vector.im' - }; - }, - - getInitialState: function() { - return { - busy: false, - errorText: null, - enteredHomeserverUrl: this.props.homeserverUrl, - enteredIdentityServerUrl: this.props.identityServerUrl - }; - }, - - componentWillMount: function() { - this._initLoginLogic(); - }, - - onPasswordLogin: function(username, password) { - var self = this; - self.setState({ - busy: true - }); - - this._loginLogic.loginViaPassword(username, password).then(function(data) { - self.props.onLoggedIn(data); - }, function(error) { - self._setErrorTextFromError(error); - }).finally(function() { - self.setState({ - busy: false - }); - }); - }, - - onHsUrlChanged: function(newHsUrl) { - this._initLoginLogic(newHsUrl); - }, - - onIsUrlChanged: function(newIsUrl) { - this._initLoginLogic(null, newIsUrl); - }, - - _initLoginLogic: function(hsUrl, isUrl) { - var self = this; - hsUrl = hsUrl || this.state.enteredHomeserverUrl; - isUrl = isUrl || this.state.enteredIdentityServerUrl; - - var loginLogic = new Signup.Login(hsUrl, isUrl); - this._loginLogic = loginLogic; - - loginLogic.getFlows().then(function(flows) { - // old behaviour was to always use the first flow without presenting - // options. This works in most cases (we don't have a UI for multiple - // logins so let's skip that for now). - loginLogic.chooseFlow(0); - }, function(err) { - self._setErrorTextFromError(err); - }).finally(function() { - self.setState({ - busy: false - }); - }); - - this.setState({ - enteredHomeserverUrl: hsUrl, - enteredIdentityServerUrl: isUrl, - busy: true, - errorText: null // reset err messages - }); - }, - - _getCurrentFlowStep: function() { - return this._loginLogic ? this._loginLogic.getCurrentFlowStep() : null - }, - - _setErrorTextFromError: function(err) { - if (err.friendlyText) { - this.setState({ - errorText: err.friendlyText - }); - return; - } - - var errCode = err.errcode; - if (!errCode && err.httpStatus) { - errCode = "HTTP " + err.httpStatus; - } - this.setState({ - errorText: ( - "Error: Problem communicating with the given homeserver " + - (errCode ? "(" + errCode + ")" : "") - ) - }); - }, - - componentForStep: function(step) { - switch (step) { - case 'm.login.password': - return ( - - ); - case 'm.login.cas': - return ( - - ); - default: - if (!step) { - return; - } - return ( -
- Sorry, this homeserver is using a login which is not - recognised by Vector ({step}) -
- ); - } - }, - - render: function() { - var Loader = sdk.getComponent("elements.Spinner"); - var loader = this.state.busy ?
: null; - - return ( -
-
-
- vector -
-
-

Sign in

- { this.componentForStep(this._getCurrentFlowStep()) } - -
- { loader } - { this.state.errorText } -
- - Create a new account - -
-
- blog  ·   - twitter  ·   - github  ·   - powered by Matrix -
-
-
-
- ); - } -}); diff --git a/src/components/structures/login/PostRegistration.js b/src/components/structures/login/PostRegistration.js deleted file mode 100644 index 28fab4c161..0000000000 --- a/src/components/structures/login/PostRegistration.js +++ /dev/null @@ -1,81 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -var React = require('react'); - -var sdk = require('matrix-react-sdk'); -var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); - -module.exports = React.createClass({ - displayName: 'PostRegistration', - - propTypes: { - onComplete: React.PropTypes.func.isRequired - }, - - getInitialState: function() { - return { - avatarUrl: null, - errorString: null, - busy: false - }; - }, - - componentWillMount: function() { - // There is some assymetry between ChangeDisplayName and ChangeAvatar, - // as ChangeDisplayName will auto-get the name but ChangeAvatar expects - // the URL to be passed to you (because it's also used for room avatars). - var cli = MatrixClientPeg.get(); - this.setState({busy: true}); - var self = this; - cli.getProfileInfo(cli.credentials.userId).done(function(result) { - self.setState({ - avatarUrl: MatrixClientPeg.get().mxcUrlToHttp(result.avatar_url), - busy: false - }); - }, function(error) { - self.setState({ - errorString: "Failed to fetch avatar URL", - busy: false - }); - }); - }, - - render: function() { - var ChangeDisplayName = sdk.getComponent('settings.ChangeDisplayName'); - var ChangeAvatar = sdk.getComponent('settings.ChangeAvatar'); - return ( -
-
-
- vector -
-
- Set a display name: - - Upload an avatar: - - - {this.state.errorString} -
-
-
- ); - } -}); diff --git a/src/components/structures/login/Registration.js b/src/components/structures/login/Registration.js deleted file mode 100644 index 0475dff9aa..0000000000 --- a/src/components/structures/login/Registration.js +++ /dev/null @@ -1,247 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -var React = require('react'); - -var sdk = require('matrix-react-sdk'); -var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); -var dis = require('matrix-react-sdk/lib/dispatcher'); -var ServerConfig = require("../../views/login/ServerConfig"); -var RegistrationForm = require("../../views/login/RegistrationForm"); -var CaptchaForm = require("matrix-react-sdk/lib/components/views/login/CaptchaForm"); -var Signup = require("matrix-react-sdk/lib/Signup"); -var MIN_PASSWORD_LENGTH = 6; - -module.exports = React.createClass({ - displayName: 'Registration', - - propTypes: { - onLoggedIn: React.PropTypes.func.isRequired, - clientSecret: React.PropTypes.string, - sessionId: React.PropTypes.string, - registrationUrl: React.PropTypes.string, - idSid: React.PropTypes.string, - hsUrl: React.PropTypes.string, - isUrl: React.PropTypes.string, - // registration shouldn't know or care how login is done. - onLoginClick: React.PropTypes.func.isRequired - }, - - getInitialState: function() { - return { - busy: false, - errorText: null, - enteredHomeserverUrl: this.props.hsUrl, - enteredIdentityServerUrl: this.props.isUrl - }; - }, - - componentWillMount: function() { - this.dispatcherRef = dis.register(this.onAction); - // attach this to the instance rather than this.state since it isn't UI - this.registerLogic = new Signup.Register( - this.props.hsUrl, this.props.isUrl - ); - this.registerLogic.setClientSecret(this.props.clientSecret); - this.registerLogic.setSessionId(this.props.sessionId); - this.registerLogic.setRegistrationUrl(this.props.registrationUrl); - this.registerLogic.setIdSid(this.props.idSid); - this.registerLogic.recheckState(); - }, - - componentWillUnmount: function() { - dis.unregister(this.dispatcherRef); - }, - - componentDidMount: function() { - // may have already done an HTTP hit (e.g. redirect from an email) so - // check for any pending response - var promise = this.registerLogic.getPromise(); - if (promise) { - this.onProcessingRegistration(promise); - } - }, - - onHsUrlChanged: function(newHsUrl) { - this.registerLogic.setHomeserverUrl(newHsUrl); - }, - - onIsUrlChanged: function(newIsUrl) { - this.registerLogic.setIdentityServerUrl(newIsUrl); - }, - - onAction: function(payload) { - if (payload.action !== "registration_step_update") { - return; - } - this.forceUpdate(); // registration state has changed. - }, - - onFormSubmit: function(formVals) { - var self = this; - this.setState({ - errorText: "", - busy: true - }); - this.onProcessingRegistration(this.registerLogic.register(formVals)); - }, - - // Promise is resolved when the registration process is FULLY COMPLETE - onProcessingRegistration: function(promise) { - var self = this; - promise.done(function(response) { - if (!response || !response.access_token) { - console.warn( - "FIXME: Register fulfilled without a final response, " + - "did you break the promise chain?" - ); - // no matter, we'll grab it direct - response = self.registerLogic.getCredentials(); - } - if (!response || !response.user_id || !response.access_token) { - console.error("Final response is missing keys."); - self.setState({ - errorText: "There was a problem processing the response." - }); - return; - } - self.props.onLoggedIn({ - userId: response.user_id, - homeserverUrl: self.registerLogic.getHomeserverUrl(), - identityServerUrl: self.registerLogic.getIdentityServerUrl(), - accessToken: response.access_token - }); - self.setState({ - busy: false - }); - }, function(err) { - if (err.message) { - self.setState({ - errorText: err.message - }); - } - self.setState({ - busy: false - }); - console.log(err); - }); - }, - - onFormValidationFailed: function(errCode) { - var errMsg; - switch (errCode) { - case "RegistrationForm.ERR_PASSWORD_MISSING": - errMsg = "Missing password."; - break; - case "RegistrationForm.ERR_PASSWORD_MISMATCH": - errMsg = "Passwords don't match."; - break; - case "RegistrationForm.ERR_PASSWORD_LENGTH": - errMsg = `Password too short (min ${MIN_PASSWORD_LENGTH}).`; - break; - default: - console.error("Unknown error code: %s", errCode); - errMsg = "An unknown error occurred."; - break; - } - this.setState({ - errorText: errMsg - }); - }, - - onCaptchaLoaded: function(divIdName) { - this.registerLogic.tellStage("m.login.recaptcha", { - divId: divIdName - }); - this.setState({ - busy: false // requires user input - }); - }, - - _getRegisterContentJsx: function() { - var currStep = this.registerLogic.getStep(); - var registerStep; - switch (currStep) { - case "Register.COMPLETE": - break; // NOP - case "Register.START": - case "Register.STEP_m.login.dummy": - registerStep = ( - - ); - break; - case "Register.STEP_m.login.email.identity": - registerStep = ( -
- Please check your email to continue registration. -
- ); - break; - case "Register.STEP_m.login.recaptcha": - registerStep = ( - - ); - break; - default: - console.error("Unknown register state: %s", currStep); - break; - } - var busySpinner; - if (this.state.busy) { - var Spinner = sdk.getComponent("elements.Spinner"); - busySpinner = ( - - ); - } - return ( -
-

Create an account

- {registerStep} -
{this.state.errorText}
- {busySpinner} - - - I already have an account - -
- ); - }, - - render: function() { - return ( -
-
-
- vector -
- {this._getRegisterContentJsx()} -
-
- ); - } -}); diff --git a/src/components/views/elements/ImageView.js b/src/components/views/elements/ImageView.js index f068c74e5b..2025cec291 100644 --- a/src/components/views/elements/ImageView.js +++ b/src/components/views/elements/ImageView.js @@ -20,7 +20,7 @@ var React = require('react'); var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); -var DateUtils = require('../../../DateUtils'); +var DateUtils = require('matrix-react-sdk/lib/DateUtils'); var filesize = require('filesize'); module.exports = React.createClass({ @@ -55,7 +55,7 @@ module.exports = React.createClass({ ).done(function() { if (self.props.onFinished) self.props.onFinished(); }, function(e) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); // display error message stating you couldn't delete this. var code = e.errcode || e.statusCode; Modal.createDialog(ErrorDialog, { diff --git a/src/components/views/login/RegistrationForm.js b/src/components/views/login/RegistrationForm.js deleted file mode 100644 index 3f9fb6ae12..0000000000 --- a/src/components/views/login/RegistrationForm.js +++ /dev/null @@ -1,126 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -var React = require('react'); -var sdk = require('matrix-react-sdk') - -/** - * A pure UI component which displays a registration form. - */ -module.exports = React.createClass({ - displayName: 'RegistrationForm', - - propTypes: { - defaultEmail: React.PropTypes.string, - defaultUsername: React.PropTypes.string, - showEmail: React.PropTypes.bool, - minPasswordLength: React.PropTypes.number, - onError: React.PropTypes.func, - onRegisterClick: React.PropTypes.func // onRegisterClick(Object) => ?Promise - }, - - getDefaultProps: function() { - return { - showEmail: false, - minPasswordLength: 6, - onError: function(e) { - console.error(e); - } - }; - }, - - getInitialState: function() { - return { - email: this.props.defaultEmail, - username: this.props.defaultUsername, - password: null, - passwordConfirm: null - }; - }, - - onSubmit: function(ev) { - ev.preventDefault(); - - var pwd1 = this.refs.password.value.trim(); - var pwd2 = this.refs.passwordConfirm.value.trim() - - var errCode; - if (!pwd1 || !pwd2) { - errCode = "RegistrationForm.ERR_PASSWORD_MISSING"; - } - else if (pwd1 !== pwd2) { - errCode = "RegistrationForm.ERR_PASSWORD_MISMATCH"; - } - else if (pwd1.length < this.props.minPasswordLength) { - errCode = "RegistrationForm.ERR_PASSWORD_LENGTH"; - } - if (errCode) { - this.props.onError(errCode); - return; - } - - var promise = this.props.onRegisterClick({ - username: this.refs.username.value.trim(), - password: pwd1, - email: this.refs.email.value.trim() - }); - - if (promise) { - ev.target.disabled = true; - promise.finally(function() { - ev.target.disabled = false; - }); - } - }, - - render: function() { - var emailSection, registerButton; - if (this.props.showEmail) { - emailSection = ( - - ); - } - if (this.props.onRegisterClick) { - registerButton = ( - - ); - } - - return ( -
-
- {emailSection} -
- -
- -
- -
- {registerButton} -
-
- ); - } -}); diff --git a/src/components/views/login/ServerConfig.js b/src/components/views/login/ServerConfig.js deleted file mode 100644 index 8f1eab3846..0000000000 --- a/src/components/views/login/ServerConfig.js +++ /dev/null @@ -1,161 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -var React = require('react'); -var Modal = require('matrix-react-sdk/lib/Modal'); -var sdk = require('matrix-react-sdk') - -/** - * A pure UI component which displays the HS and IS to use. - */ -module.exports = React.createClass({ - displayName: 'ServerConfig', - - propTypes: { - onHsUrlChanged: React.PropTypes.func, - onIsUrlChanged: React.PropTypes.func, - defaultHsUrl: React.PropTypes.string, - defaultIsUrl: React.PropTypes.string, - withToggleButton: React.PropTypes.bool, - delayTimeMs: React.PropTypes.number // time to wait before invoking onChanged - }, - - getDefaultProps: function() { - return { - onHsUrlChanged: function() {}, - onIsUrlChanged: function() {}, - withToggleButton: false, - delayTimeMs: 0 - }; - }, - - getInitialState: function() { - return { - hs_url: this.props.defaultHsUrl, - is_url: this.props.defaultIsUrl, - original_hs_url: this.props.defaultHsUrl, - original_is_url: this.props.defaultIsUrl, - // no toggle button = show, toggle button = hide - configVisible: !this.props.withToggleButton - } - }, - - onHomeserverChanged: function(ev) { - this.setState({hs_url: ev.target.value}, function() { - this._hsTimeoutId = this._waitThenInvoke(this._hsTimeoutId, function() { - this.props.onHsUrlChanged(this.state.hs_url); - }); - }); - }, - - onIdentityServerChanged: function(ev) { - this.setState({is_url: ev.target.value}, function() { - this._isTimeoutId = this._waitThenInvoke(this._isTimeoutId, function() { - this.props.onIsUrlChanged(this.state.is_url); - }); - }); - }, - - _waitThenInvoke: function(existingTimeoutId, fn) { - if (existingTimeoutId) { - clearTimeout(existingTimeoutId); - } - return setTimeout(fn.bind(this), this.props.delayTimeMs); - }, - - getHsUrl: function() { - return this.state.hs_url; - }, - - getIsUrl: function() { - return this.state.is_url; - }, - - onServerConfigVisibleChange: function(ev) { - this.setState({ - configVisible: ev.target.checked - }); - }, - - showHelpPopup: function() { - var ErrorDialog = sdk.getComponent('organisms.ErrorDialog'); - Modal.createDialog(ErrorDialog, { - title: 'Custom Server Options', - description: - You can use the custom server options to log into other Matrix - servers by specifying a different Home server URL. -
- This allows you to use Vector with an existing Matrix account on - a different Home server. -
-
- You can also set a custom Identity server but this will affect - people's ability to find you if you use a server in a group other - than the main Matrix.org group. -
, - button: "Dismiss", - focus: true - }); - }, - - render: function() { - var serverConfigStyle = {}; - serverConfigStyle.display = this.state.configVisible ? 'block' : 'none'; - - var toggleButton; - if (this.props.withToggleButton) { - toggleButton = ( -
- - -
- ); - } - - return ( -
- {toggleButton} -
-
- - - - - - What does this mean? - -
-
-
- ); - } -}); diff --git a/src/components/views/messages/MessageTimestamp.js b/src/components/views/messages/MessageTimestamp.js index a7289ca5b8..b4b7546e50 100644 --- a/src/components/views/messages/MessageTimestamp.js +++ b/src/components/views/messages/MessageTimestamp.js @@ -17,7 +17,7 @@ limitations under the License. 'use strict'; var React = require('react'); -var DateUtils = require('../../../DateUtils'); +var DateUtils = require('matrix-react-sdk/lib/DateUtils'); module.exports = React.createClass({ displayName: 'MessageTimestamp', diff --git a/src/components/views/rooms/RoomDNDView.js b/src/components/views/rooms/RoomDNDView.js index f096723f7f..0bae6e70b5 100644 --- a/src/components/views/rooms/RoomDNDView.js +++ b/src/components/views/rooms/RoomDNDView.js @@ -77,7 +77,7 @@ var roomTileSource = { MatrixClientPeg.get().deleteRoomTag(item.room.roomId, item.originalList.props.tagName).finally(function() { //component.state.set({ spinner: component.state.spinner-- }); }).fail(function(err) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { title: "Failed to remove tag " + item.originalList.props.tagName + " from room", description: err.toString() @@ -96,7 +96,7 @@ var roomTileSource = { MatrixClientPeg.get().setRoomTag(item.room.roomId, item.targetList.props.tagName, newOrder).finally(function() { //component.state.set({ spinner: component.state.spinner-- }); }).fail(function(err) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { title: "Failed to add tag " + item.targetList.props.tagName + " to room", description: err.toString() diff --git a/src/controllers/organisms/RoomList.js b/src/controllers/organisms/RoomList.js deleted file mode 100644 index 2a01527e78..0000000000 --- a/src/controllers/organisms/RoomList.js +++ /dev/null @@ -1,210 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -var React = require("react"); -var ReactDOM = require("react-dom"); - -var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg"); -var RoomListSorter = require("matrix-react-sdk/lib/RoomListSorter"); -var dis = require("matrix-react-sdk/lib/dispatcher"); - -var sdk = require('matrix-react-sdk'); -var VectorConferenceHandler = require("../../modules/VectorConferenceHandler"); - -var HIDE_CONFERENCE_CHANS = true; - -module.exports = { - getInitialState: function() { - return { - activityMap: null, - lists: {}, - } - }, - - componentWillMount: function() { - var cli = MatrixClientPeg.get(); - cli.on("Room", this.onRoom); - cli.on("Room.timeline", this.onRoomTimeline); - cli.on("Room.name", this.onRoomName); - cli.on("Room.tags", this.onRoomTags); - cli.on("RoomState.events", this.onRoomStateEvents); - cli.on("RoomMember.name", this.onRoomMemberName); - - var s = this.getRoomLists(); - s.activityMap = {}; - this.setState(s); - }, - - componentDidMount: function() { - this.dispatcherRef = dis.register(this.onAction); - }, - - onAction: function(payload) { - switch (payload.action) { - case 'view_tooltip': - this.tooltip = payload.tooltip; - this._repositionTooltip(); - if (this.tooltip) this.tooltip.style.display = 'block'; - break - } - }, - - componentWillUnmount: function() { - dis.unregister(this.dispatcherRef); - if (MatrixClientPeg.get()) { - MatrixClientPeg.get().removeListener("Room", this.onRoom); - MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline); - MatrixClientPeg.get().removeListener("Room.name", this.onRoomName); - MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents); - } - }, - - componentWillReceiveProps: function(newProps) { - this.state.activityMap[newProps.selectedRoom] = undefined; - this.setState({ - activityMap: this.state.activityMap - }); - }, - - onRoom: function(room) { - this.refreshRoomList(); - }, - - onRoomTimeline: function(ev, room, toStartOfTimeline) { - if (toStartOfTimeline) return; - - var hl = 0; - if ( - room.roomId != this.props.selectedRoom && - ev.getSender() != MatrixClientPeg.get().credentials.userId) - { - // don't mark rooms as unread for just member changes - if (ev.getType() != "m.room.member") { - hl = 1; - } - - var actions = MatrixClientPeg.get().getPushActionsForEvent(ev); - if (actions && actions.tweaks && actions.tweaks.highlight) { - hl = 2; - } - } - - if (hl > 0) { - var newState = this.getRoomLists(); - - // obviously this won't deep copy but this shouldn't be necessary - var amap = this.state.activityMap; - amap[room.roomId] = Math.max(amap[room.roomId] || 0, hl); - - newState.activityMap = amap; - - this.setState(newState); - } - }, - - onRoomName: function(room) { - this.refreshRoomList(); - }, - - onRoomTags: function(event, room) { - this.refreshRoomList(); - }, - - onRoomStateEvents: function(ev, state) { - setTimeout(this.refreshRoomList, 0); - }, - - onRoomMemberName: function(ev, member) { - setTimeout(this.refreshRoomList, 0); - }, - - refreshRoomList: function() { - // TODO: rather than bluntly regenerating and re-sorting everything - // every time we see any kind of room change from the JS SDK - // we could do incremental updates on our copy of the state - // based on the room which has actually changed. This would stop - // us re-rendering all the sublists every time anything changes anywhere - // in the state of the client. - this.setState(this.getRoomLists()); - }, - - getRoomLists: function() { - var s = { lists: {} }; - - s.lists["m.invite"] = []; - s.lists["m.favourite"] = []; - s.lists["m.recent"] = []; - s.lists["m.lowpriority"] = []; - s.lists["m.archived"] = []; - - MatrixClientPeg.get().getRooms().forEach(function(room) { - var me = room.getMember(MatrixClientPeg.get().credentials.userId); - - if (me && me.membership == "invite") { - s.lists["m.invite"].push(room); - } - else { - var shouldShowRoom = ( - me && (me.membership == "join") - ); - - // hiding conf rooms only ever toggles shouldShowRoom to false - if (shouldShowRoom && HIDE_CONFERENCE_CHANS) { - // we want to hide the 1:1 conf<->user room and not the group chat - var joinedMembers = room.getJoinedMembers(); - if (joinedMembers.length === 2) { - var otherMember = joinedMembers.filter(function(m) { - return m.userId !== me.userId - })[0]; - if (VectorConferenceHandler.isConferenceUser(otherMember)) { - // console.log("Hiding conference 1:1 room %s", room.roomId); - shouldShowRoom = false; - } - } - } - - if (shouldShowRoom) { - var tagNames = Object.keys(room.tags); - if (tagNames.length) { - for (var i = 0; i < tagNames.length; i++) { - var tagName = tagNames[i]; - s.lists[tagName] = s.lists[tagName] || []; - s.lists[tagNames[i]].push(room); - } - } - else { - s.lists["m.recent"].push(room); - } - } - } - }); - - //console.log("calculated new roomLists; m.recent = " + s.lists["m.recent"]); - - // we actually apply the sorting to this when receiving the prop in RoomSubLists. - - return s; - }, - - _repositionTooltip: function(e) { - if (this.tooltip && this.tooltip.parentElement) { - var scroll = ReactDOM.findDOMNode(this); - this.tooltip.style.top = (scroll.parentElement.offsetTop + this.tooltip.parentElement.offsetTop - scroll.children[2].scrollTop) + "px"; - } - }, -}; diff --git a/src/controllers/organisms/RoomView.js b/src/controllers/organisms/RoomView.js deleted file mode 100644 index b091a872e8..0000000000 --- a/src/controllers/organisms/RoomView.js +++ /dev/null @@ -1,738 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -var Matrix = require("matrix-js-sdk"); -var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg"); -var React = require("react"); -var ReactDOM = require("react-dom"); -var q = require("q"); -var ContentMessages = require("matrix-react-sdk/lib//ContentMessages"); -var WhoIsTyping = require("matrix-react-sdk/lib/WhoIsTyping"); -var Modal = require("matrix-react-sdk/lib/Modal"); -var sdk = require('matrix-react-sdk/lib/index'); -var CallHandler = require('matrix-react-sdk/lib/CallHandler'); -var VectorConferenceHandler = require('../../modules/VectorConferenceHandler'); -var Resend = require("../../Resend"); - -var dis = require("matrix-react-sdk/lib/dispatcher"); - -var PAGINATE_SIZE = 20; -var INITIAL_SIZE = 20; - -module.exports = { - getInitialState: function() { - var room = this.props.roomId ? MatrixClientPeg.get().getRoom(this.props.roomId) : null; - return { - room: room, - messageCap: INITIAL_SIZE, - editingRoomSettings: false, - uploadingRoomSettings: false, - numUnreadMessages: 0, - draggingFile: false, - searching: false, - searchResults: null, - syncState: MatrixClientPeg.get().getSyncState(), - hasUnsentMessages: this._hasUnsentMessages(room) - } - }, - - componentWillMount: function() { - this.dispatcherRef = dis.register(this.onAction); - MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline); - MatrixClientPeg.get().on("Room.name", this.onRoomName); - MatrixClientPeg.get().on("Room.receipt", this.onRoomReceipt); - MatrixClientPeg.get().on("RoomMember.typing", this.onRoomMemberTyping); - MatrixClientPeg.get().on("RoomState.members", this.onRoomStateMember); - MatrixClientPeg.get().on("sync", this.onSyncStateChange); - this.atBottom = true; - }, - - componentWillUnmount: function() { - if (this.refs.messagePanel) { - var messagePanel = ReactDOM.findDOMNode(this.refs.messagePanel); - messagePanel.removeEventListener('drop', this.onDrop); - messagePanel.removeEventListener('dragover', this.onDragOver); - messagePanel.removeEventListener('dragleave', this.onDragLeaveOrEnd); - messagePanel.removeEventListener('dragend', this.onDragLeaveOrEnd); - } - dis.unregister(this.dispatcherRef); - if (MatrixClientPeg.get()) { - MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline); - MatrixClientPeg.get().removeListener("Room.name", this.onRoomName); - MatrixClientPeg.get().removeListener("Room.receipt", this.onRoomReceipt); - MatrixClientPeg.get().removeListener("RoomMember.typing", this.onRoomMemberTyping); - MatrixClientPeg.get().removeListener("RoomState.members", this.onRoomStateMember); - MatrixClientPeg.get().removeListener("sync", this.onSyncStateChange); - } - }, - - onAction: function(payload) { - switch (payload.action) { - case 'message_send_failed': - case 'message_sent': - this.setState({ - hasUnsentMessages: this._hasUnsentMessages(this.state.room) - }); - case 'message_resend_started': - this.setState({ - room: MatrixClientPeg.get().getRoom(this.props.roomId) - }); - this.forceUpdate(); - break; - case 'notifier_enabled': - this.forceUpdate(); - break; - case 'call_state': - if (CallHandler.getCallForRoom(this.props.roomId)) { - // Call state has changed so we may be loading video elements - // which will obscure the message log. - // scroll to bottom - var scrollNode = this._getScrollNode(); - if (scrollNode) { - scrollNode.scrollTop = scrollNode.scrollHeight; - } - } - - // possibly remove the conf call notification if we're now in - // the conf - this._updateConfCallNotification(); - break; - case 'user_activity': - this.sendReadReceipt(); - break; - } - }, - - _getScrollNode: function() { - var panel = ReactDOM.findDOMNode(this.refs.messagePanel); - if (!panel) return null; - - if (panel.classList.contains('gm-prevented')) { - return panel; - } else { - return panel.children[2]; // XXX: Fragile! - } - }, - - onSyncStateChange: function(state) { - this.setState({ - syncState: state - }); - }, - - // MatrixRoom still showing the messages from the old room? - // Set the key to the room_id. Sadly you can no longer get at - // the key from inside the component, or we'd check this in code. - /*componentWillReceiveProps: function(props) { - },*/ - - onRoomTimeline: function(ev, room, toStartOfTimeline) { - if (!this.isMounted()) return; - - // ignore anything that comes in whilst paginating: we get one - // event for each new matrix event so this would cause a huge - // number of UI updates. Just update the UI when the paginate - // call returns. - if (this.state.paginating) return; - - // no point handling anything while we're waiting for the join to finish: - // we'll only be showing a spinner. - if (this.state.joining) return; - if (room.roomId != this.props.roomId) return; - - var scrollNode = this._getScrollNode(); - if (scrollNode) { - this.atBottom = ( - scrollNode.scrollHeight - scrollNode.scrollTop <= - (scrollNode.clientHeight + 150) // 150? - ); - } - - var currentUnread = this.state.numUnreadMessages; - if (!toStartOfTimeline && - (ev.getSender() !== MatrixClientPeg.get().credentials.userId)) { - // update unread count when scrolled up - if (this.atBottom) { - currentUnread = 0; - } - else { - currentUnread += 1; - } - } - - - this.setState({ - room: MatrixClientPeg.get().getRoom(this.props.roomId), - numUnreadMessages: currentUnread - }); - - if (toStartOfTimeline && !this.state.paginating) { - this.fillSpace(); - } - }, - - onRoomName: function(room) { - if (room.roomId == this.props.roomId) { - this.setState({ - room: room - }); - } - }, - - onRoomReceipt: function(receiptEvent, room) { - if (room.roomId == this.props.roomId) { - this.forceUpdate(); - } - }, - - onRoomMemberTyping: function(ev, member) { - this.forceUpdate(); - }, - - onRoomStateMember: function(ev, state, member) { - if (member.roomId !== this.props.roomId || - member.userId !== VectorConferenceHandler.getConferenceUserIdForRoom(member.roomId)) { - return; - } - this._updateConfCallNotification(); - }, - - _hasUnsentMessages: function(room) { - return this._getUnsentMessages(room).length > 0; - }, - - _getUnsentMessages: function(room) { - if (!room) { return []; } - // TODO: It would be nice if the JS SDK provided nicer constant-time - // constructs rather than O(N) (N=num msgs) on this. - return room.timeline.filter(function(ev) { - return ev.status === Matrix.EventStatus.NOT_SENT; - }); - }, - - _updateConfCallNotification: function() { - var room = MatrixClientPeg.get().getRoom(this.props.roomId); - if (!room) return; - var confMember = room.getMember( - VectorConferenceHandler.getConferenceUserIdForRoom(this.props.roomId) - ); - - if (!confMember) { - return; - } - var confCall = VectorConferenceHandler.getConferenceCallForRoom(confMember.roomId); - - // A conf call notification should be displayed if there is an ongoing - // conf call but this cilent isn't a part of it. - this.setState({ - displayConfCallNotification: ( - (!confCall || confCall.call_state === "ended") && - confMember.membership === "join" - ) - }); - }, - - componentDidMount: function() { - if (this.refs.messagePanel) { - var messagePanel = ReactDOM.findDOMNode(this.refs.messagePanel); - - messagePanel.addEventListener('drop', this.onDrop); - messagePanel.addEventListener('dragover', this.onDragOver); - messagePanel.addEventListener('dragleave', this.onDragLeaveOrEnd); - messagePanel.addEventListener('dragend', this.onDragLeaveOrEnd); - - var messageWrapperScroll = this._getScrollNode(); - - messageWrapperScroll.scrollTop = messageWrapperScroll.scrollHeight; - - this.sendReadReceipt(); - - this.fillSpace(); - } - - this._updateConfCallNotification(); - }, - - componentDidUpdate: function() { - if (!this.refs.messagePanel) return; - - var messageWrapperScroll = this._getScrollNode(); - - if (this.state.paginating && !this.waiting_for_paginate) { - var heightGained = messageWrapperScroll.scrollHeight - this.oldScrollHeight; - messageWrapperScroll.scrollTop += heightGained; - this.oldScrollHeight = undefined; - if (!this.fillSpace()) { - this.setState({paginating: false}); - } - } else if (this.atBottom) { - messageWrapperScroll.scrollTop = messageWrapperScroll.scrollHeight; - if (this.state.numUnreadMessages !== 0) { - this.setState({numUnreadMessages: 0}); - } - } - }, - - fillSpace: function() { - if (!this.refs.messagePanel) return; - if (this.state.searchResults) return; // TODO: paginate search results - var messageWrapperScroll = this._getScrollNode(); - if (messageWrapperScroll.scrollTop < messageWrapperScroll.clientHeight && this.state.room.oldState.paginationToken) { - this.setState({paginating: true}); - - this.oldScrollHeight = messageWrapperScroll.scrollHeight; - - if (this.state.messageCap < this.state.room.timeline.length) { - this.waiting_for_paginate = false; - var cap = Math.min(this.state.messageCap + PAGINATE_SIZE, this.state.room.timeline.length); - this.setState({messageCap: cap, paginating: true}); - } else { - this.waiting_for_paginate = true; - var cap = this.state.messageCap + PAGINATE_SIZE; - this.setState({messageCap: cap, paginating: true}); - var self = this; - MatrixClientPeg.get().scrollback(this.state.room, PAGINATE_SIZE).finally(function() { - self.waiting_for_paginate = false; - if (self.isMounted()) { - self.setState({ - room: MatrixClientPeg.get().getRoom(self.props.roomId) - }); - } - // wait and set paginating to false when the component updates - }); - } - - return true; - } - return false; - }, - - onResendAllClick: function() { - var eventsToResend = this._getUnsentMessages(this.state.room); - eventsToResend.forEach(function(event) { - Resend.resend(event); - }); - }, - - onJoinButtonClicked: function(ev) { - var self = this; - MatrixClientPeg.get().joinRoom(this.props.roomId).then(function() { - self.setState({ - joining: false, - room: MatrixClientPeg.get().getRoom(self.props.roomId) - }); - }, function(error) { - self.setState({ - joining: false, - joinError: error - }); - }); - this.setState({ - joining: true - }); - }, - - onMessageListScroll: function(ev) { - if (this.refs.messagePanel) { - var messageWrapperScroll = this._getScrollNode(); - var wasAtBottom = this.atBottom; - this.atBottom = messageWrapperScroll.scrollHeight - messageWrapperScroll.scrollTop <= messageWrapperScroll.clientHeight + 1; - if (this.atBottom && !wasAtBottom) { - this.forceUpdate(); // remove unread msg count - } - } - if (!this.state.paginating) this.fillSpace(); - }, - - onDragOver: function(ev) { - ev.stopPropagation(); - ev.preventDefault(); - - ev.dataTransfer.dropEffect = 'none'; - - var items = ev.dataTransfer.items; - if (items.length == 1) { - if (items[0].kind == 'file') { - this.setState({ draggingFile : true }); - ev.dataTransfer.dropEffect = 'copy'; - } - } - }, - - onDrop: function(ev) { - ev.stopPropagation(); - ev.preventDefault(); - this.setState({ draggingFile : false }); - var files = ev.dataTransfer.files; - if (files.length == 1) { - this.uploadFile(files[0]); - } - }, - - onDragLeaveOrEnd: function(ev) { - ev.stopPropagation(); - ev.preventDefault(); - this.setState({ draggingFile : false }); - }, - - uploadFile: function(file) { - this.setState({ - upload: { - fileName: file.name, - uploadedBytes: 0, - totalBytes: file.size - } - }); - var self = this; - ContentMessages.sendContentToRoom( - file, this.props.roomId, MatrixClientPeg.get() - ).progress(function(ev) { - //console.log("Upload: "+ev.loaded+" / "+ev.total); - self.setState({ - upload: { - fileName: file.name, - uploadedBytes: ev.loaded, - totalBytes: ev.total - } - }); - }).finally(function() { - self.setState({ - upload: undefined - }); - }).done(undefined, function(error) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); - Modal.createDialog(ErrorDialog, { - title: "Failed to upload file", - description: error.toString() - }); - }); - }, - - getWhoIsTypingString: function() { - return WhoIsTyping.whoIsTypingString(this.state.room); - }, - - onSearch: function(term, scope) { - var filter; - if (scope === "Room") { - filter = { - // XXX: it's unintuitive that the filter for searching doesn't have the same shape as the v2 filter API :( - rooms: [ - this.props.roomId - ] - }; - } - - var self = this; - MatrixClientPeg.get().search({ - body: { - search_categories: { - room_events: { - search_term: term, - filter: filter, - order_by: "recent", - include_state: true, - groupings: { - group_by: [ - { - key: "room_id" - } - ] - }, - event_context: { - before_limit: 1, - after_limit: 1, - include_profile: true, - } - } - } - } - }).then(function(data) { - // for debugging: - // data.search_categories.room_events.highlights = ["hello", "everybody"]; - - var highlights; - if (data.search_categories.room_events.highlights && - data.search_categories.room_events.highlights.length > 0) - { - // postgres on synapse returns us precise details of the - // strings which actually got matched for highlighting. - // for overlapping highlights, favour longer (more specific) terms first - highlights = data.search_categories.room_events.highlights - .sort(function(a, b) { b.length - a.length }); - } - else { - // sqlite doesn't, so just try to highlight the literal search term - highlights = [ term ]; - } - - self.setState({ - highlights: highlights, - searchResults: data, - searchScope: scope, - }); - }, function(error) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); - Modal.createDialog(ErrorDialog, { - title: "Search failed", - description: error.toString() - }); - }); - }, - - getEventTiles: function() { - var DateSeparator = sdk.getComponent('molecules.DateSeparator'); - var cli = MatrixClientPeg.get(); - - var ret = []; - var count = 0; - - var EventTile = sdk.getComponent('rooms.EventTile'); - var self = this; - - if (this.state.searchResults && - this.state.searchResults.search_categories.room_events.results && - this.state.searchResults.search_categories.room_events.groups) - { - // XXX: this dance is foul, due to the results API not directly returning sorted results - var results = this.state.searchResults.search_categories.room_events.results; - var roomIdGroups = this.state.searchResults.search_categories.room_events.groups.room_id; - - Object.keys(roomIdGroups) - .sort(function(a, b) { roomIdGroups[a].order - roomIdGroups[b].order }) // WHY NOT RETURN AN ORDERED ARRAY?!?!?! - .forEach(function(roomId) - { - // XXX: todo: merge overlapping results somehow? - // XXX: why doesn't searching on name work? - if (self.state.searchScope === 'All') { - ret.push(
  • Room: { cli.getRoom(roomId).name }

  • ); - } - - var resultList = roomIdGroups[roomId].results.map(function(eventId) { return results[eventId]; }); - for (var i = resultList.length - 1; i >= 0; i--) { - var ts1 = resultList[i].result.origin_server_ts; - ret.push(
  • ); // Rank: {resultList[i].rank} - var mxEv = new Matrix.MatrixEvent(resultList[i].result); - if (resultList[i].context.events_before[0]) { - var mxEv2 = new Matrix.MatrixEvent(resultList[i].context.events_before[0]); - if (EventTile.haveTileForEvent(mxEv2)) { - ret.push(
  • ); - } - } - if (EventTile.haveTileForEvent(mxEv)) { - ret.push(
  • ); - } - if (resultList[i].context.events_after[0]) { - var mxEv2 = new Matrix.MatrixEvent(resultList[i].context.events_after[0]); - if (EventTile.haveTileForEvent(mxEv2)) { - ret.push(
  • ); - } - } - } - }); - return ret; - } - - for (var i = this.state.room.timeline.length-1; i >= 0 && count < this.state.messageCap; --i) { - var mxEv = this.state.room.timeline[i]; - - if (!EventTile.haveTileForEvent(mxEv)) { - continue; - } - - var continuation = false; - var last = false; - var dateSeparator = null; - if (i == this.state.room.timeline.length - 1) { - last = true; - } - if (i > 0 && count < this.state.messageCap - 1) { - if (this.state.room.timeline[i].sender && - this.state.room.timeline[i - 1].sender && - (this.state.room.timeline[i].sender.userId === - this.state.room.timeline[i - 1].sender.userId) && - (this.state.room.timeline[i].getType() == - this.state.room.timeline[i - 1].getType()) - ) - { - continuation = true; - } - - var ts0 = this.state.room.timeline[i - 1].getTs(); - var ts1 = this.state.room.timeline[i].getTs(); - if (new Date(ts0).toDateString() !== new Date(ts1).toDateString()) { - dateSeparator =
  • ; - continuation = false; - } - } - - if (i === 1) { // n.b. 1, not 0, as the 0th event is an m.room.create and so doesn't show on the timeline - var ts1 = this.state.room.timeline[i].getTs(); - dateSeparator =
  • ; - continuation = false; - } - - ret.unshift( -
  • - ); - if (dateSeparator) { - ret.unshift(dateSeparator); - } - ++count; - } - return ret; - }, - - uploadNewState: function(new_name, new_topic, new_join_rule, new_history_visibility, new_power_levels) { - var old_name = this.state.room.name; - - var old_topic = this.state.room.currentState.getStateEvents('m.room.topic', ''); - if (old_topic) { - old_topic = old_topic.getContent().topic; - } else { - old_topic = ""; - } - - var old_join_rule = this.state.room.currentState.getStateEvents('m.room.join_rules', ''); - if (old_join_rule) { - old_join_rule = old_join_rule.getContent().join_rule; - } else { - old_join_rule = "invite"; - } - - var old_history_visibility = this.state.room.currentState.getStateEvents('m.room.history_visibility', ''); - if (old_history_visibility) { - old_history_visibility = old_history_visibility.getContent().history_visibility; - } else { - old_history_visibility = "shared"; - } - - var deferreds = []; - - if (old_name != new_name && new_name != undefined && new_name) { - deferreds.push( - MatrixClientPeg.get().setRoomName(this.state.room.roomId, new_name) - ); - } - - if (old_topic != new_topic && new_topic != undefined) { - deferreds.push( - MatrixClientPeg.get().setRoomTopic(this.state.room.roomId, new_topic) - ); - } - - if (old_join_rule != new_join_rule && new_join_rule != undefined) { - deferreds.push( - MatrixClientPeg.get().sendStateEvent( - this.state.room.roomId, "m.room.join_rules", { - join_rule: new_join_rule, - }, "" - ) - ); - } - - if (old_history_visibility != new_history_visibility && new_history_visibility != undefined) { - deferreds.push( - MatrixClientPeg.get().sendStateEvent( - this.state.room.roomId, "m.room.history_visibility", { - history_visibility: new_history_visibility, - }, "" - ) - ); - } - - if (new_power_levels) { - deferreds.push( - MatrixClientPeg.get().sendStateEvent( - this.state.room.roomId, "m.room.power_levels", new_power_levels, "" - ) - ); - } - - if (deferreds.length) { - var self = this; - q.all(deferreds).fail(function(err) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); - Modal.createDialog(ErrorDialog, { - title: "Failed to set state", - description: err.toString() - }); - }).finally(function() { - self.setState({ - uploadingRoomSettings: false, - }); - }); - } else { - this.setState({ - editingRoomSettings: false, - uploadingRoomSettings: false, - }); - } - }, - - _collectEventNode: function(eventId, node) { - if (this.eventNodes == undefined) this.eventNodes = {}; - this.eventNodes[eventId] = node; - }, - - _indexForEventId(evId) { - for (var i = 0; i < this.state.room.timeline.length; ++i) { - if (evId == this.state.room.timeline[i].getId()) { - return i; - } - } - return null; - }, - - sendReadReceipt: function() { - if (!this.state.room) return; - var currentReadUpToEventId = this.state.room.getEventReadUpTo(MatrixClientPeg.get().credentials.userId); - var currentReadUpToEventIndex = this._indexForEventId(currentReadUpToEventId); - - var lastReadEventIndex = this._getLastDisplayedEventIndexIgnoringOwn(); - if (lastReadEventIndex === null) return; - - if (lastReadEventIndex > currentReadUpToEventIndex) { - MatrixClientPeg.get().sendReadReceipt(this.state.room.timeline[lastReadEventIndex]); - } - }, - - _getLastDisplayedEventIndexIgnoringOwn: function() { - if (this.eventNodes === undefined) return null; - - var messageWrapper = this.refs.messagePanel; - if (messageWrapper === undefined) return null; - var wrapperRect = ReactDOM.findDOMNode(messageWrapper).getBoundingClientRect(); - - for (var i = this.state.room.timeline.length-1; i >= 0; --i) { - var ev = this.state.room.timeline[i]; - - if (ev.sender && ev.sender.userId == MatrixClientPeg.get().credentials.userId) { - continue; - } - - var node = this.eventNodes[ev.getId()]; - if (!node) continue; - - var boundingRect = node.getBoundingClientRect(); - - if (boundingRect.bottom < wrapperRect.bottom) { - return i; - } - } - return null; - } -}; diff --git a/src/skins/vector/skindex.js b/src/skins/vector/skindex.js index 3670c4f0dc..53e94ebc0f 100644 --- a/src/skins/vector/skindex.js +++ b/src/skins/vector/skindex.js @@ -29,6 +29,7 @@ skin['elements.ImageView'] = require('../../components/views/elements/ImageView' skin['messages.MessageTimestamp'] = require('../../components/views/messages/MessageTimestamp'); skin['rooms.RoomTile'] = require('../../components/views/rooms/RoomDNDView'); + // TODO: Fix this so matrix-react-sdk stuff is in react SDK skindex? skin['avatars.RoomAvatar'] = require('matrix-react-sdk/lib/components/views/avatars/RoomAvatar'); skin['avatars.MemberAvatar'] = require('matrix-react-sdk/lib/components/views/avatars/MemberAvatar'); @@ -54,8 +55,10 @@ skin['rooms.MemberInfo'] = require('matrix-react-sdk/lib/components/views/rooms/ skin['rooms.RoomHeader'] = require('matrix-react-sdk/lib/components/views/rooms/RoomHeader'); skin['rooms.RoomSettings'] = require('matrix-react-sdk/lib/components/views/rooms/RoomSettings'); skin['rooms.MemberTile'] = require('matrix-react-sdk/lib/components/views/rooms/MemberTile'); +skin['rooms.MemberList'] = require('matrix-react-sdk/lib/components/views/rooms/MemberList'); skin['rooms.MessageComposer'] = require('matrix-react-sdk/lib/components/views/rooms/MessageComposer'); skin['rooms.EventTile'] = require('matrix-react-sdk/lib/components/views/rooms/EventTile'); +skin['rooms.RoomList'] = require('matrix-react-sdk/lib/components/views/rooms/RoomList'); skin['create_room.CreateRoomButton'] = require('matrix-react-sdk/lib/components/views/create_room/CreateRoomButton'); skin['create_room.Presets'] = require('matrix-react-sdk/lib/components/views/create_room/Presets'); @@ -66,9 +69,16 @@ skin['voip.IncomingCallBox'] = require('matrix-react-sdk/lib/components/views/vo skin['voip.VideoView'] = require('matrix-react-sdk/lib/components/views/voip/VideoView'); skin['voip.VideoFeed'] = require('matrix-react-sdk/lib/components/views/voip/VideoFeed'); +skin['dialogs.QuestionDialog'] = require('matrix-react-sdk/lib/components/views/dialogs/QuestionDialog'); +skin['dialogs.ErrorDialog'] = require('matrix-react-sdk/lib/components/views/dialogs/ErrorDialog'); +skin['dialogs.LogoutPrompt'] = require('matrix-react-sdk/lib/components/views/dialogs/LogoutPrompt'); +skin['structures.CreateRoom'] = require('matrix-react-sdk/lib/components/structures/CreateRoom'); +skin['structures.UserSettings'] = require('matrix-react-sdk/lib/components/structures/UserSettings'); +skin['structures.RoomView'] = require('matrix-react-sdk/lib/components/structures/RoomView'); +skin['structures.MatrixChat'] = require('matrix-react-sdk/lib/components/structures/MatrixChat'); -// Old style stuff +// Old style stuff - this stuff only exists in VECTOR skin['molecules.BottomLeftMenu'] = require('./views/molecules/BottomLeftMenu'); skin['molecules.BottomLeftMenuTile'] = require('./views/molecules/BottomLeftMenuTile'); skin['molecules.DateSeparator'] = require('./views/molecules/DateSeparator'); @@ -79,21 +89,11 @@ skin['molecules.RoomDropTarget'] = require('./views/molecules/RoomDropTarget'); skin['molecules.RoomTooltip'] = require('./views/molecules/RoomTooltip'); skin['molecules.SearchBar'] = require('./views/molecules/SearchBar'); skin['molecules.SenderProfile'] = require('./views/molecules/SenderProfile'); -skin['organisms.CreateRoom'] = require('./views/organisms/CreateRoom'); -skin['organisms.ErrorDialog'] = require('./views/organisms/ErrorDialog'); skin['organisms.LeftPanel'] = require('./views/organisms/LeftPanel'); -skin['organisms.LogoutPrompt'] = require('./views/organisms/LogoutPrompt'); -skin['organisms.MemberList'] = require('./views/organisms/MemberList'); -skin['organisms.Notifier'] = require('./views/organisms/Notifier'); -skin['organisms.QuestionDialog'] = require('./views/organisms/QuestionDialog'); skin['organisms.RightPanel'] = require('./views/organisms/RightPanel'); skin['organisms.RoomDirectory'] = require('./views/organisms/RoomDirectory'); -skin['organisms.RoomList'] = require('./views/organisms/RoomList'); skin['organisms.RoomSubList'] = require('./views/organisms/RoomSubList'); -skin['organisms.RoomView'] = require('./views/organisms/RoomView'); -skin['organisms.UserSettings'] = require('./views/organisms/UserSettings'); skin['organisms.ViewSource'] = require('./views/organisms/ViewSource'); skin['pages.CompatibilityPage'] = require('./views/pages/CompatibilityPage'); -skin['pages.MatrixChat'] = require('./views/pages/MatrixChat'); module.exports = skin; diff --git a/src/skins/vector/views/molecules/MatrixToolbar.js b/src/skins/vector/views/molecules/MatrixToolbar.js index 5b613f563d..bf333540d2 100644 --- a/src/skins/vector/views/molecules/MatrixToolbar.js +++ b/src/skins/vector/views/molecules/MatrixToolbar.js @@ -17,19 +17,17 @@ limitations under the License. 'use strict'; var React = require('react'); - +var Notifier = require("matrix-react-sdk/lib/Notifier"); var sdk = require('matrix-react-sdk') module.exports = React.createClass({ displayName: 'MatrixToolbar', hideToolbar: function() { - var Notifier = sdk.getComponent('organisms.Notifier'); Notifier.setToolbarHidden(true); }, onClick: function() { - var Notifier = sdk.getComponent('organisms.Notifier'); Notifier.setEnabled(true); }, diff --git a/src/skins/vector/views/molecules/MessageContextMenu.js b/src/skins/vector/views/molecules/MessageContextMenu.js index b36d4ccbbf..2aeac39c4f 100644 --- a/src/skins/vector/views/molecules/MessageContextMenu.js +++ b/src/skins/vector/views/molecules/MessageContextMenu.js @@ -22,7 +22,7 @@ var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); var dis = require('matrix-react-sdk/lib/dispatcher'); var sdk = require('matrix-react-sdk') var Modal = require('matrix-react-sdk/lib/Modal'); -var Resend = require("../../../../Resend"); +var Resend = require("matrix-react-sdk/lib/Resend"); module.exports = React.createClass({ displayName: 'MessageContextMenu', @@ -46,7 +46,7 @@ module.exports = React.createClass({ ).done(function() { // message should disappear by itself }, function(e) { - var ErrorDialog = sdk.getComponent("organisms.ErrorDialog"); + var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); // display error message stating you couldn't delete this. var code = e.errcode || e.statusCode; Modal.createDialog(ErrorDialog, { diff --git a/src/skins/vector/views/organisms/CreateRoom.js b/src/skins/vector/views/organisms/CreateRoom.js deleted file mode 100644 index b40952bcc0..0000000000 --- a/src/skins/vector/views/organisms/CreateRoom.js +++ /dev/null @@ -1,173 +0,0 @@ -/* -Copyright 2015 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -'use strict'; - -var React = require('react'); - -var CreateRoomController = require('matrix-react-sdk/lib/controllers/organisms/CreateRoom') - -var sdk = require('matrix-react-sdk') - -var PresetValues = { - PrivateChat: "private_chat", - PublicChat: "public_chat", - Custom: "custom", -}; - -module.exports = React.createClass({ - displayName: 'CreateRoom', - mixins: [CreateRoomController], - - getPreset: function() { - return this.refs.presets.getPreset(); - }, - - getName: function() { - return this.refs.name_textbox.getName(); - }, - - getTopic: function() { - return this.refs.topic.getTopic(); - }, - - getAliasLocalpart: function() { - return this.refs.alias.getAliasLocalpart(); - }, - - getInvitedUsers: function() { - return this.refs.user_selector.getUserIds(); - }, - - onPresetChanged: function(preset) { - switch (preset) { - case PresetValues.PrivateChat: - this.setState({ - preset: preset, - is_private: true, - share_history: false, - }); - break; - case PresetValues.PublicChat: - this.setState({ - preset: preset, - is_private: false, - share_history: true, - }); - break; - case PresetValues.Custom: - this.setState({ - preset: preset, - }); - break; - } - }, - - onPrivateChanged: function(ev) { - this.setState({ - preset: PresetValues.Custom, - is_private: ev.target.checked, - }); - }, - - onShareHistoryChanged: function(ev) { - this.setState({ - preset: PresetValues.Custom, - share_history: ev.target.checked, - }); - }, - - onTopicChange: function(ev) { - this.setState({ - topic: ev.target.value, - }); - }, - - onNameChange: function(ev) { - this.setState({ - room_name: ev.target.value, - }); - }, - - onInviteChanged: function(invited_users) { - this.setState({ - invited_users: invited_users, - }); - }, - - onAliasChanged: function(alias) { - this.setState({ - alias: alias - }) - }, - - onEncryptChanged: function(ev) { - this.setState({ - encrypt: ev.target.checked, - }); - }, - - render: function() { - var curr_phase = this.state.phase; - if (curr_phase == this.phases.CREATING) { - var Loader = sdk.getComponent("elements.Spinner"); - return ( - - ); - } else { - var error_box = ""; - if (curr_phase == this.phases.ERROR) { - error_box = ( -
    - An error occured: {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 RoomHeader = sdk.getComponent("rooms.RoomHeader"); - - return ( -
    - -
    -
    -