Change how slides are served to be easier to edit

Serve up markdown based on filename in the data slide folder. Use the
index to find what file to use.

Removed ability to run code on slide on the server. Wasn't that useful
for how much of a pain it is.
This commit is contained in:
Buddy Sandidge 2015-04-27 23:08:20 -07:00
parent 17de8e7fb6
commit c5829b65ea
42 changed files with 55 additions and 194 deletions

123
bin/deck
View File

@ -3,10 +3,8 @@
var fs = require('fs'); var fs = require('fs');
var path = require('path'); var path = require('path');
var exec = require('child_process').exec;
var _ = require('lodash'); var _ = require('lodash');
var async = require('async');
var express = require('express'); var express = require('express');
var handlebars = require('handlebars'); var handlebars = require('handlebars');
@ -52,28 +50,16 @@ function index(req, res) {
app.get('/', index); app.get('/', index);
function serveIfExists(path) {
return function _serveIfExists(cb) {
fs.exists(path, function (exists) {
if (!exists) {
cb(null, null);
return;
}
fs.readFile(path, {encoding: 'utf8'}, cb);
});
};
}
app.get('/slides', function showHandler(req, res) { app.get('/slides', function showHandler(req, res) {
fs.readdir(pathToFile('data', 'slide'), function (err, files) { fs.readdir(pathToFile('data', 'slide'), function (err, files) {
files.sort(); files.sort();
var jsonFiles = _.filter(files, function (file) { var jsonFiles = _.filter(files, function (file) {
return /^\d+\.json$/.test(file); return /^\d+\.md$/.test(file);
}); });
res.send(_.map(jsonFiles, function (file) { res.send(_.map(jsonFiles, function (file) {
return { return {
id: parseInt(file.replace(/\.json$/, ''), 10) id: parseInt(file.replace(/\.md$/, ''), 10)
}; };
})); }));
}); });
@ -85,107 +71,34 @@ app.get(/slide\/(\d+)/, function showHandler(req, res, next) {
return; return;
} }
var slideId = req.params[0]; var slideIndex = req.params[0];
var slidePath = pathToFile('data', 'slide', slideId + '.json');
fs.exists(slidePath, function (exists) { fs.readdir(pathToFile('data', 'slide'), function (err, files) {
if (!exists) {
next();
return;
}
fs.readFile(slidePath, {encoding: 'utf8'}, function (err, content) {
if (err) { if (err) {
renderError(res, err); return renderError(res, err);
return;
} }
try { files.sort();
var slide = JSON.parse(content); var markdownFiles = _.filter(files, function (file) {
} catch (err) { return /\.md$/.test(file);
renderError(res, err);
return;
}
async.parallel({
copy: serveIfExists(pathToFile('data', 'copy', slide.copy + '.md')),
code: serveIfExists(pathToFile('data', 'code', slide.code + '.js'))
}, function (err, slideContent) {
if (err) {
renderError(res, err);
return;
}
slideContent.id = parseInt(slideId, 10);
slideContent.title = slide.title || '';
res.send(slideContent);
});
}); });
}); if (slideIndex > markdownFiles.length) {
});
app.get(/results\/([^\/]+)\/(\d\d)$/, function resultsHandler(req, res, next) {
var app = req.params[0];
var slideId = req.params[1];
var validApps = [
'node', 'phantomjs-1.9.8', 'phantomjs-2.0.0'
];
if (!_.contains(validApps, app)) {
next();
return;
}
var slidePath = pathToFile('data', 'slide', slideId + '.json');
fs.exists(slidePath, function (exists) {
if (!exists) {
return next(); return next();
} }
var noSlideError = new Error('No code for slide'); var markdownFile = markdownFiles[slideIndex - 1];
async.waterfall([ var markdownPath = pathToFile('data', 'slide', markdownFile);
fs.readFile(markdownPath, {encoding: 'utf8'}, function (err, content) {
function (cb) {
fs.readFile(slidePath, {encoding: 'utf8'}, cb);
},
function (content, cb) {
try {
var slide = JSON.parse(content);
} catch (err) {
cb(err, null);
return;
}
cb(null, slide);
},
function (slide, cb) {
var codePath = pathToFile('data', 'code', slide.code + '.js');
fs.exists(codePath, function (exists) {
if (exists) {
cb(null, codePath);
} else {
cb(noSlideError);
}
});
},
function (path, cb) {
exec(app + ' ' + path, cb);
}
], function (err, stdout, stderr) {
if (err === noSlideError) {
next();
return;
}
if (err) { if (err) {
res.send({stdout: '', stderr: err.toString()}); return renderError(res, err);
return;
} }
res.send({stdout: stdout, stderr: stderr});
});
res.send({
id: parseInt(slideIndex, 10),
copy: content
});
});
}); });
}); });

View File

@ -1,19 +0,0 @@
var page = require('webpage').create();
page.viewportSize = {width: 1280, height: 720};
page.open('https://html5test.com/', function() {
function doneLoading() {
var el = document.getElementById('loading');
return window.getComputedStyle(el).display === 'none';
}
function checkPage() {
if (page.evaluate(doneLoading)) {
page.render('static/html5.' + phantom.version.major + '.png');
console.log('created static/html5.' + phantom.version.major + '.png');
phantom.exit();
}
setTimeout(checkPage, 100);
}
checkPage();
});

View File

@ -1,5 +0,0 @@
# Use After Free
- Create webpage object in JavaScript
- Close webpage in JavaScript
- Do something with webpage in JavaScript

View File

@ -1 +0,0 @@
# JavaScript Runtime

View File

@ -1 +0,0 @@
# PhantomJS

View File

@ -1 +0,0 @@
# Testing

View File

@ -1 +0,0 @@
# Backbone's UMD

View File

@ -1 +0,0 @@
# This will error, not crash

View File

@ -1,3 +0,0 @@
{
"copy": "title"
}

View File

@ -1,3 +0,0 @@
{
"copy": "about"
}

View File

@ -1,3 +0,0 @@
{
"copy": "screen-shot"
}

View File

@ -1,4 +0,0 @@
{
"copy": "only-title",
"code": "phantom-webpage-screenshot"
}

View File

@ -1,3 +1,6 @@
# PhantomJS
```javascript
var page = require('webpage').create(); var page = require('webpage').create();
page.viewportSize = {width: 1280, height: 720}; page.viewportSize = {width: 1280, height: 720};
@ -7,3 +10,4 @@ page.open('http://phantomjs.org', function() {
console.log('created phantomjs.png. ☮ out!'); console.log('created phantomjs.png. ☮ out!');
phantom.exit(); phantom.exit();
}); });
```

View File

@ -1,3 +0,0 @@
{
"copy": "not-node"
}

View File

@ -1,3 +0,0 @@
{
"copy": "qt"
}

View File

@ -1,4 +0,0 @@
{
"copy": "use-after-free",
"code": "use-after-free"
}

View File

@ -1,3 +1,6 @@
# This will error, not crash
```javascript
var phantom = this.phantom || {exit: function () {}}; var phantom = this.phantom || {exit: function () {}};
var foo = {bar: {baz: 123}}; var foo = {bar: {baz: 123}};
delete foo.bar; delete foo.bar;
@ -7,3 +10,4 @@ try {
console.log(err); console.log(err);
phantom.exit(); phantom.exit();
} }
```

View File

@ -1,3 +0,0 @@
{
"copy": "null-pointer"
}

View File

@ -1,4 +0,0 @@
{
"copy": "crash-explain",
"code": "crash"
}

View File

@ -1,3 +1,10 @@
# Use After Free
- Create webpage object in JavaScript
- Close webpage in JavaScript
- Do something with webpage in JavaScript
```javascript
var phantom = this.phantom || {exit: function () {}}; var phantom = this.phantom || {exit: function () {}};
var page = require('webpage').create(); var page = require('webpage').create();
// code, code, code… // code, code, code…
@ -6,3 +13,4 @@ page.open('about:blank', function () {
console.log('☮ out!'); console.log('☮ out!');
phantom.exit(); phantom.exit();
}); });
```

View File

@ -1,4 +0,0 @@
{
"copy": "js-runtime",
"code": "prototypes"
}

View File

@ -1,3 +1,6 @@
# JavaScript Runtime
```javascript
var phantom = this.phantom || {exit: function () {}}; var phantom = this.phantom || {exit: function () {}};
console.log('bind:', typeof Function.prototype.bind); console.log('bind:', typeof Function.prototype.bind);
console.log('9 === parseInt("09"):', 9 === parseInt('09')); console.log('9 === parseInt("09"):', 9 === parseInt('09'));
@ -8,3 +11,4 @@ console.log('filter:', typeof Array.prototype.filter);
console.log('Object.create:', typeof Object.create); console.log('Object.create:', typeof Object.create);
phantom.exit(); phantom.exit();
```

View File

@ -1,3 +0,0 @@
{
"copy": "code-share"
}

View File

@ -1,4 +0,0 @@
{
"copy": "umd",
"code": "backbone-umd"
}

View File

@ -1,3 +1,6 @@
# Backbone's UMD
```javascript
(function(root, factory) { (function(root, factory) {
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
define(['underscore', 'jquery', 'exports'], function(_, $, exports) { define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
@ -12,3 +15,4 @@
}(this, function(root, Backbone, _, $) { }(this, function(root, Backbone, _, $) {
// Backbone… // Backbone…
})); }));
```

View File

@ -1,4 +0,0 @@
{
"copy": "only-title",
"code": "backbone"
}

View File

@ -1,3 +1,6 @@
# PhantomJS
```javascript
var phantom = phantom || {exit: function () {}}; var phantom = phantom || {exit: function () {}};
var _ = require('../../vendor/underscore/underscore'); var _ = require('../../vendor/underscore/underscore');
phantom.injectJs('../../vendor/backbone/backbone.js'); phantom.injectJs('../../vendor/backbone/backbone.js');
@ -5,3 +8,4 @@ console.log(_.toString());
console.log(Backbone.View.toString()); console.log(Backbone.View.toString());
phantom.exit(); phantom.exit();
//module.exports = Backbone; //module.exports = Backbone;
```

View File

@ -1,4 +0,0 @@
{
"copy": "testing",
"code": "some-test"
}

View File

@ -1,5 +1,9 @@
# Testing
```javascript
describe('some test', function () { describe('some test', function () {
it('→ some test case', function () { it('→ some test case', function () {
expect(1 + 1).toBe(2); expect(1 + 1).toBe(2);
}); });
}); });
```

View File

@ -1,4 +0,0 @@
{
"copy": "testing",
"code": "test"
}

View File

@ -1,3 +1,6 @@
# Testing
```javascript
phantom.injectJs('../../vendor/jasmine/lib/jasmine-core/jasmine.js'); phantom.injectJs('../../vendor/jasmine/lib/jasmine-core/jasmine.js');
var consoleFns = require('../../vendor/jasmine/lib/console/console.js'); var consoleFns = require('../../vendor/jasmine/lib/console/console.js');
var jasmine = jasmineRequire.core(jasmineRequire); var jasmine = jasmineRequire.core(jasmineRequire);
@ -13,3 +16,4 @@ jasmine.getEnv().addReporter(new jasmine.ConsoleReporter({
phantom.injectJs('./some-test.js'); phantom.injectJs('./some-test.js');
jasmine.getEnv().execute(); jasmine.getEnv().execute();
```

View File

@ -1,3 +0,0 @@
{
"copy": "other-awesome"
}

View File

@ -1,3 +0,0 @@
{
"copy": "fin"
}