Skip to content

Commit

Permalink
Merge ab34444 into 2b31a26
Browse files Browse the repository at this point in the history
  • Loading branch information
Sinewyk committed Jul 17, 2015
2 parents 2b31a26 + ab34444 commit bbd339e
Show file tree
Hide file tree
Showing 22 changed files with 910 additions and 0 deletions.
6 changes: 6 additions & 0 deletions examples/isomorphic-flux-chat/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "./../../.eslintrc",
"ecmaFeatures": {
"jsx": true
}
}
1 change: 1 addition & 0 deletions examples/isomorphic-flux-chat/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*bundle.js
33 changes: 33 additions & 0 deletions examples/isomorphic-flux-chat/README.md
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.
27 changes: 27 additions & 0 deletions examples/isomorphic-flux-chat/client.js
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')
)
28 changes: 28 additions & 0 deletions examples/isomorphic-flux-chat/components/ChatApp.jsx
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 examples/isomorphic-flux-chat/components/MessageComposer.jsx
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 examples/isomorphic-flux-chat/components/MessageListItem.jsx
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 examples/isomorphic-flux-chat/components/MessageSection.jsx
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 examples/isomorphic-flux-chat/components/ThreadListItem.jsx
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 examples/isomorphic-flux-chat/components/ThreadSection.jsx
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

0 comments on commit bbd339e

Please sign in to comment.