Split out render methods into 'views' leaving UI logic in 'controllers'. Hopefully should make it easier to skin / customise.

This commit is contained in:
David Baker 2015-06-19 12:53:48 +01:00
parent c8f0bac128
commit 2abea931ca
36 changed files with 303 additions and 184 deletions

View File

@ -1,7 +1,7 @@
var components = {}; var components = {};
function load(name) { function load(name) {
var module = require("./"+name); var module = require("./views/"+name);
components[name] = module; components[name] = module;
return module; return module;
}; };
@ -23,17 +23,19 @@ module.exports = {
// otherwise browserify has no way of knowing what module to include // otherwise browserify has no way of knowing what module to include
// Must be in this file (because the require is file-specific) and // Must be in this file (because the require is file-specific) and
// must be at the end because the components include this file. // must be at the end because the components include this file.
require('./atoms/LogoutButton'); require('./views/atoms/LogoutButton');
require('./atoms/MessageTimestamp'); require('./views/atoms/MessageTimestamp');
require('./molecules/MatrixToolbar'); require('./views/molecules/MatrixToolbar');
require('./molecules/RoomTile'); require('./views/molecules/RoomTile');
require('./molecules/MessageTile'); require('./views/molecules/MessageTile');
require('./molecules/SenderProfile'); require('./views/molecules/SenderProfile');
require('./molecules/UnknownMessageTile'); require('./views/molecules/UnknownMessageTile');
require('./molecules/MTextTile'); require('./views/molecules/MTextTile');
require('./molecules/MEmoteTile'); require('./views/molecules/MEmoteTile');
require('./molecules/RoomHeader'); require('./views/molecules/RoomHeader');
require('./molecules/MessageComposer'); require('./views/molecules/MessageComposer');
require('./organisms/RoomList'); require('./views/molecules/ProgressBar');
require('./organisms/RoomView'); require('./views/molecules/ServerConfig');
require('./templates/Login'); require('./views/organisms/RoomList');
require('./views/organisms/RoomView');
require('./views/templates/Login');

View File

@ -0,0 +1,9 @@
var dis = require("../../dispatcher");
module.exports = {
onClick: function() {
dis.dispatch({
action: 'logout'
});
},
};

View File

@ -0,0 +1,3 @@
module.exports = {
};

View File

@ -0,0 +1,3 @@
module.exports = {
};

View File

@ -0,0 +1,3 @@
module.exports = {
};

View File

@ -0,0 +1,3 @@
module.exports = {
};

View File

@ -1,10 +1,8 @@
var React = require('react'); var MatrixClientPeg = require("../../MatrixClientPeg");
var MatrixClientPeg = require("../MatrixClientPeg"); var dis = require("../../dispatcher");
var dis = require("../dispatcher"); module.exports = {
module.exports = React.createClass({
componentDidMount: function() { componentDidMount: function() {
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
}, },
@ -43,13 +41,5 @@ module.exports = React.createClass({
ev.preventDefault(); ev.preventDefault();
} }
}, },
};
render: function() {
return (
<div className="mx_MessageComposer">
<textarea ref="textarea" onKeyDown={this.onKeyDown} />
</div>
);
},
});

View File

@ -0,0 +1,3 @@
module.exports = {
};

View File

@ -0,0 +1,6 @@
module.exports = {
propTypes: {
value: React.PropTypes.number,
max: React.PropTypes.number
},
};

View File

@ -0,0 +1,3 @@
module.exports = {
};

View File

@ -0,0 +1,10 @@
var dis = require("../../dispatcher");
module.exports = {
onClick: function() {
dis.dispatch({
action: 'view_room',
room_id: this.props.room.roomId
});
},
};

View File

@ -0,0 +1,3 @@
module.exports = {
};

View File

