mirror of
https://github.com/samsonjs/samhuri.net.git
synced 2026-04-27 14:57:40 +00:00
quick and dirty comments
This commit is contained in:
parent
050f2df426
commit
4b8bf805cd
9 changed files with 431 additions and 2 deletions
|
|
@ -131,6 +131,8 @@ time { color: #444 }
|
||||||
#prev { float: left }
|
#prev { float: left }
|
||||||
#next { float: right }
|
#next { float: right }
|
||||||
|
|
||||||
|
#comments { display: none }
|
||||||
|
|
||||||
footer { text-align: center
|
footer { text-align: center
|
||||||
; font-size: 1.2em
|
; font-size: 1.2em
|
||||||
; margin: 0
|
; margin: 0
|
||||||
|
|
|
||||||
54
assets/request.js
Normal file
54
assets/request.js
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
(function() {
|
||||||
|
if (typeof SJS === 'undefined') SJS = {}
|
||||||
|
var load, _jsonpCounter = 1
|
||||||
|
SJS.request = function(options, cb) { // jsonp request, quacks like mikeal's request module
|
||||||
|
var jsonpCallbackName = '_jsonpCallback' + _jsonpCounter++
|
||||||
|
, url = options.uri + '?callback=SJS.' + jsonpCallbackName
|
||||||
|
SJS[jsonpCallbackName] = function(obj) {
|
||||||
|
cb(null, obj)
|
||||||
|
setTimeout(function() { delete SJS[jsonpCallbackName] }, 0)
|
||||||
|
}
|
||||||
|
load(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bootstrap loader from LABjs
|
||||||
|
load = function(url) {
|
||||||
|
var oDOC = document
|
||||||
|
, handler
|
||||||
|
, head = oDOC.head || oDOC.getElementsByTagName("head")
|
||||||
|
|
||||||
|
// loading code borrowed directly from LABjs itself
|
||||||
|
// (now removes script elem when done and nullifies its reference --sjs)
|
||||||
|
setTimeout(function () {
|
||||||
|
if ("item" in head) { // check if ref is still a live node list
|
||||||
|
if (!head[0]) { // append_to node not yet ready
|
||||||
|
setTimeout(arguments.callee, 25)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
head = head[0]; // reassign from live node list ref to pure node ref -- avoids nasty IE bug where changes to DOM invalidate live node lists
|
||||||
|
}
|
||||||
|
var scriptElem = oDOC.createElement("script"),
|
||||||
|
scriptdone = false
|
||||||
|
scriptElem.onload = scriptElem.onreadystatechange = function () {
|
||||||
|
if ((scriptElem.readyState && scriptElem.readyState !== "complete" && scriptElem.readyState !== "loaded") || scriptdone) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
scriptElem.onload = scriptElem.onreadystatechange = null
|
||||||
|
scriptElem.parentNode.removeChild(scriptElem)
|
||||||
|
scriptElem = null
|
||||||
|
scriptdone = true
|
||||||
|
};
|
||||||
|
scriptElem.src = url
|
||||||
|
head.insertBefore(scriptElem, head.firstChild)
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
// required: shim for FF <= 3.5 not having document.readyState
|
||||||
|
if (oDOC.readyState == null && oDOC.addEventListener) {
|
||||||
|
oDOC.readyState = "loading"
|
||||||
|
oDOC.addEventListener("DOMContentLoaded", function handler() {
|
||||||
|
oDOC.removeEventListener("DOMContentLoaded", handler, false)
|
||||||
|
oDOC.readyState = "complete"
|
||||||
|
}, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}())
|
||||||
14
blog.rb
14
blog.rb
|
|
@ -15,7 +15,9 @@ end
|
||||||
|
|
||||||
template = File.read(File.join('templates', 'blog', 'post.html'))
|
template = File.read(File.join('templates', 'blog', 'post.html'))
|
||||||
|
|
||||||
Posts = JSON.parse(File.read(File.join(srcdir, 'posts.json')))
|
# read posts
|
||||||
|
posts_file = File.join(srcdir, 'posts.json')
|
||||||
|
Posts = JSON.parse(File.read(posts_file))
|
||||||
posts = Posts['published'].map do |filename|
|
posts = Posts['published'].map do |filename|
|
||||||
lines = File.readlines(File.join(srcdir, filename))
|
lines = File.readlines(File.join(srcdir, filename))
|
||||||
post = { :filename => filename }
|
post = { :filename => filename }
|
||||||
|
|
@ -33,24 +35,32 @@ posts = Posts['published'].map do |filename|
|
||||||
end
|
end
|
||||||
post[:content] = lines.join
|
post[:content] = lines.join
|
||||||
post[:body] = RDiscount.new(post[:content]).to_html
|
post[:body] = RDiscount.new(post[:content]).to_html
|
||||||
|
# comments on by default
|
||||||
|
post[:comments] = true if post[:comments].nil?
|
||||||
post
|
post
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# generate posts
|
||||||
posts.each_with_index do |post, i|
|
posts.each_with_index do |post, i|
|
||||||
post[:html] = Mustache.render(template, { :title => post[:title],
|
post[:html] = Mustache.render(template, { :title => post[:title],
|
||||||
:post => post,
|
:post => post,
|
||||||
:previous => i < posts.length - 1 && posts[i + 1],
|
:previous => i < posts.length - 1 && posts[i + 1],
|
||||||
:next => i > 0 && posts[i - 1]
|
:next => i > 0 && posts[i - 1],
|
||||||
|
:comments => post[:comments]
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# generate landing page
|
||||||
index_template = File.read(File.join('templates', 'blog', 'index.html'))
|
index_template = File.read(File.join('templates', 'blog', 'index.html'))
|
||||||
index_html = Mustache.render(index_template, { :posts => posts,
|
index_html = Mustache.render(index_template, { :posts => posts,
|
||||||
:post => posts.first,
|
:post => posts.first,
|
||||||
:previous => posts[1]
|
:previous => posts[1]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# write landing page
|
||||||
File.open(File.join(destdir, 'index.html'), 'w') {|f| f.puts(index_html) }
|
File.open(File.join(destdir, 'index.html'), 'w') {|f| f.puts(index_html) }
|
||||||
|
|
||||||
|
# write posts
|
||||||
posts.each do |post|
|
posts.each do |post|
|
||||||
File.open(File.join(destdir, post[:filename]), 'w') {|f| f.puts(post[:html]) }
|
File.open(File.join(destdir, post[:filename]), 'w') {|f| f.puts(post[:html]) }
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,28 @@ _gaq.push( ['_setAccount', 'UA-214054-5']
|
||||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||||
})();
|
})();
|
||||||
|
if (document.addEventListener) {
|
||||||
|
document.addEventListener('DOMContentLoaded', ready, false)
|
||||||
|
} else if (window.attachEvent) {
|
||||||
|
window.attachEvent('onload', ready)
|
||||||
|
}
|
||||||
|
function ready() {
|
||||||
|
function html(id, h) {
|
||||||
|
document.getElementById(id).innerHTML = h
|
||||||
|
}
|
||||||
|
|
||||||
|
var discussion = document.getElementById('discussion')
|
||||||
|
, discussionToggle = document.getElementById('discussion-toggle')
|
||||||
|
, hidden = true
|
||||||
|
discussionToggle.onclick = function() {
|
||||||
|
hidden = !hidden
|
||||||
|
discussion.style.display = hidden ? 'none' : 'block'
|
||||||
|
discussionToggle.innerHTML = hidden ? '↓ show discussion ↓' : '↑ hide discussion ↑'
|
||||||
|
SJS.request({uri: 'http://bohodev.net:8000/comments/'}, function(err, body) {
|
||||||
|
html('comments', body)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<header>
|
<header>
|
||||||
<h1><a href=index.html>sjs' blog</a></h1>
|
<h1><a href=index.html>sjs' blog</a></h1>
|
||||||
|
|
@ -274,6 +296,21 @@ addLineNumbersToAllGists();
|
||||||
<a id=prev href=a-preview-of-mach-o-file-generation.html>← A preview of Mach-O file generation</a>
|
<a id=prev href=a-preview-of-mach-o-file-generation.html>← A preview of Mach-O file generation</a>
|
||||||
<br style=clear:both>
|
<br style=clear:both>
|
||||||
</div>
|
</div>
|
||||||
|
<div class=center><a id=discussion-toggle href=#>↓ show discussion ↓</a></div>
|
||||||
|
<div id=discussion>
|
||||||
|
<div id=comment-form>
|
||||||
|
<form method=post action=http://bohodev.net:8000/comment>
|
||||||
|
<input name=from type=hidden value=37signals-chalk-dissected.html>
|
||||||
|
<p>Name: <input name=name size=30></p>
|
||||||
|
<p>URL: <input name=url size=30></p>
|
||||||
|
<p>Thoughts: <textarea name=body cols=40 rows=5></textarea></p>
|
||||||
|
<p><input type=submit value=Add to discussion></p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id=comments>
|
||||||
|
<img id=discussion-spinner src=../assets/spinner.gif>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<a href=https://twitter.com/_sjs>@_sjs</a>
|
<a href=https://twitter.com/_sjs>@_sjs</a>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,28 @@ _gaq.push( ['_setAccount', 'UA-214054-5']
|
||||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||||
})();
|
})();
|
||||||
|
if (document.addEventListener) {
|
||||||
|
document.addEventListener('DOMContentLoaded', ready, false)
|
||||||
|
} else if (window.attachEvent) {
|
||||||
|
window.attachEvent('onload', ready)
|
||||||
|
}
|
||||||
|
function ready() {
|
||||||
|
function html(id, h) {
|
||||||
|
document.getElementById(id).innerHTML = h
|
||||||
|
}
|
||||||
|
|
||||||
|
var discussion = document.getElementById('discussion')
|
||||||
|
, discussionToggle = document.getElementById('discussion-toggle')
|
||||||
|
, hidden = true
|
||||||
|
discussionToggle.onclick = function() {
|
||||||
|
hidden = !hidden
|
||||||
|
discussion.style.display = hidden ? 'none' : 'block'
|
||||||
|
discussionToggle.innerHTML = hidden ? '↓ show discussion ↓' : '↑ hide discussion ↑'
|
||||||
|
SJS.request({uri: 'http://bohodev.net:8000/comments/'}, function(err, body) {
|
||||||
|
html('comments', body)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<header>
|
<header>
|
||||||
<h1><a href=index.html>sjs' blog</a></h1>
|
<h1><a href=index.html>sjs' blog</a></h1>
|
||||||
|
|
@ -69,6 +91,21 @@ straightforward, an example is in asm/binary.rb, in the #output method.</p>
|
||||||
<a id=next href=37signals-chalk-dissected.html>37signals' Chalk Dissected →</a>
|
<a id=next href=37signals-chalk-dissected.html>37signals' Chalk Dissected →</a>
|
||||||
<br style=clear:both>
|
<br style=clear:both>
|
||||||
</div>
|
</div>
|
||||||
|
<div class=center><a id=discussion-toggle href=#>↓ show discussion ↓</a></div>
|
||||||
|
<div id=discussion>
|
||||||
|
<div id=comment-form>
|
||||||
|
<form method=post action=http://bohodev.net:8000/comment>
|
||||||
|
<input name=from type=hidden value=a-preview-of-mach-o-file-generation.html>
|
||||||
|
<p>Name: <input name=name size=30></p>
|
||||||
|
<p>URL: <input name=url size=30></p>
|
||||||
|
<p>Thoughts: <textarea name=body cols=40 rows=5></textarea></p>
|
||||||
|
<p><input type=submit value=Add to discussion></p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id=comments>
|
||||||
|
<img id=discussion-spinner src=../assets/spinner.gif>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<a href=https://twitter.com/_sjs>@_sjs</a>
|
<a href=https://twitter.com/_sjs>@_sjs</a>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,28 @@ _gaq.push( ['_setAccount', 'UA-214054-5']
|
||||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||||
})();
|
})();
|
||||||
|
if (document.addEventListener) {
|
||||||
|
document.addEventListener('DOMContentLoaded', ready, false)
|
||||||
|
} else if (window.attachEvent) {
|
||||||
|
window.attachEvent('onload', ready)
|
||||||
|
}
|
||||||
|
function ready() {
|
||||||
|
function html(id, h) {
|
||||||
|
document.getElementById(id).innerHTML = h
|
||||||
|
}
|
||||||
|
|
||||||
|
var discussion = document.getElementById('discussion')
|
||||||
|
, discussionToggle = document.getElementById('discussion-toggle')
|
||||||
|
, hidden = true
|
||||||
|
discussionToggle.onclick = function() {
|
||||||
|
hidden = !hidden
|
||||||
|
discussion.style.display = hidden ? 'none' : 'block'
|
||||||
|
discussionToggle.innerHTML = hidden ? '↓ show discussion ↓' : '↑ hide discussion ↑'
|
||||||
|
SJS.request({uri: 'http://bohodev.net:8000/comments/'}, function(err, body) {
|
||||||
|
html('comments', body)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<header>
|
<header>
|
||||||
<h1><a href=index.html>sjs' blog</a></h1>
|
<h1><a href=index.html>sjs' blog</a></h1>
|
||||||
|
|
@ -292,6 +314,21 @@ would almost have a useful Mach object file.)</i></p>
|
||||||
<a id=next href=a-preview-of-mach-o-file-generation.html>A preview of Mach-O file generation →</a>
|
<a id=next href=a-preview-of-mach-o-file-generation.html>A preview of Mach-O file generation →</a>
|
||||||
<br style=clear:both>
|
<br style=clear:both>
|
||||||
</div>
|
</div>
|
||||||
|
<div class=center><a id=discussion-toggle href=#>↓ show discussion ↓</a></div>
|
||||||
|
<div id=discussion>
|
||||||
|
<div id=comment-form>
|
||||||
|
<form method=post action=http://bohodev.net:8000/comment>
|
||||||
|
<input name=from type=hidden value=basics-of-the-mach-o-file-format.html>
|
||||||
|
<p>Name: <input name=name size=30></p>
|
||||||
|
<p>URL: <input name=url size=30></p>
|
||||||
|
<p>Thoughts: <textarea name=body cols=40 rows=5></textarea></p>
|
||||||
|
<p><input type=submit value=Add to discussion></p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id=comments>
|
||||||
|
<img id=discussion-spinner src=../assets/spinner.gif>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<a href=https://twitter.com/_sjs>@_sjs</a>
|
<a href=https://twitter.com/_sjs>@_sjs</a>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,28 @@ _gaq.push( ['_setAccount', 'UA-214054-5']
|
||||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||||
})();
|
})();
|
||||||
|
if (document.addEventListener) {
|
||||||
|
document.addEventListener('DOMContentLoaded', ready, false)
|
||||||
|
} else if (window.attachEvent) {
|
||||||
|
window.attachEvent('onload', ready)
|
||||||
|
}
|
||||||
|
function ready() {
|
||||||
|
function html(id, h) {
|
||||||
|
document.getElementById(id).innerHTML = h
|
||||||
|
}
|
||||||
|
|
||||||
|
var discussion = document.getElementById('discussion')
|
||||||
|
, discussionToggle = document.getElementById('discussion-toggle')
|
||||||
|
, hidden = true
|
||||||
|
discussionToggle.onclick = function() {
|
||||||
|
hidden = !hidden
|
||||||
|
discussion.style.display = hidden ? 'none' : 'block'
|
||||||
|
discussionToggle.innerHTML = hidden ? '↓ show discussion ↓' : '↑ hide discussion ↑'
|
||||||
|
SJS.request({uri: 'http://bohodev.net:8000/comments/'}, function(err, body) {
|
||||||
|
html('comments', body)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<header>
|
<header>
|
||||||
<h1><a href=index.html>sjs' blog</a></h1>
|
<h1><a href=index.html>sjs' blog</a></h1>
|
||||||
|
|
@ -140,6 +162,21 @@ of the Mach-O file format</a></i><p>
|
||||||
<a id=next href=basics-of-the-mach-o-file-format.html>Basics of the Mach-O file format →</a>
|
<a id=next href=basics-of-the-mach-o-file-format.html>Basics of the Mach-O file format →</a>
|
||||||
<br style=clear:both>
|
<br style=clear:both>
|
||||||
</div>
|
</div>
|
||||||
|
<div class=center><a id=discussion-toggle href=#>↓ show discussion ↓</a></div>
|
||||||
|
<div id=discussion>
|
||||||
|
<div id=comment-form>
|
||||||
|
<form method=post action=http://bohodev.net:8000/comment>
|
||||||
|
<input name=from type=hidden value=working-with-c-style-structs-in-ruby.html>
|
||||||
|
<p>Name: <input name=name size=30></p>
|
||||||
|
<p>URL: <input name=url size=30></p>
|
||||||
|
<p>Thoughts: <textarea name=body cols=40 rows=5></textarea></p>
|
||||||
|
<p><input type=submit value=Add to discussion></p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id=comments>
|
||||||
|
<img id=discussion-spinner src=../assets/spinner.gif>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<a href=https://twitter.com/_sjs>@_sjs</a>
|
<a href=https://twitter.com/_sjs>@_sjs</a>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
174
discussd/discussd.js
Executable file
174
discussd/discussd.js
Executable file
|
|
@ -0,0 +1,174 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
var fs = require('fs')
|
||||||
|
, http = require('http')
|
||||||
|
, keys = require('keys')
|
||||||
|
, DefaultOptions = { host: 'localhost'
|
||||||
|
, port: 2020
|
||||||
|
, postsFile: 'posts.json'
|
||||||
|
}
|
||||||
|
|
||||||
|
function main() {
|
||||||
|
var options = parseArgs(DefaultOptions)
|
||||||
|
, db = new keys.Dirty('./discuss.dirty')
|
||||||
|
, context = { db: db
|
||||||
|
, posts: null
|
||||||
|
}
|
||||||
|
, server = http.createServer(requestHandler(context))
|
||||||
|
, loadPosts = function(cb) {
|
||||||
|
readJSON(options.postsFile, function(err, posts) {
|
||||||
|
if (err) {
|
||||||
|
console.error('failed to parse posts file, is it valid JSON?')
|
||||||
|
console.dir(e)
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
context.posts = posts.published
|
||||||
|
var n = context.posts.length
|
||||||
|
console.log((context.posts === null ? '' : 're') + 'loaded ' + n + ' posts...')
|
||||||
|
if (typeof cb == 'function') cb()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
, listen = function() {
|
||||||
|
console.log(process.argv[0] + ' listening on ' + options.host + ':' + options.port)
|
||||||
|
server.listen(options.port, options.host)
|
||||||
|
}
|
||||||
|
loadPosts(function() {
|
||||||
|
fs.watchFile(options.postsFile, loadPosts)
|
||||||
|
if (db._loaded) {
|
||||||
|
listen()
|
||||||
|
} else {
|
||||||
|
db.db.on('load', listen)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function readJSON(f, cb) {
|
||||||
|
fs.readFile(f, function(err, buf) {
|
||||||
|
var data
|
||||||
|
if (!err) {
|
||||||
|
try {
|
||||||
|
data = JSON.parse(buf.toString())
|
||||||
|
} catch (e) {
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cb(err, data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestHandler(context) {
|
||||||
|
function addComment(data) {
|
||||||
|
if (missingParams(data) || context.posts.indexOf(data.post) === -1) {
|
||||||
|
console.log('missing params or invalid post title in ' + JSON.stringify(data, null, 2))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
var comments = context.db.get(data.post) || []
|
||||||
|
comments.push({ name: data.name
|
||||||
|
, email: data.email
|
||||||
|
, body: data.body
|
||||||
|
, timestamp: Date.now()
|
||||||
|
})
|
||||||
|
context.db.set(data.post, comments)
|
||||||
|
console.log('[' + new Date() + '] add comment ' + JSON.stringify(data, null, 2))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return function(req, res) {
|
||||||
|
var body = ''
|
||||||
|
, m
|
||||||
|
if (req.method === 'POST' && req.url.match(/^\/comment\/?$/)) {
|
||||||
|
req.on('data', function(chunk) { body += chunk })
|
||||||
|
req.on('end', function() {
|
||||||
|
var data
|
||||||
|
try {
|
||||||
|
data = JSON.parse(body)
|
||||||
|
} catch (x) {
|
||||||
|
badRequest(res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!addComment(data)) {
|
||||||
|
badRequest(res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.writeHead(204)
|
||||||
|
res.end()
|
||||||
|
// TODO mail watchers about the comment
|
||||||
|
})
|
||||||
|
} else if (req.method === 'GET' && (m = req.url.match(/^\/comments\/(.*)$/))) {
|
||||||
|
var post = m[1]
|
||||||
|
, comments
|
||||||
|
, s
|
||||||
|
if (context.posts.indexOf(post) === -1) {
|
||||||
|
badRequest(res)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
comments = context.db.get(post) || []
|
||||||
|
s = JSON.stringify({comments: comments})
|
||||||
|
res.writeHead(200, { 'content-type': 'appliaction/json'
|
||||||
|
, 'content-length': s.length
|
||||||
|
})
|
||||||
|
res.end(s)
|
||||||
|
} else {
|
||||||
|
console.log('unhandled request')
|
||||||
|
console.dir(req)
|
||||||
|
badRequest(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseArgs(defaults) {
|
||||||
|
var expectingArg
|
||||||
|
, options = Object.keys(defaults).reduce(function(os, k) {
|
||||||
|
os[k] = defaults[k]
|
||||||
|
return os
|
||||||
|
}, {})
|
||||||
|
process.argv.slice(2).forEach(function(arg) {
|
||||||
|
if (expectingArg) {
|
||||||
|
options[expectingArg] = arg
|
||||||
|
expectingArg = null
|
||||||
|
} else {
|
||||||
|
// remove leading dashes
|
||||||
|
while (arg.charAt(0) === '-') {
|
||||||
|
arg = arg.slice(1)
|
||||||
|
}
|
||||||
|
switch (arg) {
|
||||||
|
case 'h':
|
||||||
|
case 'host':
|
||||||
|
expectingArg = 'host'
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
case 'port':
|
||||||
|
expectingArg = 'port'
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.warn('unknown option: ' + arg + ' (setting anyway)')
|
||||||
|
expectingArg = arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return options
|
||||||
|
}
|
||||||
|
|
||||||
|
function badRequest(res) {
|
||||||
|
var s = 'bad request'
|
||||||
|
res.writeHead(400, { 'content-type': 'text/plain'
|
||||||
|
, 'content-length': s.length
|
||||||
|
})
|
||||||
|
res.end(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
var missingParams = (function() {
|
||||||
|
var requiredParams = 'name email body'.split(' ')
|
||||||
|
return function(d) {
|
||||||
|
var anyMissing = false
|
||||||
|
requiredParams.forEach(function(p) {
|
||||||
|
var v = (d[p] || '').trim()
|
||||||
|
if (!v) anyMissing = true
|
||||||
|
})
|
||||||
|
return anyMissing
|
||||||
|
}
|
||||||
|
}())
|
||||||
|
|
||||||
|
if (module == require.main) main()
|
||||||
|
|
@ -14,6 +14,30 @@ _gaq.push( ['_setAccount', 'UA-214054-5']
|
||||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||||
})();
|
})();
|
||||||
|
{{#comments}}
|
||||||
|
if (document.addEventListener) {
|
||||||
|
document.addEventListener('DOMContentLoaded', ready, false)
|
||||||
|
} else if (window.attachEvent) {
|
||||||
|
window.attachEvent('onload', ready)
|
||||||
|
}
|
||||||
|
function ready() {
|
||||||
|
function html(id, h) {
|
||||||
|
document.getElementById(id).innerHTML = h
|
||||||
|
}
|
||||||
|
|
||||||
|
var discussion = document.getElementById('discussion')
|
||||||
|
, discussionToggle = document.getElementById('discussion-toggle')
|
||||||
|
, hidden = true
|
||||||
|
discussionToggle.onclick = function() {
|
||||||
|
hidden = !hidden
|
||||||
|
discussion.style.display = hidden ? 'none' : 'block'
|
||||||
|
discussionToggle.innerHTML = hidden ? '↓ show discussion ↓' : '↑ hide discussion ↑'
|
||||||
|
SJS.request({uri: 'http://bohodev.net:8000/comments/{{filename}}'}, function(err, body) {
|
||||||
|
html('comments', body)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{/comments}}
|
||||||
</script>
|
</script>
|
||||||
<header>
|
<header>
|
||||||
<h1><a href=index.html>sjs' blog</a></h1>
|
<h1><a href=index.html>sjs' blog</a></h1>
|
||||||
|
|
@ -40,6 +64,23 @@ _gaq.push( ['_setAccount', 'UA-214054-5']
|
||||||
{{/next}}
|
{{/next}}
|
||||||
<br style=clear:both>
|
<br style=clear:both>
|
||||||
</div>
|
</div>
|
||||||
|
<div class=center><a id=discussion-toggle href=#>↓ show discussion ↓</a></div>
|
||||||
|
{{#comments}}
|
||||||
|
<div id=discussion>
|
||||||
|
<div id=comment-form>
|
||||||
|
<form method=post action=http://bohodev.net:8000/comment>
|
||||||
|
<input name=from type=hidden value={{#post}}{{filename}}{{/post}}>
|
||||||
|
<p>Name: <input name=name size=30></p>
|
||||||
|
<p>URL: <input name=url size=30></p>
|
||||||
|
<p>Thoughts: <textarea name=body cols=40 rows=5></textarea></p>
|
||||||
|
<p><input type=submit value=Add to discussion></p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id=comments>
|
||||||
|
<img id=discussion-spinner src=../assets/spinner.gif>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/comments}}
|
||||||
<footer>
|
<footer>
|
||||||
<a href=https://twitter.com/_sjs>@_sjs</a>
|
<a href=https://twitter.com/_sjs>@_sjs</a>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue