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 React = require('react');
|
||||||
var ReactDOM = require('react-dom');
|
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 = {
|
module.exports = {
|
||||||
DialogContainerId: "mx_Dialog_Container",
|
DialogContainerId: "mx_Dialog_Container",
|
||||||
|
@ -36,8 +83,30 @@ module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
createDialog: function (Element, props, className) {
|
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
|
// never call this via modal.close() from onFinished() otherwise it will loop
|
||||||
var closeDialog = function() {
|
var closeDialog = function() {
|
||||||
if (props && props.onFinished) props.onFinished.apply(null, arguments);
|
if (props && props.onFinished) props.onFinished.apply(null, arguments);
|
||||||
|
@ -49,7 +118,7 @@ module.exports = {
|
||||||
var dialog = (
|
var dialog = (
|
||||||
<div className={"mx_Dialog_wrapper " + className}>
|
<div className={"mx_Dialog_wrapper " + className}>
|
||||||
<div className="mx_Dialog">
|
<div className="mx_Dialog">
|
||||||
<Element {...props} onFinished={closeDialog}/>
|
<AsyncWrapper loader={loader} {...props} onFinished={closeDialog}/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_Dialog_background" onClick={ closeDialog.bind(this, false) }></div>
|
<div className="mx_Dialog_background" onClick={ closeDialog.bind(this, false) }></div>
|
||||||
</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);
|
views$dialogs$ChatInviteDialog && (module.exports.components['views.dialogs.ChatInviteDialog'] = views$dialogs$ChatInviteDialog);
|
||||||
import views$dialogs$DeactivateAccountDialog from './components/views/dialogs/DeactivateAccountDialog';
|
import views$dialogs$DeactivateAccountDialog from './components/views/dialogs/DeactivateAccountDialog';
|
||||||
views$dialogs$DeactivateAccountDialog && (module.exports.components['views.dialogs.DeactivateAccountDialog'] = 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';
|
import views$dialogs$ErrorDialog from './components/views/dialogs/ErrorDialog';
|
||||||
views$dialogs$ErrorDialog && (module.exports.components['views.dialogs.ErrorDialog'] = views$dialogs$ErrorDialog);
|
views$dialogs$ErrorDialog && (module.exports.components['views.dialogs.ErrorDialog'] = views$dialogs$ErrorDialog);
|
||||||
import views$dialogs$InteractiveAuthDialog from './components/views/dialogs/InteractiveAuthDialog';
|
import views$dialogs$InteractiveAuthDialog from './components/views/dialogs/InteractiveAuthDialog';
|
||||||
|
|
|
@ -366,10 +366,11 @@ module.exports = WithMatrixClient(React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
onCryptoClicked: function(e) {
|
onCryptoClicked: function(e) {
|
||||||
var EncryptedEventDialog = sdk.getComponent("dialogs.EncryptedEventDialog");
|
|
||||||
var event = this.props.mxEvent;
|
var event = this.props.mxEvent;
|
||||||
|
|
||||||
Modal.createDialog(EncryptedEventDialog, {
|
Modal.createDialogAsync((cb) => {
|
||||||
|
require(['../../../async-components/views/dialogs/EncryptedEventDialog'], cb)
|
||||||
|
}, {
|
||||||
event: event,
|
event: event,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue