diff --git a/bin/cleaver b/bin/cleaver
index 3e3898c..93fbbd8 100755
--- a/bin/cleaver
+++ b/bin/cleaver
@@ -9,14 +9,14 @@ var Cleaver;
* Helper function to use the cleaver API to create and save a new
* presentation
*/
-function createAndSave(file) {
+function createAndSave(file, options) {
fs.readFile(file, 'utf-8', function (err, contents) {
- var presentation = new Cleaver(contents, path.resolve(path.dirname(file)));
+ var presentation = new Cleaver(contents, options, path.resolve(path.dirname(file)));
var promise = presentation.run();
promise
.then(function (product) {
- var outputFile = presentation.metadata.output || path.basename(file, '.md') + '-cleaver.html';
+ var outputFile = presentation.options.output || path.basename(file, '.md') + '-cleaver.html';
fs.writeFile(outputFile, product);
})
.fail(function (err) {
@@ -38,7 +38,7 @@ program
.description('Watch for changes on markdown file')
.action(function () {
var file = program.args[0];
- createAndSave(file);
+ createAndSave(file, parsedOpts);
console.log('Watching for changes on ' + file + '. Ctrl-C to abort.');
fs.watchFile(file, { persistent: true, interval: 100 }, function () {
@@ -48,11 +48,43 @@ program
});
program
+ .option('--title
', 'The title of the rendered document ' +
+ '(default: Untitled')
+ // TODO: author options
+ .option('--theme ', 'An theme to load')
+ .option('--style ', 'A particular stylesheet to load')
+ .option('--output ', 'The filename of the rendered document ' +
+ '(default: [INPUT]-cleaver.html)')
+ .option('--controls', 'Whether or not to include simple navigation ' +
+ 'controls in your presentation (default: true)')
+ .option('--progress', 'Option to display a small progress bar at the top ' +
+ 'of your presentation (default: true)')
+ .option('--encoding ', 'Content encoding used for the rendered ' +
+ 'document (default: utf-8)')
+ .option('--template ', 'URL or path to a mustache template used for ' +
+ 'individual slides')
+ .option('--layout ', 'URL or path to a mustache template used to ' +
+ 'render the entire presentation')
.option('--debug', 'Enable debug output');
program.parse(process.argv);
+// TODO: a lot of code duplication here
+var parsedOpts = {
+ title: program.title,
+ theme: program.theme,
+ style: program.style,
+ output: program.output,
+ controls: program.controls,
+ progress: program.progress,
+ encoding: program.encoding,
+ template: program.template,
+ layout: program.layout,
+ debug: program.debug
+};
+
if (!program.args.length) {
+ // TODO: custom help screen
program.help();
} else {
/**
@@ -71,5 +103,5 @@ if (!program.args.length) {
// Load cleaver with the new ENV for debugging
// TODO: This seems a little janky, maybe handle this in lib/
Cleaver = require('../');
- createAndSave(program.args[0]);
+ createAndSave(program.args[0], parsedOpts);
}
diff --git a/docs/options.md b/docs/options.md
index 4f34f19..08fdcef 100644
--- a/docs/options.md
+++ b/docs/options.md
@@ -19,7 +19,7 @@ YAML format. A typical option setup resembles the following.
### title
-The title of the slidshow.
+The title of the rendered document.
**Default**: Untitled
@@ -90,13 +90,13 @@ Content encoding to use on the rendered document.
### template
-URL or absolute/relative path to a mustache template used to render the slides.
+URL or path to a mustache template used to render the slides.
See [default.mustache](https://github.com/jdan/cleaver/blob/master/templates/default.mustache)
for inspiration.
### layout
-URL or absolute/relative path to a mustache template used to render the entire
+URL or path to a mustache template used to render the entire
slideshow. See
[layout.mustache](https://github.com/jdan/cleaver/blob/master/templates/layout.mustache)
for inspiration.
diff --git a/lib/index.js b/lib/index.js
index 7c7b74d..25a552b 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -13,12 +13,19 @@ var helper;
* include external dependencies (stylesheets, scripts, etc)
*
* @param {string} document The input document
+ * @param {!Object} options Optional settings object to overwrite the options
+ * listed in the cleaver document
* @param {!string} includePath Optional resource path (default: '.')
* @constructor
*/
-function Cleaver(document, includePath) {
+function Cleaver(document, options, includePath) {
this.document = document.toString();
+ this.options = options || {};
this.path = path.resolve(includePath || '.');
+ /**
+ * Require helper using `this.path` as a context for where to locate any
+ * specified assets
+ */
helper = require('./helper')(this.path);
this.templates = {
@@ -37,7 +44,6 @@ function Cleaver(document, includePath) {
style: []
};
- this.metadata = null;
this.slides = [];
this.override = false;
@@ -68,16 +74,21 @@ Cleaver.prototype.loadDocument = function () {
/**
- * Parses the metadata and renders the slides.
+ * Parses the options and renders the slides.
*
* @return {Promise}
*/
Cleaver.prototype.renderSlides = function () {
var slices = this.slice(this.document);
- var i;
+ var i, options;
- this.metadata = yaml.safeLoad(slices[0].content) || {};
- debug('parsed metadata');
+ options = yaml.safeLoad(slices[0].content) || {};
+ // Load any options that are not already present from the constructor
+ for (i in options) {
+ this.options[i] = this.options[i] || options[i];
+ }
+
+ debug('parsed options');
for (i = 1; i < slices.length; i++) {
this.slides.push({
@@ -89,16 +100,16 @@ Cleaver.prototype.renderSlides = function () {
}
// insert an author slide (if necessary) at the end
- if (this.metadata.author) {
- if (this.metadata.author.twitter &&
- !this.metadata.author.twitter.match(/^@/)) {
- this.metadata.author.twitter = '@' + this.metadata.author.twitter;
+ if (this.options.author) {
+ var twitter = this.options.author.twitter;
+ if (twitter && !twitter.match(/^@/)) {
+ this.options.author.twitter = '@' + this.options.author.twitter;
}
this.slides.push({
id: i,
hidden: true,
- content: this.renderAuthorSlide(this.metadata.author)
+ content: this.renderAuthorSlide(this.options.author)
});
}
@@ -107,7 +118,7 @@ Cleaver.prototype.renderSlides = function () {
/**
- * Populates `slides` and some extra loaded content, based on the metadata
+ * Populates `slides` and some extra loaded content, based on the options
* listed in the document.
*
* @return {Promise}
@@ -116,24 +127,24 @@ Cleaver.prototype.populateResources = function () {
var promises = [];
// maybe load an external stylesheet
- if (this.metadata.style) {
- promises.push(helper.populateSingle(this.metadata.style, this.external, 'style')
+ if (this.options.style) {
+ promises.push(helper.populateSingle(this.options.style, this.external, 'style')
.then(function () {
debug('loaded user stylesheet');
}));
}
// maybe load an external template
- if (this.metadata.template) {
- promises.push(helper.populateSingle(this.metadata.template, this.templates, 'slides')
+ if (this.options.template) {
+ promises.push(helper.populateSingle(this.options.template, this.templates, 'slides')
.then(function () {
debug('loaded user template');
}));
}
// maybe load an external layout
- if (this.metadata.layout) {
- promises.push(helper.populateSingle(this.metadata.layout, this.templates, 'layout')
+ if (this.options.layout) {
+ promises.push(helper.populateSingle(this.options.layout, this.templates, 'layout')
.then(function () {
debug('loaded user layout');
}));
@@ -150,8 +161,8 @@ Cleaver.prototype.populateResources = function () {
*/
Cleaver.prototype.populateThemeResources = function () {
// maybe load a theme
- if (this.metadata.theme) {
- return helper.loadTheme(this.metadata.theme, this).then(function () {
+ if (this.options.theme) {
+ return helper.loadTheme(this.options.theme, this).then(function () {
debug('loaded theme');
});
}
@@ -179,8 +190,8 @@ Cleaver.prototype.loadStaticAssets = function () {
* @return {Promise}
*/
Cleaver.prototype.renderSlideshow = function () {
- var putControls = this.metadata.controls || (this.metadata.controls === undefined);
- var putProgress = this.metadata.progress || (this.metadata.progress === undefined);
+ var putControls = this.options.controls || (this.options.controls === undefined);
+ var putProgress = this.options.progress || (this.options.progress === undefined);
var style, script, output;
// Render the slides in a template (maybe as specified by the user)
@@ -193,8 +204,8 @@ Cleaver.prototype.renderSlideshow = function () {
debug('rendered slides');
// TODO: handle defaults gracefully
- var title = this.metadata.title || 'Untitled';
- var encoding = this.metadata.encoding || 'utf-8';
+ var title = this.options.title || 'Untitled';
+ var encoding = this.options.encoding || 'utf-8';
if (this.override && this.external.loaded.style) {
style = this.external.loaded.style && this.external.loaded.style.join('\n');
@@ -221,9 +232,9 @@ Cleaver.prototype.renderSlideshow = function () {
title: title,
encoding: encoding,
style: style,
- author: this.metadata.author,
+ author: this.options.author,
script: script,
- metadata: this.metadata
+ options: this.options
};
/* Return the rendered slideshow */
@@ -249,7 +260,7 @@ Cleaver.prototype.renderSlide = function (content) {
/**
* Renders the author slide.
*
- * @param {string} content The author field of the slideshow metadata
+ * @param {string} content The author field of the slideshow options
* @return {string} The formatted author slide
*/
Cleaver.prototype.renderAuthorSlide = function (content) {
@@ -282,7 +293,7 @@ Cleaver.prototype.slice = function(document) {
continue;
} else {
- /* If we leave out metadata, add an empty slide at the beginning */
+ /* If we leave out options, add an empty slide at the beginning */
if (i === 0) {
slices.push({ content: '' });
}
@@ -319,7 +330,7 @@ Cleaver.prototype.slice = function(document) {
Cleaver.prototype.run = function () {
var self = this;
- // Load document -> Parse Metadata / Render Slides -> Populate Resources
+ // Load document -> Parse options / Render Slides -> Populate Resources
var documentChain = this.loadDocument()
.then(self.renderSlides.bind(self))
.then(self.populateThemeResources.bind(self))