-
Notifications
You must be signed in to change notification settings - Fork 160
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
910 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"extends": "./../../.eslintrc", | ||
"ecmaFeatures": { | ||
"jsx": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*bundle.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
## Isomorphic Flux Chat Example | ||
|
||
This is the Facebook [flux-chat](https://github.com/facebook/flux/tree/master/examples/flux-chat) | ||
example re-written in NuclearJS to demonstate the differences in the libraries as well as to show how Getters are used. | ||
|
||
## Running | ||
|
||
You must have [npm](https://www.npmjs.org/) installed on your computer. | ||
From the root project directory run these commands from the command line: | ||
|
||
`npm install` | ||
|
||
This will install all dependencies. | ||
|
||
To build the project, first run this command: | ||
|
||
`npm run build` it will build the project. | ||
|
||
Then run `npm start`. It will run the server on the port 1337, if you want another port use `npm start -- --port=9000` for example. | ||
|
||
That's it. The client and server share everything except the entry file which is different for the client (`./js/main.js`) and server (`./server.js`). | ||
|
||
Then open a browser and go to `http://localhost:1337` and you can expect the page while disabling javascript =). | ||
|
||
Don't hesitate to run `npm run watch` and `npm start` in parallel to hack around. | ||
|
||
## Considerations | ||
|
||
Do not forget that React.render* functions are synchronous, it's up to the developers to actually make sure that the reactor is already filled before they call the render function. | ||
|
||
One could for example make all actions return a promise or be callback based. | ||
|
||
Then in the request server side, just wait for the data to be fetched somehow, and then render. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
var mockData = require('./mock/messages') | ||
var Nuclear = require('nuclear-js') | ||
var NuclearAddons = require('nuclear-js-react-addons') | ||
var reactor = new Nuclear.Reactor({ | ||
debug: process.env.NODE_ENV, | ||
}) | ||
window.reactor = reactor | ||
var Chat = require('./modules/chat') | ||
|
||
var ChatApp = require('./components/ChatApp.jsx') | ||
ChatApp = NuclearAddons.provideReactor(ChatApp) | ||
|
||
Chat.register(reactor) | ||
|
||
// @todo: refactor to use new nuclear methods when 1.1 lands ? | ||
if (window.window.reactor_state !== null) { | ||
reactor.__state = Nuclear.Immutable.fromJS(window.reactor_state) | ||
} else { | ||
Chat.actions.receiveAll(reactor, mockData) | ||
} | ||
|
||
var React = require('react') | ||
window.React = React // export for http://fb.me/react-devtools | ||
|
||
React.render(<ChatApp reactor={reactor}/>, | ||
document.getElementById('react') | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/** | ||
* This file is provided by Facebook for testing and evaluation purposes | ||
* only. Facebook reserves all rights not expressly granted. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | ||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
*/ | ||
|
||
var React = require('react') | ||
var MessageSection = require('./MessageSection.jsx') | ||
var ThreadSection = require('./ThreadSection.jsx') | ||
|
||
var ChatApp = React.createClass({ | ||
render: function() { | ||
return ( | ||
<div className="chatapp"> | ||
<ThreadSection /> | ||
<MessageSection /> | ||
</div> | ||
) | ||
}, | ||
}) | ||
|
||
module.exports = ChatApp |
63 changes: 63 additions & 0 deletions
63
examples/isomorphic-flux-chat/components/MessageComposer.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/** | ||
* This file is provided by Facebook for testing and evaluation purposes | ||
* only. Facebook reserves all rights not expressly granted. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | ||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
*/ | ||
|
||
var Chat = require('../modules/chat') | ||
var React = require('react') | ||
var NuclearMixin = require('nuclear-js-react-addons/nuclearMixin') | ||
|
||
var ENTER_KEY_CODE = 13 | ||
|
||
// Difference with classic suggested architecture: | ||
// use the nuclear react mixin to have access to the | ||
// reactor in the context, that you can then use to | ||
// pass as first arguments of your actions | ||
|
||
var MessageComposer = React.createClass({ | ||
mixins: [NuclearMixin], | ||
|
||
propTypes: { | ||
threadID: React.PropTypes.string.isRequired, | ||
}, | ||
|
||
getInitialState: function() { | ||
return {text: ''} | ||
}, | ||
|
||
render: function() { | ||
return ( | ||
<textarea | ||
className="message-composer" | ||
name="message" | ||
value={this.state.text} | ||
onChange={this._onChange} | ||
onKeyDown={this._onKeyDown} | ||
/> | ||
) | ||
}, | ||
|
||
_onChange: function(event, value) { | ||
this.setState({text: event.target.value}) | ||
}, | ||
|
||
_onKeyDown: function(event) { | ||
if (event.keyCode === ENTER_KEY_CODE) { | ||
event.preventDefault() | ||
var text = this.state.text.trim() | ||
if (text) { | ||
Chat.actions.createMessage(this.context.reactor, text, this.props.threadID) | ||
} | ||
this.setState({text: ''}) | ||
} | ||
}, | ||
}) | ||
|
||
module.exports = MessageComposer |
38 changes: 38 additions & 0 deletions
38
examples/isomorphic-flux-chat/components/MessageListItem.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/** | ||
* This file is provided by Facebook for testing and evaluation purposes | ||
* only. Facebook reserves all rights not expressly granted. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | ||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
*/ | ||
|
||
var React = require('react') | ||
|
||
var ReactPropTypes = React.PropTypes | ||
|
||
var MessageListItem = React.createClass({ | ||
propTypes: { | ||
message: ReactPropTypes.object, | ||
}, | ||
|
||
render: function() { | ||
var message = this.props.message | ||
var dateString = (new Date(message.get('timestamp'))).toLocaleTimeString() | ||
|
||
return ( | ||
<li className="message-list-item"> | ||
<h5 className="message-author-name">{message.get('authorName')}</h5> | ||
<div className="message-time"> | ||
{dateString} | ||
</div> | ||
<div className="message-text">{message.get('text')}</div> | ||
</li> | ||
) | ||
}, | ||
}) | ||
|
||
module.exports = MessageListItem |
64 changes: 64 additions & 0 deletions
64
examples/isomorphic-flux-chat/components/MessageSection.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
/** | ||
* This file is provided by Facebook for testing and evaluation purposes | ||
* only. Facebook reserves all rights not expressly granted. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | ||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
*/ | ||
|
||
var MessageComposer = require('./MessageComposer.jsx') | ||
var MessageListItem = require('./MessageListItem.jsx') | ||
var Chat = require('../modules/chat') | ||
var React = require('react') | ||
var NuclearMixin = require('nuclear-js-react-addons/nuclearMixin') | ||
|
||
var MessageSection = React.createClass({ | ||
mixins: [NuclearMixin], | ||
|
||
getDataBindings() { | ||
return { | ||
thread: Chat.getters.currentThread, | ||
} | ||
}, | ||
|
||
componentDidMount: function() { | ||
this._scrollToBottom() | ||
}, | ||
|
||
render: function() { | ||
var thread = this.state.thread | ||
var messageListItems = thread.get('messages').map(message => { | ||
return ( | ||
<MessageListItem | ||
key={message.get('id')} | ||
message={message} | ||
/> | ||
) | ||
}) | ||
|
||
return ( | ||
<div className="message-section"> | ||
<h3 className="message-thread-heading">{thread.get('threadName')}</h3> | ||
<ul className="message-list" ref="messageList"> | ||
{messageListItems} | ||
</ul> | ||
<MessageComposer threadID={thread.get('threadID')}/> | ||
</div> | ||
) | ||
}, | ||
|
||
componentDidUpdate: function() { | ||
this._scrollToBottom() | ||
}, | ||
|
||
_scrollToBottom: function() { | ||
var ul = this.refs.messageList.getDOMNode() | ||
ul.scrollTop = ul.scrollHeight | ||
}, | ||
}) | ||
|
||
module.exports = MessageSection |
58 changes: 58 additions & 0 deletions
58
examples/isomorphic-flux-chat/components/ThreadListItem.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/** | ||
* This file is provided by Facebook for testing and evaluation purposes | ||
* only. Facebook reserves all rights not expressly granted. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | ||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
*/ | ||
|
||
var React = require('react') | ||
var Chat = require('../modules/chat') | ||
var cx = require('react/lib/cx') | ||
var NuclearMixin = require('nuclear-js-react-addons/nuclearMixin') | ||
|
||
var ReactPropTypes = React.PropTypes | ||
|
||
var ThreadListItem = React.createClass({ | ||
mixins: [NuclearMixin], | ||
|
||
propTypes: { | ||
thread: ReactPropTypes.object, | ||
currentThreadID: ReactPropTypes.string, | ||
}, | ||
|
||
render: function() { | ||
var thread = this.props.thread | ||
var lastMessage = thread.get('messages').last() | ||
var dateString = (new Date(lastMessage.get('timestamp'))).toLocaleTimeString() | ||
return ( | ||
<li | ||
className={cx({ | ||
'thread-list-item': true, | ||
'active': thread.get('threadID') === this.props.currentThreadID, | ||
})} | ||
onClick={this._onClick}> | ||
<h5 className="thread-name">{thread.get('threadName')}</h5> | ||
<div className="thread-time"> | ||
{dateString} | ||
</div> | ||
<div className="thread-last-message"> | ||
{lastMessage.get('text')} | ||
</div> | ||
</li> | ||
) | ||
}, | ||
|
||
_onClick: function() { | ||
var threadID = this.props.thread.get('threadID') | ||
if (this.props.currentThreadID !== threadID) { | ||
Chat.actions.clickThread(this.context.reactor, threadID) | ||
} | ||
}, | ||
}) | ||
|
||
module.exports = ThreadListItem |
57 changes: 57 additions & 0 deletions
57
examples/isomorphic-flux-chat/components/ThreadSection.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/** | ||
* This file is provided by Facebook for testing and evaluation purposes | ||
* only. Facebook reserves all rights not expressly granted. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | ||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
*/ | ||
|
||
var React = require('react') | ||
var Chat = require('../modules/chat') | ||
var NuclearMixin = require('nuclear-js-react-addons/nuclearMixin') | ||
|
||
var ThreadListItem = require('./ThreadListItem.jsx') | ||
|
||
var ThreadSection = React.createClass({ | ||
mixins: [NuclearMixin], | ||
|
||
getDataBindings() { | ||
return { | ||
threads: Chat.getters.threads, | ||
unreadCount: Chat.getters.unreadCount, | ||
currentThreadID: Chat.getters.currentThreadID, | ||
} | ||
}, | ||
|
||
render: function() { | ||
var threadListItems = this.state.threads.map(thread => { | ||
return ( | ||
<ThreadListItem | ||
key={thread.get('threadID')} | ||
thread={thread} | ||
currentThreadID={this.state.currentThreadID} | ||
/> | ||
) | ||
}, this) | ||
var unread = | ||
this.state.unreadCount === 0 ? | ||
null : | ||
<span>Unread threads: {this.state.unreadCount}</span> | ||
return ( | ||
<div className="thread-section"> | ||
<div className="thread-count"> | ||
{unread} | ||
</div> | ||
<ul className="thread-list"> | ||
{threadListItems} | ||
</ul> | ||
</div> | ||
) | ||
}, | ||
}) | ||
|
||
module.exports = ThreadSection |
Oops, something went wrong.