diff --git a/lib/boards-api.js b/lib/boards-api.js
index 1fa9dfd..f2842b2 100644
--- a/lib/boards-api.js
+++ b/lib/boards-api.js
@@ -207,6 +207,48 @@ BoardsAPI.prototype.createPost = function (post, board, done) {
}
], done)
}
+BoardsAPI.prototype.createComment = function (comment, parent, done) {
+ try {
+ comment.date = parseInt((new Date()).getTime() / 1000, 10)
+ comment.op = this.id
+ comment.parent = parent
+ var comment_str = JSON.stringify(comment)
+ } catch (e) {
+ console.log('Error, invalid Post:', e)
+ return done(e)
+ }
+ if (!comment.text) return done('empty comment')
+ console.log('Commenting:', comment)
+ var dest = '/ipfs-boards-profile/comments/' + parent + '/' + comment.date + '.json'
+ var commenthash
+ asyncjs.waterfall([
+ // Create required directories
+ cb => this.ipfs.files.mkdir('/ipfs-boards-profile/comments/' + parent + '/', { p: true }, cb),
+ (e, cb) => {
+ // Remove old comment file if present
+ this.ipfs.files.rm(dest, { r: true }, res => cb())
+ },
+ (cb) => {
+ // Serialize comment and add to IPFS
+ this.ipfs.add(new Buffer(comment_str), cb)
+ },
+ (res, cb) => {
+ // Move post into mfs
+ console.log('added Comment to IPFS:', res.Hash)
+ commenthash = res.Hash
+ var spath = '/ipfs/' + res.Hash
+ this.ipfs.files.cp([spath, dest], cb)
+ },
+ (e, cb) => this.ipfs.files.stat('/', cb),
+ (res, cb) => {
+ var profile_hash = res.Hash
+ console.log('Publishing profile...')
+ this.ipfs.name.publish(profile_hash, err => {
+ done(err, commenthash)
+ })
+ }
+ ], done)
+}
BoardsAPI.prototype.delete = function (opts, done) {
var url = '/ipfs-boards-profile/'
diff --git a/webapp/components/comment.jsx b/webapp/components/comment.jsx
index 1dddf58..6f7b362 100644
--- a/webapp/components/comment.jsx
+++ b/webapp/components/comment.jsx
@@ -4,6 +4,62 @@ var Icon = require('icon.jsx')
var Clock = require('clock.jsx')
var Link = require('react-router').Link
var UserID = require('userID.jsx')
+var { Error, Success } = require('status-components.jsx')
+
+var CommentEditor = React.createClass({
+ getInitialState () {
+ return { }
+ },
+ componentDidMount () {
+ this.init(this.props)
+ },
+ componentWillReceiveProps (props) {
+ this.init(props)
+ },
+ init (props) {
+ this.setState({ api: props.api })
+ },
+ handleChange (event) {
+ var obj = {}
+ obj[event.target.id] = event.target.value
+ this.setState(obj)
+ },
+ save () {
+ var boards = this.props.api
+ var comment = { text: this.state.text }
+ this.setState({ loading: true })
+ boards.createComment(comment, this.props.parent, (err, hash) => {
+ if (err) {
+ this.setState({ loading: false, error: err })
+ } else {
+ this.setState({ loading: false, success: true, hash })
+ }
+ })
+ },
+ render () {
+ if (this.state.error) {
+ return
+ } else if (this.state.loading) {
+ return
+
+
Publishing Comment
+
+ } else if (this.state.success) {
+ var url = '/@' + this.props.adminID + '/' + this.props.board + '/' + (this.props.post || this.props.parent) + '/' + this.state.hash
+ return
+ View
+
+ } else {
+ return
+
+
Note: this version of the app doesn't check wether you are allowed to post on this board, so there are no guarantees that your post will be visible.
+
+
+
+
+ }
+ }
+})
var Comment = React.createClass({
getInitialState () {
@@ -29,7 +85,10 @@ var Comment = React.createClass({
}
},
getComments () {
- return
+ return
+ },
+ toggleReply () {
+ this.setState({ reply: !this.state.reply })
},
render () {
if (this.props.comment) {
@@ -38,9 +97,15 @@ var Comment = React.createClass({
{this.getPermalink()}
+ { this.props.allowReply
+ ? Reply
+ : }
{this.getParentlink()}
+ { this.state.reply
+ ?
+ : }
{this.getComments()}
} else {
return
Invalid Comment
@@ -56,7 +121,7 @@ var Comments = React.createClass({
if (this.props.api) this.init(this.props.api)
},
componentWillReceiveProps (props) {
- if (props.api) this.init(props.api)
+ if (props.api !== this.props.api) this.init(props.api)
},
init (boards) {
boards.getEventEmitter().on('comment for ' + this.props.parent, cmnt => {
@@ -76,7 +141,7 @@ var Comments = React.createClass({
},
getComments () {
if (this.state.comments.length > 0) {
- return this.state.comments.map(cmnt => ())
+ return this.state.comments.map(cmnt => ())
} else return
},
render () {
@@ -90,4 +155,4 @@ var Comments = React.createClass({
}
})
-module.exports = { Comment, Comments }
+module.exports = { Comment, Comments, CommentEditor }
diff --git a/webapp/components/post.jsx b/webapp/components/post.jsx
index c887c4a..b73ba9a 100644
--- a/webapp/components/post.jsx
+++ b/webapp/components/post.jsx
@@ -5,7 +5,7 @@ var Link = require('react-router').Link
var Clock = require('clock.jsx')
var UserID = require('userID.jsx')
var { Error } = require('status-components.jsx')
-var Comments = require('comment.jsx').Comments
+var { Comments, CommentEditor } = require('comment.jsx')
module.exports = React.createClass({
getInitialState () {
@@ -54,6 +54,9 @@ module.exports = React.createClass({
}
} else return
},
+ toggleReply () {
+ this.setState({ reply: !this.state.reply })
+ },
getContent () {
if (this.state.error) {
return
@@ -75,6 +78,9 @@ module.exports = React.createClass({
View
+ { this.props.allowReply
+ ? Reply
+ : }
{this.editorLink()}
@@ -83,7 +89,10 @@ module.exports = React.createClass({
render () {
return
{this.getContent()}
-
+ { this.state.reply
+ ?
+ :
}
+
}
})
diff --git a/webapp/pages/commentpage.jsx b/webapp/pages/commentpage.jsx
index 9e302d0..3d3d403 100644
--- a/webapp/pages/commentpage.jsx
+++ b/webapp/pages/commentpage.jsx
@@ -12,7 +12,6 @@ module.exports = function (boardsAPI) {
},
componentDidMount: function () {
boardsAPI.use(boards => {
- boards.init()
boards.getEventEmitter().on('init', err => {
if (!err && this.isMounted()) {
this.init(boards)
@@ -24,7 +23,9 @@ module.exports = function (boardsAPI) {
})
},
componentWillReceiveProps: function (nextProps) {
- boardsAPI.use(boards => this.downloadComment(boards, nextProps))
+ if (this.props.params !== nextProps.params) {
+ boardsAPI.use(boards => this.downloadComment(boards, nextProps))
+ }
},
downloadComment: function (boards, props) {
this.setState({ comment: false })
@@ -34,13 +35,18 @@ module.exports = function (boardsAPI) {
comment: { title: 'Error', text: err.Message || err.Error }
})
} else {
- this.setState({ comment })
+ if (!comment.parent && comment.text) {
+ // Redirect to post page
+ this.props.history.push('/@' + this.props.params.userid + '/' + this.props.params.boardname + '/' + this.props.params.commenthash)
+ } else {
+ this.setState({ comment })
+ }
}
})
},
init: function (boards) {
if (this.state.init) return
- this.setState({ api: true, boards: boards })
+ this.setState({ api: true, boards, canReply: boards.isInit && !boards.limited })
this.downloadComment(boards, this.props)
},
getContext: function () {
@@ -54,7 +60,7 @@ module.exports = function (boardsAPI) {
},
showComment: function () {
if (this.state.comment) {
- return
+ return
} else {
return
diff --git a/webapp/pages/postpage.jsx b/webapp/pages/postpage.jsx
index 426e900..bf57a85 100644
--- a/webapp/pages/postpage.jsx
+++ b/webapp/pages/postpage.jsx
@@ -11,7 +11,10 @@ module.exports = function (boardsAPI) {
},
componentDidMount: function () {
boardsAPI.use(boards => {
- this.setState({ api: boards })
+ this.setState({ api: boards, allowReply: boards.isInit && !boards.limited })
+ boards.getEventEmitter().on('init', (err, limited) => {
+ this.setState({ api: boards, allowReply: !err && !limited })
+ })
})
},
getContext: function () {
@@ -29,7 +32,7 @@ module.exports = function (boardsAPI) {
{this.getContext()}
-
+
} else {
return
diff --git a/webapp/style.css b/webapp/style.css
index 75046ba..78d3538 100644
--- a/webapp/style.css
+++ b/webapp/style.css
@@ -14,6 +14,7 @@ hr {
a {
text-decoration: underline;
color: #ababab;
+ cursor: pointer;
}
.nounderline {