Yesterday, I was able to get nearly all of the necessary pieces of a couchapp show page working correctly. Today I will try to do it a little better. Specifically, I would like to figure out rendering Textile via Javascript and re-usable templates (e.g. headers and footers) in CouchDB / couchapp show templates.
I need to be able to display Textile because that is how I edit/store recipe summaries and instructions. On the actual web site, I am simply using Redcloth (by way of Sinatra) to convert for web display.
Happily, I do not have to do much work on Javascript Textile conversion—Jeff Minard and Stuart Langridge have a working demo for doing just this. To add this code to my couchapp, I create a new
lib
directory and add the "super textile" code to lib/super_textile.js
:/*(I make a small change to the code to insert double
* Lifted from http://jrm.cc/extras/live-textile-preview.php
*
* - Jeff Minard (jeff aht creatimation daht net / http://www.jrm.cc/)
* - Stuart Langridge (http://www.kryogenix.org/)
*
*/
function superTextile(s) {
var r = s;
// quick tags first
var qtags = [['\\*', 'strong'],
['\\?\\?', 'cite'],
['\\+', 'ins'], //fixed
['~', 'sub'],
['\\^', 'sup'], // me
['@', 'code']];
// do all sorts of stuff to "r"...
return r;
}
<br>
tags after paragraphs)To use that function, I pull it into my recipe.js show function with a couchapp
!code
directive and then, er, use it:function(doc, req) {It is a simple matter to use those new template variables:
// !json templates.recipe
// !code vendor/couchapp/template.js
// !code vendor/couchapp/path.js
// !code lib/super_textile.js
var image;
for (var prop in doc._attachments) {
image = prop;
}
return template(templates.recipe, {
title: doc.title,
docid: (doc && doc._id),
asset_path: assetPath(),
summary: superTextile(doc.summary),
instructions: superTextile(doc.instructions),
image: image
});
}
<!DOCTYPE html>After uploading the couchapp to my DB, I see nicely formatted textile:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Recipe: <%= title %></title>
<link rel="stylesheet" href="<%= asset_path %>/style/main.css" type="text/css" />
</head>
<body>
<h1><%= title %></h1>
<%= summary %>
<%= instructions %>
<img src="../../../../<%= docid %>/<%= image %>" />
</body>
</html>
Easy enough.
To add a header and footer, I first create them in the
templates
directory. I will follow the Rails convention of prefixing partial templates with an underscore, so I create templates/_header.html
and templates/_footer.html
. To include these in the show function, I again use the couchapp !json
directive. To render, I will send()
chunks of HTML (first the header, the the main template) to the browser and finally return the footer to be sent last to the browser:function(doc, req) {After pushing my couchapp to my recipes DB, I find this in the browser:
// !json templates.recipe
// !json templates._header
// !json templates._footer
// !code vendor/couchapp/template.js
// !code vendor/couchapp/path.js
// !code lib/super_textile.js
var image;
for (var prop in doc._attachments) {
image = prop;
}
send(template(templates._header, {}));
send(template(templates.recipe, {
title: doc.title,
docid: (doc && doc._id),
asset_path: assetPath(),
summary: superTextile(doc.summary),
instructions: superTextile(doc.instructions),
image: image
}));
return template(templates._footer, {});
}
Ugh. Not quite what I was hoping for.
I believe that this is an indication that
send()
only works in list functions. It makes sense to send data in chunks in a list function—especially if there are many chunks. I expected it to work in the show functions as well. No matter, I can concatenate the template outputs together easily enough (flog scores be damned):return template(templates._header, {}) +Now when I load the page, I find:
template(templates.recipe, {
title: doc.title,
docid: (doc && doc._id),
asset_path: assetPath(),
summary: superTextile(doc.summary),
instructions: superTextile(doc.instructions),
image: image
}) +
template(templates._footer, {});
Much better.
Tomorrow: updating documents with couchapp.
Day #18
BTW, in the soon-to-be-released CouchDB 0.11 you'll be able to use the list-style API, such as send(), from your show functions.
ReplyDeletehttp://github.com/apache/couchdb/commit/15d10793a32a5fa57c80e9eab8803dc7d284ca6d
Good to know. I did eventually grok that send() is better suited to list functions. Even so, this newbie found it confusing. Hopefully that addition to 0.11 will help future newbies avoid similar confusion. Also, there may be some legit reasons for send() in show functions as well.
ReplyDeleteThanks!