@ -1,6 +1,6 @@
var React = require('react'); var React = require("react");
module.exports = React.createClass({ module.exports = {
propTypes: { propTypes: {
onHsUrlChanged: React.PropTypes.func, onHsUrlChanged: React.PropTypes.func,
onIsUrlChanged: React.PropTypes.func, onIsUrlChanged: React.PropTypes.func,
@ -41,21 +41,4 @@ module.exports = React.createClass({
getIsUrl: function() { getIsUrl: function() {
return this.state.is_url; return this.state.is_url;
}, },
};
render: function() {
return (
<div className="HomeServerTextBox">
<table className="serverConfig">
<tr>
<td>Home Server URL</td>
<td><input type="text" value={this.state.hs_url} onChange={this.hsChanged} /></td>
</tr>
<tr>
<td>Identity Server URL</td>
<td><input type="text" value={this.state.is_url} onChange={this.isChanged} /></td>
</tr>
</table>
</div>
);
}
});

View File

@ -0,0 +1,2 @@
module.exports = {
};

View File

@ -1,12 +1,11 @@
var React = require('react'); var React = require("react");
var MatrixClientPeg = require("../../MatrixClientPeg");
var MatrixClientPeg = require("../MatrixClientPeg"); var ComponentBroker = require('../../ComponentBroker');
var ComponentBroker = require('../ComponentBroker');
var RoomTile = ComponentBroker.get("molecules/RoomTile"); var RoomTile = ComponentBroker.get("molecules/RoomTile");
module.exports = {
module.exports = React.createClass({
componentWillMount: function() { componentWillMount: function() {
var cli = MatrixClientPeg.get(); var cli = MatrixClientPeg.get();
cli.on("Room.timeline", this.onRoomTimeline); cli.on("Room.timeline", this.onRoomTimeline);
@ -56,15 +55,5 @@ module.exports = React.createClass({
); );
}); });
}, },
};
render: function() {
return (
<div className="mx_RoomList">
<ul>
{this.makeRoomTiles()}
</ul>
</div>
);
}
});

View File

@ -1,14 +1,6 @@
var React = require('react'); var MatrixClientPeg = require("../../MatrixClientPeg");
var MatrixClientPeg = require("../MatrixClientPeg"); module.exports = {
var ComponentBroker = require('../ComponentBroker');
var MessageTile = ComponentBroker.get('molecules/MessageTile');
var RoomHeader = ComponentBroker.get('molecules/RoomHeader');
var MessageComposer = ComponentBroker.get('molecules/MessageComposer');
module.exports = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
room: MatrixClientPeg.get().getRoom(this.props.roomId) room: MatrixClientPeg.get().getRoom(this.props.roomId)
@ -41,26 +33,6 @@ module.exports = React.createClass({
}); });
}, },
getMessageTiles: function() {
return this.state.room.timeline.map(function(mxEv) {
return (
<li key={mxEv.getId()}><MessageTile mxEvent={mxEv} /></li>
);
});
},
render: function() {
return (
<div className="mx_RoomView">
<RoomHeader room={this.state.room} />
<ul ref="messageList">
{this.getMessageTiles()}
</ul>
<MessageComposer roomId={this.props.roomId} />
</div>
);
},
componentDidMount: function() { componentDidMount: function() {
var messageUl = this.refs.messageList.getDOMNode(); var messageUl = this.refs.messageList.getDOMNode();
messageUl.scrollTop = messageUl.scrollHeight; messageUl.scrollTop = messageUl.scrollHeight;
@ -72,5 +44,5 @@ module.exports = React.createClass({
messageUl.scrollTop = messageUl.scrollHeight; messageUl.scrollTop = messageUl.scrollHeight;
} }
} }
}); };

View File

