Allow Modal to be used with async-loaded components
Add Modal.createDialogAsync, which can be used to display asynchronously-loaded React components. Also make EncryptedEventDialog use it as a handy demonstration.
This commit is contained in:
parent
1d5112db5d
commit
ac22803ba0
4 changed files with 74 additions and 6 deletions
73
src/Modal.js
73
src/Modal.js
|
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue