Skip to content

Commit

Permalink
Fixes, tests, Grunt setup
Browse files Browse the repository at this point in the history
  • Loading branch information
humphd committed Apr 2, 2014
1 parent c902e8b commit b8cd041
Show file tree
Hide file tree
Showing 8 changed files with 252 additions and 17 deletions.
25 changes: 25 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = function(grunt) {

grunt.initConfig({
compress: {
main: {
options: {
archive: 'test.zip',
mode: 'zip'
},
files: [
{expand: true, src: ['test/*.*'], dest: './'}
]
}
},

jshint: {
all: [ 'src/**/*.js' ]
}
});

grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-compress');

grunt.registerTask('default', ['jshint', 'compress']);
};
25 changes: 25 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "nohost",
"description": "A web server in your web browser",
"keywords": ["web", "server", "files"],
"version": "0.0.1",
"author": "David Humphrey <david.humphrey@senecacolleage.ca> (@humphd)",
"homepage": "http://humphd.github.io/nohost/",
"license": "Apache2",
"scripts": {
"test": "grunt"
},
"repository": {
"type": "git",
"url": "https://github.com/humphd/nohost.git"
},
"devDependencies": {
"grunt": "~0.4.0",
"grunt-contrib-clean": "~0.4.0",
"grunt-contrib-requirejs": "~0.4.0",
"grunt-contrib-uglify": "~0.1.2",
"grunt-contrib-compress": "~0.4.1",
"grunt-contrib-connect": "~0.1.2",
"grunt-contrib-jshint": "~0.7.1"
}
}
38 changes: 37 additions & 1 deletion src/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,24 @@ define(function() {

return {

isMedia: function(ext) {
return ext === '.avi' ||
ext === '.mpeg' ||
ext === '.mp4' ||
ext === '.ogg' ||
ext === '.webm' ||
ext === '.mov' ||
ext === '.qt' ||
ext === '.divx' ||
ext === '.wmv' ||
ext === '.mp3' ||
ext === '.wav';
},

isImage: function(ext) {
return ext === '.png' ||
ext === '.jpg' ||
ext === '.pjpg' ||
ext === '.jpeg'||
ext === '.gif';
},
Expand All @@ -27,9 +42,30 @@ define(function() {
return 'image/x-icon';
case '.jpg':
case '.jpeg':
return 'image.jpeg';
return 'image/jpeg';
case '.gif':
return 'image/gif';
//XXX: Some of these media types can be video or audio, prefer video.
case '.mp4':
return 'video/mp4';
case '.mpeg':
return 'video/mpeg';
case '.ogg':
case '.ogv':
return 'video/ogg';
case '.mov':
case '.qt':
return 'video/quicktime';
case '.webm':
return 'video/webm';
case '.avi':
case '.divx':
return 'video/avi';
case '.mpa':
case '.mp3':
return 'audio/mpeg';
case '.wav':
return 'audio/vnd.wave';
}
return 'application/octet-stream';
},
Expand Down
142 changes: 127 additions & 15 deletions src/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ function(Filer, Async, Log, Content) {
* Open, Write to the document stream, and Close.
*/
function _writeMarkup(markup) {
/* jshint evil:true */
document.open();
document.write(markup);
document.close();
Expand All @@ -15,7 +16,7 @@ function(Filer, Async, Log, Content) {
/**
* Given an HTML string, rewrite it with inline resources
*/
function _handleHTML(html, path, fs) {
function _processHTML(html, path, fs, callback) {
var dir = Path.dirname(path);
var parser = new DOMParser();
var doc;
Expand Down Expand Up @@ -69,7 +70,7 @@ function(Filer, Async, Log, Content) {
continue;
}
elem.href = '?' + Path.join(dir, url);
};
}

callback();
},
Expand All @@ -78,7 +79,7 @@ function(Filer, Async, Log, Content) {

Async.eachSeries(elems, function(elem, cb) {
// Skip any links for protocols (we only want relative paths)
var url = elem.getAttribute('href');;
var url = elem.getAttribute('href');
if(!url || /\:?\/\//.test(url) || /\s*data\:/.test(url)) {
return cb();
}
Expand Down Expand Up @@ -107,17 +108,73 @@ function(Filer, Async, Log, Content) {
callback();
});
},
function iframes(callback) {
var elems = doc.querySelectorAll('iframe');

Async.eachSeries(elems, function(elem, cb) {
// Skip any links for protocols (we only want relative paths)
var url = elem.getAttribute('src');
if(!url || /\:?\/\//.test(url) || /\s*data\:/.test(url)) {
return cb();
}

var path = Path.resolve(dir, url);
fs.exists(path, function(found) {
if(!found) {
return cb();
}

fs.readFile(path, 'utf8', function(err, data) {
if(err) {
return cb(err);
}

_processHTML(data, path, fs, function(err, html) {
elem.src = Content.toDataURL(data, 'text/html');
cb();
});
});
});
}, function(err) {
if(err) {
Log.error(err);
}
callback();
});
},
function styles(callback) {
var elems = doc.querySelectorAll('style');

Async.eachSeries(elems, function(elem, cb) {
var content = elem.textContent;
console.log(elems, elems[0].innerHTML);
if(!content) {
cb();
return;
}
_processCSS(content, path, fs, function(err, css) {
elem.textContent = css;
cb();
});
}, function(err) {
if(err) {
Log.error(err);
}
callback();
});
},
function imgs(callback) {
rewriteElements('img', 'src', null, callback);
},
function scripts(callback) {
rewriteElements('script', 'src', 'text/javascript', callback);
},
function iframes(callback) {
rewriteElements('iframe', 'src', null, callback);
function sources(callback) {
rewriteElements('source', 'src', null, callback);
}
], function callback(err, result) {
_writeMarkup(doc.documentElement.innerHTML);
], function(err, result) {
// Return the processed HTML
callback(null, doc.documentElement.innerHTML);
});
}

Expand Down Expand Up @@ -150,11 +207,11 @@ function(Filer, Async, Log, Content) {
});
fetch(input, replacements, next);
});
};
}

