From 145dcab8be51513c2ab4345c94fc9dcdd3165dec Mon Sep 17 00:00:00 2001 From: Julian Gruber Date: Wed, 16 Jan 2013 23:39:06 +0100 Subject: [PATCH] more options for caching, prettier frontend, refresh all link, safe cache as .png in git-like folders --- README.md | 4 +- bin/review.js | 9 +++-- cache/.gitkeep | 0 example/cache.js | 11 ++++-- lib/review.js | 4 +- lib/snapshot.js | 16 ++++---- package.json | 4 +- public/app.js | 96 +++++++++++++++++++----------------------------- public/style.css | 23 +++++++++--- views/index.jade | 20 +++++----- 10 files changed, 95 insertions(+), 92 deletions(-) delete mode 100644 cache/.gitkeep diff --git a/README.md b/README.md index f38befc..af5826c 100644 --- a/README.md +++ b/README.md @@ -85,9 +85,9 @@ Configure the resolutions to use for screenshots. Defaults to `["1200x800"]` PhantomJS will wait for `x` milliseconds after loading the page before it takes the screenshot, so you can make sure your page is completely loaded. Defaults to `0`. -### review#cache(x) +### review#cache({ dir : 'directory', expires : 60 }) -Cache rendered snapshots for `x` seconds. +Cache rendered snapshots for `expires` seconds in `dir`. ### review#listen(port) diff --git a/bin/review.js b/bin/review.js index 36504a8..2722012 100755 --- a/bin/review.js +++ b/bin/review.js @@ -4,7 +4,9 @@ var review = require('..') var optimist = require('optimist') var argv = optimist - .usage('Host review\nUsage: $0 [options]\n\nExample: review --sites=\'{"google":"http://google.com"}\'') + .usage( + 'Host review\nUsage: $0 [options]\n\n'+ + 'Examples: review --sites=\'{"google":"http://google.com"}\' --cache=\'{"dir":"cache","expires":100}\'') .demand(['sites']) .describe('port', 'Port to listen on') @@ -26,8 +28,8 @@ var argv = optimist .default('wait', 0) .alias('w', 'wait') - .describe('cache', 'Cache snapshots for x seconds') - .default('cache', false) + .describe('cache', 'Cache snapshots for x milliseconds') + .default('cache', 'false') .alias('c', 'cache') .describe('help', 'Print usage instructions') @@ -41,6 +43,7 @@ review() .sites(JSON.parse(argv.sites)) .resolutions(JSON.parse(argv.resolutions)) .wait(argv.wait) + .cache(argv.cache? { dir : __dirname + '/cache', expires : argv.cache } : false) .listen(argv.port, function () { console.log('-> Review on port ' + argv.port) }) \ No newline at end of file diff --git a/cache/.gitkeep b/cache/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/example/cache.js b/example/cache.js index cc5f9d2..0d89b18 100644 --- a/example/cache.js +++ b/example/cache.js @@ -1,10 +1,13 @@ var review = require('..') review() - .title('Cached Review') - .sites({ localhost : 'http://localhost:3000/' }) - .resolutions(['1280x1024', '800x600']) - .cache(5) + .title('Review') + .sites({ 'github' : 'https://github.com/' }) + .resolutions(['1440x900', '1200x800', '640x480']) + .cache({ + dir : __dirname + '/cache/', + expires : 86400 + }) .listen(5000, function () { console.log('-> Review on port 5000') }) \ No newline at end of file diff --git a/lib/review.js b/lib/review.js index c374c62..f69ca43 100644 --- a/lib/review.js +++ b/lib/review.js @@ -1,4 +1,5 @@ var express = require('express') +var span = require('span') module.exports = review @@ -101,7 +102,8 @@ function review () { sites : _sites, resolutions : _resolutions, wait : wait, - cache : cache + cache : cache, + expires : cache? span(cache.expires * 1000) : null }) } }) diff --git a/lib/snapshot.js b/lib/snapshot.js index f2e543f..6a79673 100644 --- a/lib/snapshot.js +++ b/lib/snapshot.js @@ -4,6 +4,7 @@ var fs = require('fs') var path = require('path') var EventEmitter = require('events').EventEmitter var crypto = require('crypto') +var mkdirp = require('mkdirp') var app = module.exports = express() @@ -27,7 +28,6 @@ app.cache = function (_cache) { */ var script = __dirname + '/../script/rasterize.js' -var cacheDir = path.join(__dirname, '/../cache/') /** * cache handling @@ -55,15 +55,15 @@ app.get('/:url/:resolution/:wait', function (req, res, next) { .update(req.params['resolution']) .digest('hex') - var dir = hash.slice(0, 2) - var filename = cacheDir + dir + '/' + hash + var dir = path.join(cache.dir, hash.slice(0, 2)) + var filename = path.join(dir, hash + '.png') - function createCash () { + function createCache () { caching[hash] = true snapshot(req.params, function (err, rasterized) { if (err) return caching[hash] = false, next(err) - fs.mkdir(cacheDir + dir, function () { + mkdirp(dir, function () { fs.writeFile(filename, rasterized, function (err) { caching[hash] = false if (err) return next(err) @@ -76,12 +76,12 @@ app.get('/:url/:resolution/:wait', function (req, res, next) { } // refresh - if ('refresh' in req.query) return createCash() + if ('refresh' in req.query) return createCache() // choose action based on cache file stat fs.stat(filename, function (err, stat) { // serve cache - if (!err && stat.mtime >= (Date.now() - cache * 1000)) { + if (!err && stat.mtime >= (Date.now() - cache.expires * 1000)) { return res.sendfile(filename) } @@ -90,7 +90,7 @@ app.get('/:url/:resolution/:wait', function (req, res, next) { return caches.once(hash, res.sendfile.bind(res, filename)) } - createCash() + createCache() }) }) diff --git a/package.json b/package.json index 2e87629..f42d7bd 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ "dependencies": { "optimist": "~0.3.5", "jade": "~0.28.1", - "express": "~3.0.6" + "express": "~3.0.6", + "mkdirp": "~0.3.4", + "span": "0.0.5" } } diff --git a/public/app.js b/public/app.js index 6b6e087..f9d2e01 100644 --- a/public/app.js +++ b/public/app.js @@ -1,71 +1,49 @@ var images = Array.prototype.slice.apply(document.querySelectorAll('img')) -var info = document.querySelector('#info') -var loading = document.querySelector('#loading') - -var loaded = 0 -var reloads = 0 -var allLoaded = false +var links = Array.prototype.slice.apply(document.querySelectorAll('.refresh')) +var refreshAll = document.querySelector('.refresh-all') /** - * loading indicator + * refresh all */ - -var iv = setInterval(function () { - if (loaded == images.length) return clearInterval(iv) - - loading.innerHTML += '.' - if (loading.innerHTML == '....') loading.innerHTML = '' -}, 500) -info.innerHTML = '0 / ' + images.length + ' loaded' +refreshAll.addEventListener('click', function () { + var msg = "You're about to refresh " + images.length + " snapshots. Are you sure?" + if (images.length > 10 && !confirm(msg)) return + images.forEach(refresh) +}) /** - * reload + * refresh */ - -images.forEach(function (image) { - image.addEventListener('click', function () { - reloads++ - - // show gray placeholder in same dimensions - var oldSrc = image.src + '' - var oldHeight = image.height - - image.src = '/empty.jpg' - image.style.height = oldHeight + 'px' - - setTimeout(function () { - // force reload - var newSrc = oldSrc - newSrc += newSrc.match(/\?/) - ? '&reload' - : '?reload' - - image.src = newSrc - - function onLoad () { - image.style.height = 'auto' - image.removeEventListener('load', onLoad) - } - - image.addEventListener('load', onLoad) - }, 500) + +links.forEach(function (link) { + link.addEventListener('click', function () { + refresh(link.parentNode.nextSibling.childNodes[0]) }) }) -/** - * loading status - */ - -images.forEach(function (image) { - image.addEventListener('load', function () { - if (allLoaded) return - loaded++ - info.innerHTML = (loaded-reloads) + ' / ' + images.length + ' loaded' - if ((loaded-reloads) == images.length) { - allLoaded = true - info.innerHTML = 'all loaded' - loading.innerHTML = '' +function refresh (image) { + // show gray placeholder in same dimensions + var oldSrc = image.src + '' + var oldHeight = image.height + + image.src = '/empty.jpg' + image.style.height = oldHeight + 'px' + + setTimeout(function () { + // force refresh + var newSrc = oldSrc + newSrc += newSrc.match(/\?/) + ? '&refresh' + : '?refresh' + + image.src = newSrc + + function onLoad () { + image.style.height = 'auto' + image.removeEventListener('load', onLoad) } - }) -}) \ No newline at end of file + + image.addEventListener('load', onLoad) + }, 500) +} \ No newline at end of file diff --git a/public/style.css b/public/style.css index c43ebd9..42b2ef9 100644 --- a/public/style.css +++ b/public/style.css @@ -3,20 +3,33 @@ body { padding : 20px 40px; } +a { + cursor : pointer; +} + +a.refresh-all { + color : lightblue; + font-weight : bold; + margin-left : 0.5ex; + position : relative; + top : -0.2ex; +} + +a.refresh { + position : relative; + top : -0.2ex; + color : lightblue; +} + h1 span, h2 span { color : lightgray; } h1 span { font-weight : normal; - font-size : 40%; color : lightblue; } -#info { - margin-left : 1em; -} - img { box-shadow: 2px 2px 25px rgba(0, 0, 0, 0.80); -moz-box-shadow: 2px 2px 25px rgba(0, 0, 0, 0.80); diff --git a/views/index.jade b/views/index.jade index 5b3e6b0..3931e44 100644 --- a/views/index.jade +++ b/views/index.jade @@ -5,21 +5,23 @@ html link(rel='stylesheet',href='/style.css') body h1= title - span#info be patient - span#loading + a.refresh-all ⟲ if cache - p Serving potentially cached screenshots. Click an image to refresh. + p Images are cached for #{expires}. Refresh at will. else - p Be patient, images will start appearing after #{wait/1000}s. Click an image to refresh. + if wait + p Be patient, images will start appearing after #{wait/1000}s. Refresh at will. each url, title in sites each resolution in resolutions h2= title - span #{resolution.name} - img( - src='/snapshot/#{url}/#{resolution.name}/#{wait}', - style="width:#{resolution.width}; max-width:#{resolution.maxWidth}" - ) + span #{resolution.name} + a.refresh ⟲ + a(href="#{decodeURIComponent(url)}",target="_blank") + img( + src='/snapshot/#{url}/#{resolution.name}/#{wait}', + style="width:#{resolution.width}; max-width:#{resolution.maxWidth}" + ) script(src="/app.js") \ No newline at end of file