Comparing version 0.2.0 to 0.2.5
@@ -19,4 +19,9 @@ title: Basic Example | ||
This will be in a separate paragraph | ||
This will be in a separate paragraph. | ||
<img src="http://whatismarkdown.com/workspace/img/logo.gif" alt="Drawing" style="width: 150px;"/> | ||
![markdown-logo](logo.gif) | ||
<img src="logo.gif" /> | ||
-- | ||
@@ -30,2 +35,12 @@ | ||
No need for mutliple templates! | ||
No need for multiple templates! | ||
-- | ||
### Unicode | ||
* 林花謝了春紅 太匆匆 | ||
* 胭脂淚 留人醉 幾時重 | ||
* Matching Pairs «»‹› “”‘’「」〈〉《》〔〕 | ||
* Greek αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω | ||
* currency ¤ $ ¢ € ₠ £ ¥ |
@@ -10,2 +10,4 @@ var fs = require('fs'); | ||
function Cleaver(file) { | ||
this.file = file | ||
if (!file) throw "!! Please specify a file to parse"; | ||
@@ -15,4 +17,6 @@ | ||
this.templates = { | ||
main: 'layout.mustache', | ||
author: 'author.mustache' | ||
layout: 'layout.mustache', | ||
author: 'author.mustache', | ||
agenda: 'agenda.mustache', | ||
slides: 'default.mustache' | ||
}; | ||
@@ -52,2 +56,3 @@ | ||
// insert an author slide (if necessary) at the end | ||
if (self.metadata.author) { | ||
@@ -57,9 +62,26 @@ 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)); | ||
} | ||
var promises = []; | ||
// maybe load an external stylesheet | ||
if (self.metadata.style) { | ||
return helper.loadSingle(self.metadata.style) | ||
promises.push(helper.loadSingle(self.metadata.style) | ||
.then(function (data) { | ||
self.external.loaded.style = data; | ||
}) | ||
})); | ||
} | ||
// maybe load an external template | ||
if (self.metadata.template) { | ||
promises.push(helper.loadSingle(self.metadata.template) | ||
.then(function (data) { | ||
self.templates.loaded.slides = data; | ||
})); | ||
} | ||
return Q.all(promises); | ||
}); | ||
@@ -86,16 +108,26 @@ } | ||
var putControls = this.metadata.controls || (this.metadata.controls === undefined); | ||
var outputLocation = this.metadata.output || 'cleaver.html'; | ||
var title = this.metadata.title || 'Untitled'; | ||
var slideData = { | ||
// Render the slides in a template (maybe as specified by the user) | ||
var slideshow = mustache.render(this.templates.loaded.slides, { | ||
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 | ||
}); | ||
// TODO: handle defaults gracefully | ||
var title = this.metadata.title || 'Untitled'; | ||
var encoding = this.metadata.encoding || 'utf-8'; | ||
var layoutData = { | ||
slideshow: slideshow, | ||
title: title, | ||
encoding: encoding, | ||
style: this.resources.loaded.style, | ||
externalStyle: this.external.loaded.style | ||
}; | ||
return helper.save(outputLocation, mustache.render(this.templates.loaded.main, slideData)); | ||
// Render the main layout | ||
var outputLocation = this.metadata.output || path.basename(this.file, '.md') + '-cleaver.html'; | ||
return helper.save(outputLocation, mustache.render(this.templates.loaded.layout, layoutData)); | ||
} | ||
@@ -113,3 +145,27 @@ | ||
/* | ||
* 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); | ||
} | ||
/** | ||
@@ -121,3 +177,3 @@ * Returns a chopped up document that's easy to parse | ||
Cleaver.prototype._slice = function(document) { | ||
var cuts = document.split('\n--\n'); | ||
var cuts = document.split(/\r?\n--\r?\n/); | ||
var slices = []; | ||
@@ -124,0 +180,0 @@ |
{ | ||
"name": "cleaver", | ||
"preferGlobal": true, | ||
"version": "0.2.0", | ||
"version": "0.2.5", | ||
"author": "Jordan Scales <scalesjordan@gmail.com>", | ||
@@ -6,0 +6,0 @@ "description": "30-second slideshows for hackers", |
# Cleaver | ||
30-second slideshows for hackers | ||
30-second Slideshows for Hackers | ||
@@ -38,11 +38,11 @@ ## Intro | ||
No need for mutliple templates! | ||
No need for multiple templates! | ||
Into this: | ||
![output](https://dsz91cxz97a03.cloudfront.net/hHBVUtbREK.gif) | ||
![output](https://i.cloudup.com/hHBVUtbREK.gif) | ||
## Quick Start | ||
Get it on NPM. | ||
Get it [on NPM](https://npmjs.org/package/cleaver): | ||
@@ -53,3 +53,3 @@ ``` | ||
Run it. | ||
And run it like so: | ||
@@ -91,4 +91,8 @@ ``` | ||
* **style**: An optional stylesheet to load | ||
* **output**: A location to save the rendered document (default: *cleaver.html*) | ||
* **controls**: A boolean representing whether or not arrow buttons should be included (default: *true*) | ||
* **output**: A location to save the rendered document (default: *FILENAME-cleaver.html*) | ||
* **controls**: Option whether or not arrow buttons should be included (default: *true*) | ||
* **agenda**: Option whether or not to insert an agenda slide (similar to a table of contents) after the title (default: *false*) | ||
* **encoding**: A specified content encoding (default: *utf-8*) | ||
* **template**: An absolute path specifying a template in which to render the slides (default: | ||
*default.css*) | ||
@@ -98,3 +102,3 @@ If author is included, the following slide will be automatically inserted | ||
![author slide](https://dsz91cxz97a03.cloudfront.net/YxgwvqVZNg-1200x1200.png) | ||
![author slide](https://i.cloudup.com/YxgwvqVZNg-1200x1200.png) | ||
@@ -117,3 +121,3 @@ ### Title slide | ||
No need for mutliple templates! | ||
No need for multiple templates! | ||
@@ -135,6 +139,38 @@ Since slides are written in [Markdown](http://daringfireball.net/projects/markdown/), | ||
## Contributing | ||
### Templates | ||
By default, cleaver slides are rendered in the following template: | ||
```html | ||
<div id="wrapper"> | ||
{{#slides}} | ||
<section class="slide">{{{.}}}</section> | ||
{{/slides}} | ||
</div> | ||
{{#controls}} | ||
<div id="controls"> | ||
<div id="prev">←</div> | ||
<div id="next">→</div> | ||
</div> | ||
{{/controls}} | ||
<script type="text/javascript"> | ||
{{{navigation}}} | ||
</script> | ||
``` | ||
Power users may wish to render into custom templates. To do so, simply copy the following file | ||
and specify a template (with an absolute path) like so: | ||
```yaml | ||
title: Basic Example | ||
output: basic.html | ||
template: /Users/jordan/Slides/example/example.mustache | ||
``` | ||
### Contributing | ||
* Fork it | ||
* Clone it | ||
* Install dependencies (`npm install`) | ||
* Checkout a release branch (`git checkout -b feature/cool-wordart`) | ||
@@ -148,2 +184,2 @@ * Make changes, commit, and push | ||
[MIT Licensed](https://github.com/prezjordan/cleaver/blob/master/LICENSE) | ||
[MIT Licensed](https://github.com/jdan/cleaver/blob/master/LICENSE) |
@@ -13,2 +13,4 @@ /** | ||
wrapper.insertBefore(lastSlide, wrapper.firstChild); | ||
updateURL(); | ||
} | ||
@@ -28,6 +30,67 @@ | ||
wrapper.appendChild(firstSlide); | ||
updateURL(); | ||
} | ||
/** | ||
* Updates the current URL to include a hashtag of the current page number. | ||
*/ | ||
function updateURL() { | ||
window.history.replaceState({} , null, '#' + currentPage()); | ||
} | ||
/** | ||
* Returns the current page number of the presentation. | ||
*/ | ||
function currentPage() { | ||
return document.querySelector('#wrapper .slide').dataset.page; | ||
} | ||
/** | ||
* Returns a NodeList of each .slide element. | ||
*/ | ||
function allSlides() { | ||
return document.querySelectorAll('#wrapper .slide'); | ||
} | ||
/** | ||
* Give each slide a "page" data attribute. | ||
*/ | ||
function setPageNumbers() { | ||
var wrapper = document.querySelector('#wrapper'); | ||
var pages = wrapper.querySelectorAll('section'); | ||
var page; | ||
for (var i = 0; i < pages.length; ++i) { | ||
page = pages[i]; | ||
page.dataset.page = i; | ||
} | ||
} | ||
/** | ||
* Go to the specified page of content. | ||
*/ | ||
function goToPage(page) { | ||
// Try to find the target slide. | ||
var targetSlide = document.querySelector('#wrapper .slide[data-page="' + page + '"]'); | ||
// If it actually exists, go forward until we find it. | ||
if (targetSlide) { | ||
var numSlides = allSlides().length; | ||
for (var i = 0; currentPage() != page && i < numSlides; i++) { | ||
goForward(); | ||
} | ||
} | ||
} | ||
window.onload = function () { | ||
// Give each slide a "page" data attribute. | ||
setPageNumbers(); | ||
// If the location hash specifies a page number, go to it. | ||
var page = window.location.hash.slice(1); | ||
if (page) goToPage(page); | ||
document.onkeydown = function (e) { | ||
@@ -34,0 +97,0 @@ var kc = e.keyCode; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
19641
17
451
179
0