Permalink
Browse files

* Support new extended Markdown syntax for classes and figures

  • Loading branch information...
joehewitt committed Nov 3, 2011
1 parent 6aa29d6 commit 1816d6dbf901ea9135c2f6c698d8252f4876308c
Showing with 335 additions and 39 deletions.
  1. +6 −6 lib/Blog.js
  2. +0 −26 lib/ImageEmbedder.js
  3. +1 −1 lib/ImageTransformer.js
  4. +159 −0 lib/NerveTransformer.js
  5. +98 −1 test/blogs/c/posts.md
  6. +71 −5 test/nerve-test.js
View
@@ -17,7 +17,7 @@ var abind = require('dandy/errors').abind;
var ibind = require('dandy/errors').ibind;
var NerveAPI = require('./NerveAPI').NerveAPI;
var Post = require('./Post').Post;
-var ImageEmbedder = require('./ImageEmbedder').ImageEmbedder;
+var NerveTransformer = require('./NerveTransformer').NerveTransformer;
var syndicate = require('./syndicate');
// *************************************************************************************************
@@ -509,16 +509,16 @@ subclass(Blog, events.EventEmitter, {
},
renderPost: function(post, cb) {
- // Replaces images with embeds
- var embedder = new ImageEmbedder(this);
- embedder.visit(post.tree);
+ // Performs nerve-specific parsing
+ var transformer = new NerveTransformer(this);
+ transformer.visit(post.tree);
- if (!embedder.embeds.length) {
+ if (!transformer.embeds.length) {
post.body = markdom.toHTML(post.tree);
cb(0, post);
} else {
// Asynchronously render each of the embeds
- async.mapSeries(embedder.embeds,
+ async.mapSeries(transformer.embeds,
_.bind(function(embed, cb2) {
this.renderEmbed(embed, post, cb2);
}, this),
View
@@ -1,26 +0,0 @@
-
-var _ = require('underscore');
-var markdom = require('markdom');
-
-// *************************************************************************************************
-
-function ImageEmbedder(blog) {
- this.blog = blog;
- this.embeds = [];
-}
-
-ImageEmbedder.prototype = _.extend(new markdom.NodeTransformer(), {
- image: function(node) {
- var m = this.blog.matchTransform(node.url);
- if (m) {
- var embed = new markdom.nodeTypes.Embed(node.url, node.title, node.alt, m.groups,
- m.transform, m.query);
- this.embeds.push(embed);
- return embed;
- } else {
- return node;
- }
- },
-});
-
-exports.ImageEmbedder = ImageEmbedder;
View
@@ -19,12 +19,12 @@ ImageTransformer.prototype = {
var parts = url.split(/\s+/);
var relativePath = parts[0];
- var reOptions = /(center|start|end)|(\d+px)/;
var options = {
width: 0,
height: 0,
align: '',
};
+ var reOptions = /(center|start|end)|(\d+px)/;
for (var i = 1; i < parts.length; ++i) {
var m = reOptions.exec(parts[i]);
if (m) {
View
@@ -0,0 +1,159 @@
+
+var _ = require('underscore');
+var markdom = require('markdom'),
+ Header = markdom.nodeTypes.Header,
+ HRule = markdom.nodeTypes.HRule,
+ Span = markdom.nodeTypes.Span,
+ Block = markdom.nodeTypes.Block,
+ Embed = markdom.nodeTypes.Embed,
+ NodeSet = markdom.nodeTypes.NodeSet;
+
+// *************************************************************************************************
+
+var reMetadata = /^((.|\n)*?)\s*\((([\.@][A-Za-z0-9\/_-]+\s*)+)\)\s*$/;
+var reFigure = /@[A-Za-z0-9\.\/_-]+/;
+var reStyle = /(\.[A-Za-z0-9_-]+)+/;
+
+// *************************************************************************************************
+
+function NerveTransformer(blog) {
+ this.blog = blog;
+ this.embeds = [];
+}
+
+NerveTransformer.prototype = _.extend(new markdom.NodeTransformer(), {
+ nodeSet: function(nodeSet) {
+ var newNodes = [];
+ var stack = [];
+
+ function push(newNode) {
+ if (stack.length) {
+ stack[stack.length-1].content.nodes.push(newNode);
+ } else {
+ newNodes.push(newNode);
+ }
+ }
+
+ function findClasses(node) {
+ if (node.content && node.content.nodes) {
+ var lastChild = node.content.nodes[node.content.nodes.length-1];
+ if (lastChild && lastChild.classes) {
+ return lastChild.classes;
+ }
+ }
+ }
+
+ for (var i = 0; i < nodeSet.nodes.length; ++i) {
+ var node = this.visit(nodeSet.nodes[i]);
+ if (node instanceof Header && node.content && node.content.nodes.length == 1) {
+ var classes = findClasses(node);
+ if (classes) {
+ var block = new Block(new NodeSet());
+ block.classes = classes;
+ push(block);
+ stack.push(block);
+ } else {
+ push(node);
+ }
+ } else if (node instanceof HRule) {
+ if (stack.length) {
+ stack.pop();
+ } else {
+ push(node);
+ }
+ } else {
+ push(node);
+ }
+ }
+ nodeSet.nodes = newNodes;
+
+ return nodeSet;
+ },
+
+ image: function(node) {
+ var m = this.blog.matchTransform(node.url);
+ if (m) {
+ var embed = new Embed(node.url, node.title, node.alt, m.groups, m.transform, m.query);
+ this.embeds.push(embed);
+ return embed;
+ } else {
+ return node;
+ }
+ },
+
+ text: function(node) {
+ parseStyling(node);
+ return node;
+ },
+
+ blockCode: function(node) {
+ parseStyling(node);
+ return node;
+ },
+
+ link: function(node) {
+ var result = parseClasses(node.url);
+ if (result.classes) {
+ var span = new Span(node.content);
+ if (node.title) {
+ span.setAttribute('title', node.title);
+ }
+ span.classes = result.classes;
+ return span;
+ }
+ return node;
+ }
+});
+
+exports.NerveTransformer = NerveTransformer;
+
+function parseStyling(node) {
+ var m = reMetadata.exec(node.text);
+ if (m) {
+ node.text = node.text.slice(0, m.index+m[1].length);
+
+ var result = parseClasses(m[3]);
+ node.classes = result.classes;
+
+ if (result.figure && result.figure.length) {
+ var projectName, figureName;
+ if (result.figure.length == 1) {
+ projectName = figureName = result.figure[0];
+ } else {
+ projectName = result.figure[0];
+ figureName = result.figure[1];
+ }
+
+ node.figure = result.figure;
+ node.addClass('figure');
+ node.setAttribute('require', projectName);
+ node.setAttribute('figure', figureName);
+ }
+ }
+}
+
+function parseClasses(text) {
+ var classes = [];
+ var figure;
+ if (text) {
+ var parts = text.split(/\s+/);
+ for (var i = 0; i < parts.length; ++i) {
+ var m = reFigure.exec(parts[i]);
+ if (m) {
+ figure = m[0].slice(1).split('/');
+ } else {
+ m = reStyle.exec(parts[i]);
+ if (m) {
+ var partClasses = m[0].split('.').slice(1);
+ classes.push.apply(classes, partClasses);
+ }
+ }
+ }
+ }
+
+ var result = {figure: figure};
+ if (classes.length) {
+ result.classes = classes;
+ }
+ return result;
+}
View
@@ -11,5 +11,102 @@ Post 2 [11/1/11]
Post 3 [11/1/11]
=====
-![](salvia.jpg 200px 100px "The title")
+This is text. (.ignore.this) This is more text. (.styled.post)
+
+Post 4 [11/1/11]
+=====
+
+This is a line (and this is not styling)
+
+Post 5 [11/1/11]
+=====
+
+* This is a list item (.styled)
+
+Post 6 [11/1/11]
+=====
+
+> This is a blockquote
+> and it is
+> (.styled)
+
+Post 7 [11/1/11]
+=====
+
+ This is a code block
+ and it is
+
+ (.styled)
+
+Post 8 [11/1/11]
+======
+
+This is an [example of how](.styled) spans can be styled.
+
+Post 9 [11/1/11]
+======
+
+This is an [example of complex content ![](http://foo.com/foo.jpg)](.styled) inside a styled span.
+
+Post 9 [11/1/11]
+======
+
+This is a [span with a title](.styled "the title").
+
+Post 10 [11/1/11]
+=======
+
+Monkey see.
+
+(.section)
+---------
+
+One banana.
+
+Two bananas.
+
+----------
+
+Monkey do.
+
+
+Post 11 [11/1/11]
+=======
+
+Monkey see.
+
+(.section)
+---------
+
+One banana.
+
+(.nested)
+---------
+
+1.5 banana
+
+---------
+
+Two bananas.
+
+----------
+
+Monkey do.
+
+
+Post 12 [11/1/11]
+==========
+
+Simple figure. (@example)
+
+Figure with dot. (@example.com)
+
+Figure with slash. (@example.com/bar)
+
+Figure and class names. (@example.com .foo.bar)
+
+Post 13 [11/1/11]
+==========
+Line 1 (.line1)
+Line 2 (.line2)
Oops, something went wrong.

0 comments on commit 1816d6d

Please sign in to comment.