rc-web@69
|
1 var handlebars = require('handlebars'),
|
rc-web@69
|
2 async = require('async'),
|
rc-web@69
|
3 cheerio = require('cheerio'),
|
rc-web@69
|
4 marked = require('marked'),
|
rc-web@69
|
5 path = require('path'),
|
rc-web@69
|
6 fs = require('fs'),
|
rc-web@69
|
7 _ = require('underscore'),
|
rc-web@69
|
8 highlight = require('highlight.js');
|
rc-web@69
|
9
|
rc-web@69
|
10 var config = {
|
rc-web@69
|
11 addIdsToHeadings: true,
|
rc-web@69
|
12 gfm: true, //github flavored markdown
|
rc-web@69
|
13 highlight: function(code, lang) {
|
rc-web@69
|
14 return highlight.highlight('javascript', code).value;
|
rc-web@69
|
15 }
|
rc-web@69
|
16 };
|
rc-web@69
|
17
|
rc-web@69
|
18 var jqueryPath = './lib/jquery.js',
|
rc-web@69
|
19 asyncTolkens = {},
|
rc-web@69
|
20 markdownCallbacks = [];
|
rc-web@69
|
21
|
rc-web@69
|
22 var transforms = {};
|
rc-web@69
|
23
|
rc-web@69
|
24 function addTransform(name, callback) {
|
rc-web@69
|
25 transforms[name] = callback;
|
rc-web@69
|
26 }
|
rc-web@69
|
27
|
rc-web@69
|
28 addTransform('html', function(buffer, complete, context, data) {
|
rc-web@69
|
29 return complete(buffer.toString());
|
rc-web@69
|
30 });
|
rc-web@69
|
31
|
rc-web@69
|
32 addTransform('md', function(buffer, complete, context, data) {
|
rc-web@69
|
33 var html = marked(buffer.toString(), {
|
rc-web@69
|
34 gfm: config.gfm,
|
rc-web@69
|
35 highlight: config.highlight
|
rc-web@69
|
36 });
|
rc-web@69
|
37 async.series(_.map(markdownCallbacks, function(callback) {
|
rc-web@69
|
38 return function(next) {
|
rc-web@69
|
39 callback(html, function(modifiedHTML) {
|
rc-web@69
|
40 html = modifiedHTML;
|
rc-web@69
|
41 next();
|
rc-web@69
|
42 });
|
rc-web@69
|
43 }
|
rc-web@69
|
44 }), function() {
|
rc-web@69
|
45 complete(html);
|
rc-web@69
|
46 });
|
rc-web@69
|
47 });
|
rc-web@69
|
48
|
rc-web@69
|
49 addTransform('hbs', function(buffer, complete, context, data) {
|
rc-web@69
|
50 var output = handlebars.compile(buffer.toString(), {
|
rc-web@69
|
51 data: true
|
rc-web@69
|
52 })(context, {
|
rc-web@69
|
53 data: data
|
rc-web@69
|
54 });
|
rc-web@69
|
55 var filteredAsyncTolkens = {};
|
rc-web@69
|
56 _.each(asyncTolkens, function(tolkenData, tolken) {
|
rc-web@69
|
57 if (data.file === tolkenData.file) {
|
rc-web@69
|
58 filteredAsyncTolkens[tolken] = tolkenData;
|
rc-web@69
|
59 }
|
rc-web@69
|
60 });
|
rc-web@69
|
61 if (!_.keys(filteredAsyncTolkens).length) {
|
rc-web@69
|
62 complete(output);
|
rc-web@69
|
63 } else {
|
rc-web@69
|
64 async.series(_.map(filteredAsyncTolkens, function(tolkenData, tolken) {
|
rc-web@69
|
65 return function(next) {
|
rc-web@69
|
66 var args = tolkenData.args;
|
rc-web@69
|
67 args.push(function(callbackOutput) {
|
rc-web@69
|
68 output = output.replace(tolken, callbackOutput.toString());
|
rc-web@69
|
69 next();
|
rc-web@69
|
70 });
|
rc-web@69
|
71 tolkenData.callback.apply(tolkenData.callback, args);
|
rc-web@69
|
72 };
|
rc-web@69
|
73 }), function() {
|
rc-web@69
|
74 complete(output);
|
rc-web@69
|
75 });
|
rc-web@69
|
76 }
|
rc-web@69
|
77 });
|
rc-web@69
|
78
|
rc-web@69
|
79 function $(html, callback) {
|
rc-web@69
|
80 callback(cheerio.load(html));
|
rc-web@69
|
81 }
|
rc-web@69
|
82
|
rc-web@69
|
83 function modifyDocumentFragment(html, callback, next) {
|
rc-web@69
|
84 $(html, function($) {
|
rc-web@69
|
85 callback($);
|
rc-web@69
|
86 next($.html());
|
rc-web@69
|
87 });
|
rc-web@69
|
88 }
|
rc-web@69
|
89
|
rc-web@69
|
90 function removeOuterBodyTag(html) {
|
rc-web@69
|
91 return html.replace(/^\s*\<body\>/, '').replace(/\<\/body\>\s*$/, '');
|
rc-web@69
|
92 }
|
rc-web@69
|
93
|
rc-web@69
|
94 handlebars.registerAsyncHelper = function(name, callback) {
|
rc-web@69
|
95 handlebars.registerHelper(name, function() {
|
rc-web@69
|
96 var tolken = String(new Date().getTime() + Math.random());
|
rc-web@69
|
97 var args = _.toArray(arguments),
|
rc-web@69
|
98 data = args[args.length - 1].data;
|
rc-web@69
|
99 asyncTolkens[tolken] = {
|
rc-web@69
|
100 file: data.file,
|
rc-web@69
|
101 args: args,
|
rc-web@69
|
102 callback: callback
|
rc-web@69
|
103 };
|
rc-web@69
|
104 return tolken;
|
rc-web@69
|
105 });
|
rc-web@69
|
106 };
|
rc-web@69
|
107
|
rc-web@69
|
108 handlebars.registerHelper('require', function(file, options) {
|
rc-web@69
|
109 var filePath = path.join(path.dirname(options.data.file), file);
|
rc-web@69
|
110 require(filePath)(module.exports);
|
rc-web@69
|
111 return '';
|
rc-web@69
|
112 });
|
rc-web@69
|
113
|
rc-web@69
|
114 handlebars.registerAsyncHelper('include', function(file, options, callback) {
|
rc-web@69
|
115 var filePath = path.join(path.dirname(options.data.file), file);
|
rc-web@69
|
116 transform(filePath, function(fileData) {
|
rc-web@69
|
117 var selector = options.hash.select;
|
rc-web@69
|
118 if (selector) {
|
rc-web@69
|
119 $(fileData.toString(), function($) {
|
rc-web@69
|
120 var generatedHTML = '';
|
rc-web@69
|
121 $(selector).each(function() {
|
rc-web@69
|
122 // make more like a regular dom object
|
rc-web@69
|
123 this.attributes = this[0].attribs;
|
rc-web@69
|
124 this.id = this[0].attribs.id;
|
rc-web@69
|
125 this.tagName = this[0].name;
|
rc-web@69
|
126 this.innerHTML = this.html();
|
rc-web@69
|
127 generatedHTML += options.fn(this);
|
rc-web@69
|
128 });
|
rc-web@69
|
129 callback(generatedHTML);
|
rc-web@69
|
130 });
|
rc-web@69
|
131 } else {
|
rc-web@69
|
132 callback(fileData.toString());
|
rc-web@69
|
133 }
|
rc-web@69
|
134 }, options.hash, options.data);
|
rc-web@69
|
135 });
|
rc-web@69
|
136
|
rc-web@69
|
137 function transform(source, callback, options) {
|
rc-web@69
|
138 fs.readFile(source, function(err, data) {
|
rc-web@69
|
139 if (err) {
|
rc-web@69
|
140 console.trace();
|
rc-web@69
|
141 throw err;
|
rc-web@69
|
142 }
|
rc-web@69
|
143 var extensions = source.split('/').pop().split('.');
|
rc-web@69
|
144 var callbacks = _.filter(extensions, function(extension) {
|
rc-web@69
|
145 return extension in transforms;
|
rc-web@69
|
146 }).map(function(extension) {
|
rc-web@69
|
147 return function(next) {
|
rc-web@69
|
148 transforms[extension](data, next, options || {}, {
|
rc-web@69
|
149 file: source
|
rc-web@69
|
150 });
|
rc-web@69
|
151 };
|
rc-web@69
|
152 });
|
rc-web@69
|
153 async.series(callbacks, callback);
|
rc-web@69
|
154 });
|
rc-web@69
|
155 }
|
rc-web@69
|
156
|
rc-web@69
|
157 function onMarkdown(callback) {
|
rc-web@69
|
158 markdownCallbacks.push(callback);
|
rc-web@69
|
159 }
|
rc-web@69
|
160
|
rc-web@69
|
161 onMarkdown(function(html, next) {
|
rc-web@69
|
162 if (config.addIdsToHeadings) {
|
rc-web@69
|
163 modifyDocumentFragment(html, function($) {
|
rc-web@69
|
164 if (config.addIdsToHeadings) {
|
rc-web@69
|
165 addIdsToHeadings($);
|
rc-web@69
|
166 }
|
rc-web@69
|
167 }, next);
|
rc-web@69
|
168 } else {
|
rc-web@69
|
169 next(html);
|
rc-web@69
|
170 }
|
rc-web@69
|
171 });
|
rc-web@69
|
172
|
rc-web@69
|
173 function addIdsToHeadings($) {
|
rc-web@69
|
174 $('h1,h2,h3,h4,h5,h6').each(function() {
|
rc-web@69
|
175 var text = $(this).html().split('<').shift();
|
rc-web@69
|
176 var id = text.replace(/(^\s+|\s+$)/g, '').replace(/[\s]+/g, '-').replace(/([a-z])([A-Z])/g, function() {
|
rc-web@69
|
177 return arguments[1] + '-' + arguments[2].toLowerCase();
|
rc-web@69
|
178 }).toLowerCase();
|
rc-web@69
|
179 if (id.match(/^\s+$/) || !id) {
|
rc-web@69
|
180 return;
|
rc-web@69
|
181 }
|
rc-web@69
|
182 $(this).attr('id', id);
|
rc-web@69
|
183 });
|
rc-web@69
|
184 }
|
rc-web@69
|
185
|
rc-web@69
|
186 module.exports = {
|
rc-web@69
|
187 config: config,
|
rc-web@69
|
188 transform: transform,
|
rc-web@69
|
189 handlebars: handlebars,
|
rc-web@69
|
190 $: $,
|
rc-web@69
|
191 modifyDocumentFragment: modifyDocumentFragment,
|
rc-web@69
|
192 onMarkdown: onMarkdown,
|
rc-web@69
|
193 addTransform: addTransform
|
rc-web@69
|
194 }; |