parent
6ae4cd0767
commit
fbe1b2dac2
@ -0,0 +1,17 @@
|
|||||||
|
#coding=utf-8
|
||||||
|
|
||||||
|
module Mobile
|
||||||
|
module Apis
|
||||||
|
class Issues< Grape::API
|
||||||
|
resources :issues do
|
||||||
|
|
||||||
|
desc "get special issuse"
|
||||||
|
get ':id' do
|
||||||
|
issue = Issue.find(params[:id])
|
||||||
|
present :data, issue, with: Mobile::Entities::Issue
|
||||||
|
present :status, 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,9 @@
|
|||||||
|
module Mobile
|
||||||
|
module Entities
|
||||||
|
class Issue <Grape::Entity
|
||||||
|
expose :subject
|
||||||
|
expose :description
|
||||||
|
expose :author, using: Mobile::Entities::User
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
* Created by guange on 16/3/19.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var CommentBox = React.createClass({
|
||||||
|
|
||||||
|
loadFromServer: function(){
|
||||||
|
$.ajax({
|
||||||
|
url: this.props.url,
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(data){
|
||||||
|
this.setState({data: data});
|
||||||
|
}.bind(this),
|
||||||
|
error: function(xhr,status,err){
|
||||||
|
console.error(this.props.url, status, err.toString());
|
||||||
|
}.bind(this)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onCommentSubmit: function(comment){
|
||||||
|
console.log(comment);
|
||||||
|
},
|
||||||
|
getInitialState: function(){
|
||||||
|
return {data: []};
|
||||||
|
},
|
||||||
|
componentDidMount: function(){
|
||||||
|
this.loadFromServer();
|
||||||
|
setInterval(this.loadFromServer, 2000);
|
||||||
|
},
|
||||||
|
render: function(){
|
||||||
|
return(
|
||||||
|
<div className="commentBox">
|
||||||
|
<CommentForm onCommentSubmit={this.onCommentSubmit}/>
|
||||||
|
<CommentList data={this.state.data}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var CommentList = React.createClass({
|
||||||
|
render: function(){
|
||||||
|
|
||||||
|
var commentNodes = this.props.data.map(function(comment){
|
||||||
|
return (
|
||||||
|
<Comment author={comment.author}>
|
||||||
|
{comment.text}
|
||||||
|
</Comment>
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="commentList">
|
||||||
|
{commentNodes}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var CommentForm = React.createClass({
|
||||||
|
handleSubmit: function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var author = this.refs.author.value.trim();
|
||||||
|
var text = this.refs.text.value.trim();
|
||||||
|
if(!text || !author){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.onCommentSubmit({author: author, text: text});
|
||||||
|
|
||||||
|
this.refs.author.value = '';
|
||||||
|
this.refs.text.value = '';
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
render: function(){
|
||||||
|
return (
|
||||||
|
<form className="commentForm" onSubmit={this.handleSubmit}>
|
||||||
|
<input type="text" placeholder="Your name" ref="author" />
|
||||||
|
<input type="text" placeholder="Say something..." ref="text" />
|
||||||
|
<input type="submit" value="Post" />
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var Comment = React.createClass({
|
||||||
|
|
||||||
|
rawMarkup: function() {
|
||||||
|
var rawMarkup = marked(this.props.children.toString(), {sanitize: true});
|
||||||
|
return { __html: rawMarkup };
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function(){
|
||||||
|
return (
|
||||||
|
<div className="comment">
|
||||||
|
<h2 className="commentAuthor">
|
||||||
|
{this.props.author}
|
||||||
|
</h2>
|
||||||
|
<span dangerouslySetInnerHTML={this.rawMarkup()}></span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
React.render(<CommentBox url="api/comment.json"/>, document.getElementById("example"));
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* ReactDOM v0.14.0
|
||||||
|
*
|
||||||
|
* Copyright 2013-2015, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
|
||||||
|
;(function(f) {
|
||||||
|
// CommonJS
|
||||||
|
if (typeof exports === "object" && typeof module !== "undefined") {
|
||||||
|
module.exports = f(require('react'));
|
||||||
|
|
||||||
|
// RequireJS
|
||||||
|
} else if (typeof define === "function" && define.amd) {
|
||||||
|
define(['react'], f);
|
||||||
|
|
||||||
|
// <script>
|
||||||
|
} else {
|
||||||
|
var g
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
g = window;
|
||||||
|
} else if (typeof global !== "undefined") {
|
||||||
|
g = global;
|
||||||
|
} else if (typeof self !== "undefined") {
|
||||||
|
g = self;
|
||||||
|
} else {
|
||||||
|
// works providing we're not in "use strict";
|
||||||
|
// needed for Java 8 Nashorn
|
||||||
|
// see https://github.com/facebook/react/issues/3037
|
||||||
|
g = this;
|
||||||
|
}
|
||||||
|
g.ReactDOM = f(g.React);
|
||||||
|
}
|
||||||
|
|
||||||
|
})(function(React) {
|
||||||
|
return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
||||||
|
});
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -0,0 +1,81 @@
|
|||||||
|
/**
|
||||||
|
* Created by guange on 16/3/21.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Index = React.createClass({
|
||||||
|
render: function(){
|
||||||
|
return (<div>index page</div>);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var apiUrl = 'http://localhost:3000/api/v1/';
|
||||||
|
|
||||||
|
var PostContainer = React.createClass({
|
||||||
|
loadDataFromServer: function(){
|
||||||
|
$.ajax({
|
||||||
|
url: apiUrl + 'issues/' + this.props.params.id,
|
||||||
|
dataType: 'json',
|
||||||
|
success: function(data){
|
||||||
|
this.setState({data: data.data});
|
||||||
|
}.bind(this),
|
||||||
|
error: function(xhr,status,err){
|
||||||
|
console.log(err);
|
||||||
|
}.bind(this)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
componentDidMount: function(){
|
||||||
|
this.loadDataFromServer();
|
||||||
|
},
|
||||||
|
getInitialState: function(){
|
||||||
|
return {data: null};
|
||||||
|
},
|
||||||
|
render: function(){
|
||||||
|
return (
|
||||||
|
<div className="post-container">
|
||||||
|
<div className="post-wrapper">
|
||||||
|
<PostView data={this.state.data}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var PostView = React.createClass({
|
||||||
|
render: function(){
|
||||||
|
if(!this.props.data){
|
||||||
|
return <div></div>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="post-main">
|
||||||
|
<div className="post-avatar fl"><img src={this.props.data.author.img_url} width="45" height="45" className="border-radius" /></div>
|
||||||
|
<div className="post-title hidden mb5"><span className="c-grey3 f15 fb">{this.props.data.subject}</span></div>
|
||||||
|
<div className="post-title hidden"><a herf="javascript:void(0);" className="mr10">{this.props.data.author.nickname}</a>项目问题</div>
|
||||||
|
<div className="cl"></div>
|
||||||
|
<div className="post-content c-grey2 mt10">
|
||||||
|
<p className="post-all-content">{this.props.data.description}</p>
|
||||||
|
</div>
|
||||||
|
<a herf="javascript:void(0);" className="link-blue f13 fl mt5 post-more undis" style={{textDecoration: 'underline'}}>点击展开</a>
|
||||||
|
<div className="cl"></div>
|
||||||
|
<span className="c-grey f13 mt10 fl">{this.props.data.time}</span>
|
||||||
|
<div className="cl"></div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var Route = ReactRouter.Route;
|
||||||
|
var Router = ReactRouter.Router;
|
||||||
|
|
||||||
|
var routes = (
|
||||||
|
<Router>
|
||||||
|
<Route path="/" component={Index}/>
|
||||||
|
<Route path="issue/:id" component={PostContainer} />
|
||||||
|
</Router>
|
||||||
|
);
|
||||||
|
|
||||||
|
React.render(routes, document.getElementById("container"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
|||||||
|
@charset "utf-8";
|
||||||
|
/* CSS Document */
|
||||||
|
|
||||||
|
/*基本样式*/
|
||||||
|
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体";}
|
||||||
|
h1,h2,h3,h4,h5,p {padding:0px; margin:0px;}
|
||||||
|
.f13 {font-size:13px;}
|
||||||
|
.f15 {font-size:15px;}
|
||||||
|
.fb {font-weight:bold;}
|
||||||
|
.mt5 {margin-top:5px;}
|
||||||
|
.mt10 {margin-top:10px;}
|
||||||
|
.mb5 {margin-bottom:5px;}
|
||||||
|
.ml10 {margin-left:10px;}
|
||||||
|
.mr10 {margin-right:10px;}
|
||||||
|
.ml15 {margin-left:15px;}
|
||||||
|
.mr15 {margin-right:15px;}
|
||||||
|
.c-blue {color:#269ac9;}
|
||||||
|
.c-grey {color:#9a9a9a;}
|
||||||
|
.c-grey2 {color:#707070;}
|
||||||
|
.c-grey3 {color:#555555;}
|
||||||
|
a:link,a:visited{text-decoration:none;}
|
||||||
|
a:hover,a:active{cursor:pointer;}
|
||||||
|
a.link-blue {color:#269ac9;}
|
||||||
|
.border-radius {border-radius:5px;}
|
||||||
|
.max-width-60 {max-width:60px;}
|
||||||
|
.max-width-130 {max-width:130px;}
|
||||||
|
.hidden {overflow:hidden; white-space:nowrap; text-overflow:ellipsis;}
|
||||||
|
.inline-block {display:inline-block;}
|
||||||
|
.undis {display:none;}
|
||||||
|
|
||||||
|
/*动态样式*/
|
||||||
|
.post-container {width:100%;}
|
||||||
|
.post-wrapper {width:98%; border:1px solid #e6e6e6; border-radius:3px; background-color:#ffffff; margin:15px auto;}
|
||||||
|
.post-main {padding:10px; color:#9a9a9a;}
|
||||||
|
.post-avatar {width:45px; height:45px; margin-right:10px;}
|
||||||
|
.post-title {font-size:13px; text-align:left;}
|
||||||
|
.fl {float:left;}
|
||||||
|
.cl {clear:both; overflow:hidden;}
|
||||||
|
.post-content {width:100%; font-size:13px; line-height:18px; height:90px; overflow:hidden;}
|
||||||
|
.post-interactive {width:100%; height:35px; line-height:35px; vertical-align:middle; border-top:1px solid #e6e6e6; background-color:#f8f9fb;}
|
||||||
|
.post-interactive-column {width:50%; text-align:center; float:left; font-size:13px;}
|
Loading…
Reference in new issue