diff options
Diffstat (limited to 'web/src/js/components/ContentView/ContentLoader.jsx')
-rw-r--r-- | web/src/js/components/ContentView/ContentLoader.jsx | 97 |
1 files changed, 54 insertions, 43 deletions
diff --git a/web/src/js/components/ContentView/ContentLoader.jsx b/web/src/js/components/ContentView/ContentLoader.jsx index eff82d05..fb022df6 100644 --- a/web/src/js/components/ContentView/ContentLoader.jsx +++ b/web/src/js/components/ContentView/ContentLoader.jsx @@ -1,58 +1,34 @@ import React, { Component, PropTypes } from 'react' import { MessageUtils } from '../../flow/utils.js' -// This is the only place where we use jQuery. -// Remove when possible. -import $ from "jquery" -export default class ContentLoader extends Component { +export default View => class extends React.Component { + + static displayName = View.displayName || View.name + static matches = View.matches static propTypes = { + ...View.propTypes, + content: PropTypes.string, // mark as non-required flow: PropTypes.object.isRequired, message: PropTypes.object.isRequired, } - constructor(props, context) { - super(props, context) - this.state = { content: null, request: null } - } - - requestContent(nextProps) { - if (this.state.request) { - this.state.request.abort() + constructor(props) { + super(props) + this.state = { + content: undefined, + request: undefined, } - - const requestUrl = MessageUtils.getContentURL(nextProps.flow, nextProps.message) - const request = $.get(requestUrl) - - this.setState({ content: null, request }) - - request - .done(content => { - this.setState({ content }) - }) - .fail((xhr, textStatus, errorThrown) => { - if (textStatus === 'abort') { - return - } - this.setState({ content: `AJAX Error: ${textStatus}\r\n${errorThrown}` }) - }) - .always(() => { - this.setState({ request: null }) - }) } componentWillMount() { - this.requestContent(this.props) + this.startRequest(this.props) } componentWillReceiveProps(nextProps) { - let reload = nextProps.message !== this.props.message - let isUserEdit = !nextProps.readonly && nextProps.message.content - - if (isUserEdit) - this.setState({content: nextProps.message.content}) - else if(reload) - this.requestContent(nextProps) + if (nextProps.message.contentHash !== this.props.message.contentHash) { + this.startRequest(nextProps) + } } componentWillUnmount() { @@ -61,15 +37,50 @@ export default class ContentLoader extends Component { } } + startRequest(props) { + if (this.state.request) { + this.state.request.abort() + } + let requestUrl = MessageUtils.getContentURL(props.flow, props.message) + + // We use XMLHttpRequest instead of fetch() because fetch() is not (yet) abortable. + let request = new XMLHttpRequest(); + request.addEventListener("load", this.requestComplete.bind(this, request)); + request.addEventListener("error", this.requestFailed.bind(this, request)); + request.open("GET", requestUrl); + request.send(); + this.setState({ request, content: undefined }) + } + + requestComplete(request, e) { + if (request !== this.state.request) { + return // Stale request + } + this.setState({ + content: request.responseText, + request: undefined + }) + } + + requestFailed(request, e) { + if (request !== this.state.request) { + return // Stale request + } + console.error(e) + // FIXME: Better error handling + this.setState({ + content: "Error getting content.", + request: undefined + }) + } + render() { return this.state.content ? ( - React.cloneElement(this.props.children, { - content: this.state.content - }) + <View content={this.state.content} {...this.props}/> ) : ( <div className="text-center"> <i className="fa fa-spinner fa-spin"></i> </div> ) } -} +}; |