forked from jdan/cleaver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcleaver.js
175 lines (140 loc) · 4.17 KB
/
cleaver.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
var fs = require('fs');
var Q = require('q');
var path = require('path');
var md = require('node-markdown').Markdown;
var yaml = require('js-yaml');
var mustache = require('mustache');
var helper = require('./helper');
function Cleaver(file) {
this.file = file
if (!file) throw "!! Please specify a file to parse";
// TODO: make these constants?
this.templates = {
main: 'layout.mustache',
author: 'author.mustache',
agenda: 'agenda.mustache'
};
this.resources = {
style: 'default.css',
navigation: 'navigation.js'
};
this.external = {
document: file
};
this.metadata = null;
this.slides = [];
}
/**
* Renders the document
*/
Cleaver.prototype._parseDocument = function () {
var self = this;
return Q.all([
helper.load(this.external),
helper.load(this.templates, 'templates')
])
.then(function (data) {
var slices = self._slice(self.external.loaded.document);
self.metadata = yaml.safeLoad(slices[0]);
for (var i = 1; i < slices.length; i++) {
self.slides.push(md(slices[i]));
}
// insert an author slide (if necessary) at the end
if (self.metadata.author) {
self.slides.push(self._renderAuthorSlide(self.metadata.author));
}
// insert an agenda slide (if necessary) as our second slide
if (self.metadata.agenda) {
self.slides.splice(1, 0, self._renderAgendaSlide(slices));
}
// maybe load an external stylesheet
if (self.metadata.style) {
return helper.loadSingle(self.metadata.style)
.then(function (data) {
self.external.loaded.style = data;
})
}
});
}
/**
* Loads the templates, default stylesheet, and any external stylesheets
* as defined by the user.
* @return {Promise.<Array.<Object>>}
*/
Cleaver.prototype._loadAssets = function () {
return Q.all([
helper.load(this.resources, 'resources')
]);
}
/**
* Renders the slideshow
*/
Cleaver.prototype._renderSlideshow = function () {
var putControls = this.metadata.controls || (this.metadata.controls === undefined);
var outputLocation = this.metadata.output || path.basename(this.file, '.md') + '-cleaver.html';
var title = this.metadata.title || 'Untitled';
var slideData = {
slides: this.slides,
title: title,
controls: putControls,
style: this.resources.loaded.style,
externalStyle: this.external.loaded.style,
// TODO: uglify navigation.js?
navigation: this.resources.loaded.navigation
};
return helper.save(outputLocation, mustache.render(this.templates.loaded.main, slideData));
}
/**
* Renders the author slide
* @param {string} authorData The author field of the slideshow metadata
* @return {string} The formatted author slide
*/
Cleaver.prototype._renderAuthorSlide = function (authorData) {
return mustache.render(this.templates.loaded.author, authorData);
}
/*
* Renders the agenda slide
* @param {string} slices The set of slices that had been loaded from the input file
* @return {string} The formatted agenda slide
*/
Cleaver.prototype._renderAgendaSlide = function (slices) {
var titles = [];
var firstLine, lastTitle, matches;
for (var i = 1; i < slices.length; i++) {
firstLine = slices[i].split(/(\n|\r)+/)[0];
matches = /^(#{3,})\s+(.+)$/.exec(firstLine);
// Only index non-title slides (begins with 3 ###)
if (!matches) continue;
if (lastTitle != matches[2]) {
lastTitle = matches[2];
titles.push(lastTitle);
}
}
return mustache.render(this.templates.loaded.agenda, titles);
}
/**
* Returns a chopped up document that's easy to parse
* @param {string} The full document
* @return {Array.<string>} A list of all slides
*/
Cleaver.prototype._slice = function(document) {
var cuts = document.split(/\r?\n--\r?\n/);
var slices = [];
for (var i = 0; i < cuts.length; i++) {
slices.push(cuts[i].trim());
}
return slices;
}
/**
* Method to run the whole show
*/
Cleaver.prototype.run = function () {
var self = this;
Q.all([this._parseDocument(), this._loadAssets()])
.then(self._renderSlideshow.bind(self))
.fail(function (err) {
throw err;
})
.done();
}
module.exports = Cleaver;