function fetchFiles(list, next) {
fetch(list, [], next);
};
}

content.replace(/url\(['"]?([^'"\)]+)['"]?\)/g, function(_, url) {
if(!url || /\:?\/\//.test(url) || /\s*data\:/.test(url)) {
Expand All @@ -163,7 +220,7 @@ function(Filer, Async, Log, Content) {
urls.push(url);
});
fetchFiles(urls, callback);
};
}

aggregate(css, function(err, replacements) {
if(err) {
Expand Down Expand Up @@ -223,7 +280,54 @@ function(Filer, Async, Log, Content) {
' }'+
'</style></head><body>' +
'<img src="' + path + '"></body></html>';
_handleHTML(syntheticDoc, path, fs);
_processHTML(syntheticDoc, path, fs, function(err, html) {
if(err) {
Log.error('unable to read `' + path + '`');
this.handle404(path);
return;
}
_writeMarkup(html);
});
},

/**
* Synthesize a document for media
*/
handleMedia: function(path, fs) {
var syntheticDoc = '<!DOCTYPE html>' +
'<html><head>' +
'<title>' + path + '</title>' +
'<style>' +
' /* based on http://dxr.mozilla.org/mozilla-central/source/layout/style/TopLevelVideoDocument.css */' +
' body {' +
' height: 100%;' +
' width: 100%;' +
' margin: 0;' +
' padding: 0;' +
' }' +
' video {' +
' position: absolute;' +
' top: 0;' +
' right: 0;' +
' bottom: 0;' +
' left: 0;' +
' margin: auto;' +
' max-width: 100%;' +
' max-height: 100%;' +
' }' +
' video:focus {' +
' outline-width: 0;' +
' }' +
'</style></head><body>' +
'<video src="' + path + '"></video></body></html>';
_processHTML(syntheticDoc, path, fs, function(err, html) {
if(err) {
Log.error('unable to read `' + path + '`');
this.handle404(path);
return;
}
_writeMarkup(html);
});
},

/**
Expand Down Expand Up @@ -289,7 +393,7 @@ function(Filer, Async, Log, Content) {
return '<tr><td valign="top"><img src="' + icon + '" alt="' + alt + '"></td><td>' +
'<a href="' + href + '">' + name + '</a> </td>' +
'<td align="right">' + modified + ' </td>' +
'<td align="right">' + size + '</td><td>&nbsp;</td></tr>';
'<td align="right">' + size + '</td><td>&nbsp;</td></tr>';
}

function processEntries(entries) {
Expand All @@ -298,7 +402,7 @@ function(Filer, Async, Log, Content) {
var name = Path.basename(entry.path);
var ext = Path.extname(entry.path);
var href = '?' + Path.join(path, entry.path);
var icon;
var icon;
var alt;

if(entry.type === 'DIRECTORY') {
Expand All @@ -315,13 +419,14 @@ function(Filer, Async, Log, Content) {
break;
case '.htm':
case '.html':
/* falls through */
default:
icon = 'icons/text.png';
alt = '[TXT]';
break;
}
}
rows += row(icon, alt, href, name, entry.modified, entry.size);
rows += row(icon, alt, href, name, entry.modified, entry.size);
});

_writeMarkup(header + rows + footer);
Expand All @@ -347,7 +452,14 @@ function(Filer, Async, Log, Content) {
return;
}

_handleHTML(html, path, fs);
_processHTML(html, path, fs, function(err, html) {
if(err) {
Log.error('unable to read `' + path + '`');
this.handle404(path);
return;
}
_writeMarkup(html);
});
});
}

Expand Down
4 changes: 3 additions & 1 deletion src/webserver.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function(Filer, Log, Handlers, Content) {

/**
* Download a file (e.g., disk image *.zip) into the server's root.
* Both a url and File/Blog are acceptable.
* Both a url and File/Blob are acceptable.
*/
download: function(url, callback) {
if(typeof url === 'string') {
Expand Down Expand Up @@ -104,6 +104,8 @@ function(Filer, Log, Handlers, Content) {

if(Content.isImage(ext)) {
Handlers.handleImage(path, fs);
} else if(Content.isMedia(ext)) {
Handlers.handleMedia(path, fs);
} else if(Content.isHTML(ext)) {
Handlers.handleHTML(path, fs);
} else {
Expand Down
Binary file added test/media/trailer.mp4
Binary file not shown.
16 changes: 16 additions & 0 deletions test/style-test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<title>HTML5 Style Test</title>
<style>
body {
color: red;
background-image: url('./media/tree.jpg');
}
</style>
</head>
<body>
<p>This text should be red, and the background should be a picture of a tree.</p>
</body>
</html>
Loading

0 comments on commit b8cd041

Please sign in to comment.