@ -1,20 +1,11 @@
var React = require('react');
var ComponentBroker = require('../ComponentBroker');
var RoomList = ComponentBroker.get('organisms/RoomList');
var RoomView = ComponentBroker.get('organisms/RoomView');
var MatrixToolbar = ComponentBroker.get('molecules/MatrixToolbar');
var Login = ComponentBroker.get('templates/Login');
// should be atomised // should be atomised
var Loader = require("react-loader"); var Loader = require("react-loader");
var mxCliPeg = require("../../MatrixClientPeg");
var mxCliPeg = require("../MatrixClientPeg"); var dis = require("../../dispatcher");
var dis = require("../dispatcher"); module.exports = {
module.exports = React.createClass({
getInitialState: function() { getInitialState: function() {
return { return {
logged_in: !!(mxCliPeg.get() && mxCliPeg.get().credentials), logged_in: !!(mxCliPeg.get() && mxCliPeg.get().credentials),
@ -78,27 +69,5 @@ module.exports = React.createClass({
}); });
cli.startClient(); cli.startClient();
}, },
};
render: function() {
if (this.state.logged_in && this.state.ready) {
return (
<div className="mx_MatrixChat">
<div className="mx_MatrixChat_leftPanel">
<MatrixToolbar />
<RoomList selectedRoom={this.state.currentRoom} />
</div>
<RoomView roomId={this.state.currentRoom} key={this.state.currentRoom} />
</div>
);
} else if (this.state.logged_in) {
return (
<Loader />
);
} else {
return (
<Login onLoggedIn={this.onLoggedIn} />
);
}
}
});

View File

@ -1,12 +1,11 @@
var React = require('react'); var MatrixClientPeg = require("../../MatrixClientPeg");
var MatrixClientPeg = require("../MatrixClientPeg");
var Matrix = require("matrix-js-sdk"); var Matrix = require("matrix-js-sdk");
var ServerConfig = require("../molecules/ServerConfig"); var ComponentBroker = require("../../ComponentBroker");
var ProgressBar = require("../molecules/ProgressBar");
var Loader = require("react-loader");
module.exports = React.createClass({ var ServerConfig = ComponentBroker.get("molecules/ServerConfig");
module.exports = {
getInitialState: function() { getInitialState: function() {
return { return {
step: 'choose_hs', step: 'choose_hs',
@ -99,29 +98,4 @@ module.exports = React.createClass({
); );
} }
}, },
};
loginContent: function() {
if (this.state.busy) {
return (
<Loader />
);
} else {
return (
<div>
<h1>Please log in:</h1>
{this.componentForStep(this.state.step)}
<div className="error">{this.state.errorText}</div>
</div>
);
}
},
render: function() {
return (
<div className="mx_Login">
<ProgressBar value={this.state.currentStep} max={this.state.totalSteps} />
{this.loginContent()}
</div>
);
}
});

View File

@ -1 +1 @@
module.exports.MatrixChat = require("./pages/MatrixChat"); module.exports.MatrixChat = require("./views/pages/MatrixChat");

View File

