Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #618 from matrix-org/rav/async_dialog
Browse files Browse the repository at this point in the history
Allow Modal to be used with async-loaded components
  • Loading branch information
richvdh authored Jan 19, 2017
2 parents 89fa47d + ac22803 commit ba2460a
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 6 deletions.
73 changes: 71 additions & 2 deletions src/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,53 @@ limitations under the License.

var React = require('react');
var ReactDOM = require('react-dom');
import sdk from './index';

/**
* Wrap an asynchronous loader function with a react component which shows a
* spinner until the real component loads.
*/
const AsyncWrapper = React.createClass({
propTypes: {
/** A function which takes a 'callback' argument which it will call
* with the real component once it loads.
*/
loader: React.PropTypes.func.isRequired,
},

getInitialState: function() {
return {
component: null,
}
},

componentWillMount: function() {
this._unmounted = false;
this.props.loader((e) => {
if (this._unmounted) {
return;
}
this.setState({component: e});
});
},

componentWillUnmount: function() {
this._unmounted = true;
},

render: function() {
const {loader, ...otherProps} = this.props;

if (this.state.component) {
const Component = this.state.component;
return <Component {...otherProps} />;
} else {
// show a spinner until the component is loaded.
const Spinner = sdk.getComponent("elements.Spinner");
return <Spinner />;
}
},
});

module.exports = {
DialogContainerId: "mx_Dialog_Container",
Expand All @@ -36,8 +83,30 @@ module.exports = {
},

createDialog: function (Element, props, className) {
var self = this;
return this.createDialogAsync((cb) => {cb(Element)}, props, className);
},

/**
* Open a modal view.
*
* This can be used to display a react component which is loaded as an asynchronous
* webpack component. To do this, set 'loader' as:
*
* (cb) => {
* require(['<module>'], cb);
* }
*
* @param {Function} loader a function which takes a 'callback' argument,
* which it should call with a React component which will be displayed as
* the modal view.
*
* @param {Object} props properties to pass to the displayed
* component. (We will also pass an 'onFinished' property.)
*
* @param {String} className CSS class to apply to the modal wrapper
*/
createDialogAsync: function (loader, props, className) {
var self = this;
// never call this via modal.close() from onFinished() otherwise it will loop
var closeDialog = function() {
if (props && props.onFinished) props.onFinished.apply(null, arguments);
Expand All @@ -49,7 +118,7 @@ module.exports = {
var dialog = (
<div className={"mx_Dialog_wrapper " + className}>
<div className="mx_Dialog">
<Element {...props} onFinished={closeDialog}/>
<AsyncWrapper loader={loader} {...props} onFinished={closeDialog}/>
</div>
<div className="mx_Dialog_background" onClick={ closeDialog.bind(this, false) }></div>
</div>
Expand Down
2 changes: 0 additions & 2 deletions src/component-index.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ import views$dialogs$ChatInviteDialog from './components/views/dialogs/ChatInvit
views$dialogs$ChatInviteDialog && (module.exports.components['views.dialogs.ChatInviteDialog'] = views$dialogs$ChatInviteDialog);
import views$dialogs$DeactivateAccountDialog from './components/views/dialogs/DeactivateAccountDialog';
views$dialogs$DeactivateAccountDialog && (module.exports.components['views.dialogs.DeactivateAccountDialog'] = views$dialogs$DeactivateAccountDialog);
import views$dialogs$EncryptedEventDialog from './components/views/dialogs/EncryptedEventDialog';
views$dialogs$EncryptedEventDialog && (module.exports.components['views.dialogs.EncryptedEventDialog'] = views$dialogs$EncryptedEventDialog);
import views$dialogs$ErrorDialog from './components/views/dialogs/ErrorDialog';
views$dialogs$ErrorDialog && (module.exports.components['views.dialogs.ErrorDialog'] = views$dialogs$ErrorDialog);
import views$dialogs$InteractiveAuthDialog from './components/views/dialogs/InteractiveAuthDialog';
Expand Down
5 changes: 3 additions & 2 deletions src/components/views/rooms/EventTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,10 +366,11 @@ module.exports = WithMatrixClient(React.createClass({
},

onCryptoClicked: function(e) {
var EncryptedEventDialog = sdk.getComponent("dialogs.EncryptedEventDialog");
var event = this.props.mxEvent;

Modal.createDialog(EncryptedEventDialog, {
Modal.createDialogAsync((cb) => {
require(['../../../async-components/views/dialogs/EncryptedEventDialog'], cb)
}, {
event: event,
});
},
Expand Down

0 comments on commit ba2460a

Please sign in to comment.