@ -1,13 +1,9 @@
var React = require('react'); var React = require('react');
var dis = require("../dispatcher"); var LogoutButtonController = require("../../controllers/atoms/LogoutButton");
module.exports = React.createClass({ module.exports = React.createClass({
onClick: function() { mixins: [LogoutButtonController],
dis.dispatch({
action: 'logout'
});
},
render: function() { render: function() {
return ( return (

View File

@ -1,6 +1,10 @@
var React = require('react'); var React = require('react');
var MessageTimestampController = require("../../controllers/atoms/MessageTimestamp");
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [MessageTimestampController],
render: function() { render: function() {
var date = new Date(this.props.ts); var date = new Date(this.props.ts);
return ( return (

View File

@ -1,6 +1,10 @@
var React = require('react'); var React = require('react');
var MEmoteTileController = require("../../controllers/molecules/MEmoteTile");
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [MEmoteTileController],
render: function() { render: function() {
var mxEvent = this.props.mxEvent; var mxEvent = this.props.mxEvent;
var content = mxEvent.getContent(); var content = mxEvent.getContent();

View File

@ -1,6 +1,10 @@
var React = require('react'); var React = require('react');
var MTextTileController = require("../../controllers/molecules/MTextTile");
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [MTextTileController],
render: function() { render: function() {
var content = this.props.mxEvent.getContent(); var content = this.props.mxEvent.getContent();
return ( return (

View File

@ -1,10 +1,14 @@
var React = require('react'); var React = require('react');
var ComponentBroker = require('../ComponentBroker'); var ComponentBroker = require('../../ComponentBroker');
var LogoutButton = ComponentBroker.get("atoms/LogoutButton"); var LogoutButton = ComponentBroker.get("atoms/LogoutButton");
var MatrixToolbarController = require("../../controllers/molecules/MatrixToolbar");
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [MatrixToolbarController],
render: function() { render: function() {
return ( return (
<div className="mx_MatrixToolbar"> <div className="mx_MatrixToolbar">

View File

@ -0,0 +1,16 @@
var React = require('react');
var MessageComposerController = require("../../controllers/molecules/MessageComposer");
module.exports = React.createClass({
mixins: [MessageComposerController],
render: function() {
return (
<div className="mx_MessageComposer">
<textarea ref="textarea" onKeyDown={this.onKeyDown} />
</div>
);
},
});

View File

@ -2,7 +2,7 @@ var React = require('react');
var classNames = require("classnames"); var classNames = require("classnames");
var ComponentBroker = require('../ComponentBroker'); var ComponentBroker = require('../../ComponentBroker');
var MessageTimestamp = ComponentBroker.get('atoms/MessageTimestamp'); var MessageTimestamp = ComponentBroker.get('atoms/MessageTimestamp');
var SenderProfile = ComponentBroker.get('molecules/SenderProfile'); var SenderProfile = ComponentBroker.get('molecules/SenderProfile');
@ -14,7 +14,11 @@ var tileTypes = {
'm.emote': ComponentBroker.get('molecules/MEmoteTile') 'm.emote': ComponentBroker.get('molecules/MEmoteTile')
}; };
var MessageTileController = require("../../controllers/molecules/MessageTile");
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [MessageTileController],
render: function() { render: function() {
var content = this.props.mxEvent.getContent(); var content = this.props.mxEvent.getContent();
var msgtype = content.msgtype; var msgtype = content.msgtype;

View File

@ -1,10 +1,9 @@
var React = require('react'); var React = require('react');
var ProgressBarController = require("./../molecules/ProgressBar");
module.exports = React.createClass({ module.exports = React.createClass({
propTypes: { mixins: [ProgressBarController],
value: React.PropTypes.number,
max: React.PropTypes.number
},
render: function() { render: function() {
// Would use an HTML5 progress tag but if that doesn't animate if you // Would use an HTML5 progress tag but if that doesn't animate if you

View File

@ -1,6 +1,10 @@
var React = require('react'); var React = require('react');
var RoomHeaderController = require("../../controllers/molecules/RoomHeader");
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [RoomHeaderController],
render: function() { render: function() {
return ( return (
<div className="mx_RoomHeader"> <div className="mx_RoomHeader">

View File

@ -1,16 +1,10 @@
var React = require('react'); var React = require('react');
var classNames = require('classnames'); var classNames = require('classnames');
var dis = require("../dispatcher"); var RoomTileController = require("../../controllers/molecules/RoomTile");
module.exports = React.createClass({ module.exports = React.createClass({
onClick: function() { mixins: [RoomTileController],
dis.dispatch({
action: 'view_room',
room_id: this.props.room.roomId
});
},
render: function() { render: function() {
var classes = classNames({ var classes = classNames({
'mx_RoomTile': true, 'mx_RoomTile': true,

View File

@ -1,6 +1,10 @@
var React = require('react'); var React = require('react');
var SenderProfileController = require("../../controllers/molecules/SenderProfile");
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [SenderProfileController],
render: function() { render: function() {
var mxEvent = this.props.mxEvent; var mxEvent = this.props.mxEvent;
var name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); var name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender();

View File

@ -0,0 +1,24 @@
var React = require('react');
var ServerConfigController = require("../../controllers/molecules/ServerConfig");
module.exports = React.createClass({
mixins: [ServerConfigController],
render: function() {
return (
<div className="HomeServerTextBox">
<table className="serverConfig">
<tr>
<td>Home Server URL</td>
<td><input type="text" value={this.state.hs_url} onChange={this.hsChanged} /></td>
</tr>
<tr>
<td>Identity Server URL</td>
<td><input type="text" value={this.state.is_url} onChange={this.isChanged} /></td>
</tr>
</table>
</div>
);
}
});

View File

@ -1,6 +1,10 @@
var React = require('react'); var React = require('react');
var UnknownMessageTileController = require("../../controllers/molecules/UnknownMessageTile");
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [UnknownMessageTileController],
render: function() { render: function() {
return ( return (
<span className="mx_UnknownMessageTile"> <span className="mx_UnknownMessageTile">

View File

@ -0,0 +1,19 @@
var React = require('react');
var RoomListController = require("../../controllers/organisms/RoomList");
module.exports = React.createClass({
mixins: [RoomListController],
render: function() {
return (
<div className="mx_RoomList">
<ul>
{this.makeRoomTiles()}
</ul>
</div>
);
}
});

View File

@ -0,0 +1,35 @@
var React = require('react');
var ComponentBroker = require('../../ComponentBroker');
var MessageTile = ComponentBroker.get('molecules/MessageTile');
var RoomHeader = ComponentBroker.get('molecules/RoomHeader');
var MessageComposer = ComponentBroker.get('molecules/MessageComposer');
var RoomViewController = require("../../controllers/organisms/RoomView");
module.exports = React.createClass({
mixins: [RoomViewController],
getMessageTiles: function() {
return this.state.room.timeline.map(function(mxEv) {
return (
<li key={mxEv.getId()}><MessageTile mxEvent={mxEv} /></li>
);
});
},
render: function() {
return (
<div className="mx_RoomView">
<RoomHeader room={this.state.room} />
<ul ref="messageList">
{this.getMessageTiles()}
</ul>
<MessageComposer roomId={this.props.roomId} />
</div>
);
},
});

View File

@ -0,0 +1,40 @@
var React = require('react');
var ComponentBroker = require('../../ComponentBroker');
var RoomList = ComponentBroker.get('organisms/RoomList');
var RoomView = ComponentBroker.get('organisms/RoomView');
var MatrixToolbar = ComponentBroker.get('molecules/MatrixToolbar');
var Login = ComponentBroker.get('templates/Login');
var MatrixChatController = require("../../controllers/pages/MatrixChat");
// should be atomised
var Loader = require("react-loader");
module.exports = React.createClass({
mixins: [MatrixChatController],
render: function() {
if (this.state.logged_in && this.state.ready) {
return (
<div className="mx_MatrixChat">
<div className="mx_MatrixChat_leftPanel">
<MatrixToolbar />
<RoomList selectedRoom={this.state.currentRoom} />
</div>
<RoomView roomId={this.state.currentRoom} key={this.state.currentRoom} />
</div>
);
} else if (this.state.logged_in) {
return (
<Loader />
);
} else {
return (
<Login onLoggedIn={this.onLoggedIn} />
);
}
}
});

View File

@ -0,0 +1,37 @@
var React = require('react');
var ComponentBroker = require("../../ComponentBroker");
var ProgressBar = ComponentBroker.get("molecules/ProgressBar");
var Loader = require("react-loader");
var LoginController = require("../../controllers/templates/Login");
module.exports = React.createClass({
mixins: [LoginController],
loginContent: function() {
if (this.state.busy) {
return (
<Loader />
);
} else {
return (
<div>
<h1>Please log in:</h1>
{this.componentForStep(this.state.step)}
<div className="error">{this.state.errorText}</div>
</div>
);
}
},
render: function() {
return (
<div className="mx_Login">
<ProgressBar value={this.state.currentStep} max={this.state.totalSteps} />
{this.loginContent()}
</div>
);
}
});