From dc8639c5ef7af3935e368bbfc5f183907653dff7 Mon Sep 17 00:00:00 2001 From: Andrew Davidson Date: Sun, 24 Jan 2016 22:05:38 -0500 Subject: [PATCH] Fixed #19 with the addition of some new modules to parse the image EXIF data. Made a lot of progress on #1 with additional work on the rendering templates. --- app.js | 1 - data/static/scripts/crunch.js | 6 +-- data/static/stylesheets/style.css | 15 ++----- package.json | 7 ++-- photo.js | 40 +++++++++---------- post.js | 66 ++++++++++++++++++++++++++++++- routes-photo.js | 32 +++++++++++---- routes-post.js | 3 +- routes-preview.js | 42 ++++++++++---------- schemas.js | 2 + views/admin-photo-view.jade | 7 +++- views/admin-post-view.jade | 2 +- views/partial-photo.jade | 3 ++ views/render-footer.jade | 3 +- views/render-layout.jade | 45 +++++++++++---------- views/render-photo.jade | 15 +++---- views/render-post-index.jade | 14 ++++++- views/render-sidebar.jade | 3 ++ 18 files changed, 202 insertions(+), 104 deletions(-) create mode 100644 views/partial-photo.jade create mode 100644 views/render-sidebar.jade diff --git a/app.js b/app.js index 01a4509..fc3f7f6 100644 --- a/app.js +++ b/app.js @@ -5,7 +5,6 @@ var passport = require('passport'); var Strategy = require('passport-local').Strategy; var async = require('async'); var fs = require('fs'); -var markdown = require( "markdown" ).markdown; var moment = require("moment"); // Make ourselves a nice little express app. diff --git a/data/static/scripts/crunch.js b/data/static/scripts/crunch.js index 9ef0e30..2c88fd1 100644 --- a/data/static/scripts/crunch.js +++ b/data/static/scripts/crunch.js @@ -1,15 +1,15 @@ function changeImg(e) { if (e.getAttribute('load') == 'lazy') { - path = '/photos/'+e.getAttribute('slug'); + path = e.getAttribute('slug'); if (window.devicePixelRatio && window.devicePixelRatio > 1) { console.log('Loading retina version of '+e.getAttribute('slug')); e.setAttribute('load', 'loaded'); - e.src = path+'/'+e.getAttribute('size')+'2x.'+e.getAttribute('ext'); + e.src = path+e.getAttribute('size')+'2x.'+e.getAttribute('ext'); } else { console.log('Loading non-retina version of '+e.getAttribute('slug')); e.setAttribute('load', 'loaded'); - e.src = path+'/'+e.getAttribute('size')+'.'+e.getAttribute('ext'); + e.src = path+e.getAttribute('size')+'.'+e.getAttribute('ext'); } } } diff --git a/data/static/stylesheets/style.css b/data/static/stylesheets/style.css index a43ec41..0d6424e 100644 --- a/data/static/stylesheets/style.css +++ b/data/static/stylesheets/style.css @@ -1,13 +1,4 @@ -@media (min-width: 768px) { - div.nav-title-block { - height:240px; - bottom:20px; - position:fixed; - } -} - -@media (max-width: 768px) { - div.nav-title-block img.img-responsive { - max-width: 200px; - } +article { + border-bottom: 1px rgb(119, 119, 119) solid; + padding-bottom: 20px; } diff --git a/package.json b/package.json index 3e6477f..e8daf43 100644 --- a/package.json +++ b/package.json @@ -9,13 +9,13 @@ "connect-redis": "^3.0.2", "cookie-parser": "^1.3.5", "debug": "^2.2.0", + "exif": "^0.5.1", "express": "^4.13.1", "express-flash": "^0.0.2", "express-session": "^1.13.0", - "gm": "^1.21.1", "jade": "^1.11.0", "lodash": "^4.0.0", - "markdown": "^0.5.0", + "marked": "^0.3.5", "moment": "^2.11.1", "mongodb": "^2.1.4", "morgan": "^1.6.1", @@ -25,6 +25,7 @@ "passport": "^0.3.0", "passport-local": "^1.0.0", "redis": "^2.4.2", - "serve-favicon": "^2.3.0" + "serve-favicon": "^2.3.0", + "sharp": "^0.12.2" } } diff --git a/photo.js b/photo.js index 9e9074d..ce90f0a 100644 --- a/photo.js +++ b/photo.js @@ -3,11 +3,11 @@ var _ = require("lodash"); var fs = require('fs'); var mkdirp = require('mkdirp'); var jade = require('jade'); -var markdown = require( "markdown" ).markdown; +var marked = require('marked'); var path = require('path'); var schemas = require('./schemas.js'); -var gm = require('gm'); var config = require("./config.js").config; +var sharp = require('sharp'); var Photo = function(data) { this.data = this.sanitize(data); @@ -97,14 +97,14 @@ Photo.prototype.getShortDate = function () { // Arguments: None // Returns: Content as String Photo.prototype.renderMarkdown = function () { - return markdown.toHTML(this.get("markdown")); + return marked(this.get("markdown")); } // Function to get the relative url of a photo, this sets the permalink structure // Arguments: None // Returns: URL as String Photo.prototype.getURL = function () { - var url = "/photo/"; + var url = "/photos/"; url += moment(this.get("photoDate")).format("YYYY/MM/"); url += this.get("slug") + '/'; return url; @@ -153,13 +153,11 @@ Photo.prototype.makeSlug = function () { // Arguments: Callback function // Returns: err Photo.prototype.build = function (callback) { - var options = { + console.log('Rendering photo: '+this.get("title")); + var jadeOut = jade.renderFile('views/render-photo.jade', { pretty: true, photo: this - }; - - console.log('Rendering photo: '+this.get("title")); - var jadeOut = jade.renderFile('views/render-photo.jade', options); + }); console.log('Creating directory: '+ this.getDirectory()); @@ -169,20 +167,20 @@ Photo.prototype.build = function (callback) { if (err) console.log(err); for (var size in config.imageSizes) { console.log('Generating '+size+' for '+self.get("slug")); - (function(size){ - gm(self.get('masterPath')) - .autoOrient() - .resize(config.imageSizes[size], config.imageSizes[size]) - .write(path.join(self.getDirectory(),size+'.'+self.get("extension")), - function(err) { - if (err) { + (function (size) { + var outFile = path.join(self.getDirectory(),size+'.'+self.get("extension")); + sharp(self.get('masterPath')) + .resize(config.imageSizes[size], config.imageSizes[size]) + .max() + .quality(95) + .withoutEnlargement() + .toFile(outFile, function(err) { + if (!err) { + console.log(self.get("slug")+' '+size+' generated.'); + } else { console.log(self.get("slug")+' resize failed.'); } - else { - console.log(self.get("slug")+' '+size+' generated.'); - } - } - ); + }); })(size); } diff --git a/post.js b/post.js index 9ba1c53..6fc3bb0 100644 --- a/post.js +++ b/post.js @@ -3,7 +3,7 @@ var _ = require("lodash"); var fs = require('fs'); var mkdirp = require('mkdirp'); var jade = require('jade'); -var markdown = require( "markdown" ).markdown; +var marked = require('marked'); var path = require('path'); var schemas = require('./schemas.js'); var config = require("./config.js").config; @@ -101,7 +101,7 @@ Post.prototype.getShortDate = function () { // Arguments: None // Returns: Content as String Post.prototype.renderMarkdown = function () { - return markdown.toHTML(this.get("markdown")); + return marked(this.get("markdown")); } // Function to get the relative url of a post, this sets the permalink structure @@ -168,6 +168,7 @@ Post.prototype.build = function (callback) { Post.buildMonthIndex(year, month, function (err) { if (err) console.log(err); }); + Post.buildIndex(); var options = { pretty: true, @@ -348,6 +349,7 @@ Post.buildMonthIndex = function (year, month, callback) { var jadeOut = jade.renderFile('views/render-post-index.jade', { pretty: true, posts: posts, + pageTitle: 'Posts from '+year+'/'+month, title: 'Posts from '+year+'/'+month }); @@ -397,6 +399,7 @@ Post.buildYearIndex = function (year, callback) { var jadeOut = jade.renderFile('views/render-post-index.jade', { pretty: true, posts: posts, + pageTitle: 'Posts from '+year, title: 'Posts from '+year }); @@ -416,5 +419,64 @@ Post.buildYearIndex = function (year, callback) { } +// Function to build the main index +// Inputs: none +// Returns: none +Post.buildIndex = function () { + console.log("Building home index"); + Post.getPosts(null, null, function (err, posts) { + pages = posts.length / 10; + for ( p = 0; p < pages ; p++) { + (function (p) { + console.log("Building page "+p+" of index."); + var start = p*10; + var end = (p+1)*10-1; + if ( p > 0 ) { + var title = 'Page 2'; + var pageTitle = 'Page 2'; + } + if ( p === 0 ) { + var prev = -1; + } else { + var prev = p-1; + } + if ( p + 1 < pages ) { + var next = p+2; + } else { + var next = false; + } + var jadeOut = jade.renderFile('views/render-post-index.jade', { + pretty: true, + title: title, + pageTitle: pageTitle, + next: next, + prev: prev, + posts: posts.slice(start, end) + }); + + if (p === 0) { + var directory = path.join(config.buildDir, 'blog'); + var file = path.join(directory, 'index.html'); + } else { + var directory = path.join(config.buildDir, 'blog', (p+1).toString()); + var file = path.join(directory, 'index.html'); + } + mkdirp(directory, function (err) { + console.log('Made directory: '+directory); + if (!err) { + fs.writeFile(file, jadeOut, 'utf-8', function (err) { + console.log('Wrote out: '+file); + if (err) console.log(err); + }); + } else { + console.log('Failed to build '+file, err) + } + }); + })(p); + } + }); +} + + // Export the Post object for external use. module.exports = Post; diff --git a/routes-photo.js b/routes-photo.js index ca29dec..624bf80 100644 --- a/routes-photo.js +++ b/routes-photo.js @@ -1,7 +1,10 @@ // Routes for photo administration. var config = require('./config.js').config; var multer = require('multer'); +var ExifImage = require('exif').ExifImage; +var jade = require('jade'); var upload = multer({ dest: config.uploadDir }); +var uuid = require('node-uuid'); module.exports = function(app) { @@ -29,10 +32,15 @@ module.exports = function(app) { function (req, res, next) { if (req.params.uuid) { Photo.getByUUID(req.params.uuid, function(err, photo) { + var jadeOut = jade.renderFile('views/partial-photo.jade', { + pretty: true, + photo: photo + }); res.render('admin-photo-view', { successNotice: req.flash('successNotice'), failureNotice: req.flash('failureNotice'), photo, + htmlSnippet: jadeOut, user: req.user }); }); @@ -56,8 +64,7 @@ module.exports = function(app) { app.post('/admin/photo/new', upload.single('photo'), function(req, res, next) { - console.log(req.file); - photo = new Photo(); + var photo = new Photo({'uuid': uuid.v1()}); if (req.body.title != '') { photo.set('title', req.body.title); } else { @@ -85,18 +92,27 @@ module.exports = function(app) { photo.set("published", false); } - photo.save(null, function (err) { + ExifImage({image: photo.get('masterPath')}, function (err, exifData) { if (!err) { - req.flash('successNotice', 'Photo created.'); - res.redirect('/admin/photo/view/'+photo.get('uuid')); + photo.set('exif', exifData.exif || {}); + photo.set('gps', exifData.gps || {}); + photo.save(null, function (err) { + if (!err) { + req.flash('successNotice', 'Photo created.'); + res.redirect('/admin/photo/view/'+photo.get('uuid')); + } else { + console.log(err); + req.flash('failureNotice', 'Photo failed to be created'); + res.redirect(req.header('Referer') || '/admin'); + } + }); } else { console.log(err); req.flash('failureNotice', 'Photo failed to be created'); - res.redirect('/admin/photo/new'); + res.redirect(req.header('Referer') || '/admin'); } - }); - } + } ); app.get('/admin/photo/edit/:uuid', diff --git a/routes-post.js b/routes-post.js index 9d0eee6..53c8fad 100644 --- a/routes-post.js +++ b/routes-post.js @@ -1,4 +1,5 @@ var config = require('./config.js').config; +var uuid = require('node-uuid'); // Post management routing @@ -55,7 +56,7 @@ module.exports = function(app) { // POST /admin/post/new app.post('/admin/post/new', function(req, res, next) { - var post = new Post(); + var post = new Post({'uuid': uuid.v1()}); post.set("title", req.body.title); if (req.body.slug != "") { post.set("slug", req.body.slug); diff --git a/routes-preview.js b/routes-preview.js index f10767c..79e9fbd 100644 --- a/routes-preview.js +++ b/routes-preview.js @@ -9,27 +9,29 @@ module.exports = function (app) { function(req, res, next) { if (req.params[0] != '') { var path = __dirname + '/' + config.buildDir + '/blog/' + req.params[0]; - console.log('Trying to serve: ' + path); - fs.exists(path, function(exists) { - if (exists) { - console.log(path + ' exists serving...'); - res.sendFile(path); - } - else { - console.log(path + ' does not exist...'); - if (path.slice(-1) != '/') path += '/'; - path += 'index.html' - console.log('Trying to serve: ' + path); - fs.exists(path, function(exists) { - if (exists) { - console.log(path + ' exists serving...'); - res.sendFile(path); - } - }); - } - }); + } else { + var path = __dirname + '/' + config.buildDir + '/blog/'; } - } + console.log('Trying to serve: ' + path); + fs.exists(path, function(exists) { + if (exists) { + console.log(path + ' exists serving...'); + res.sendFile(path); + } + else { + console.log(path + ' does not exist...'); + if (path.slice(-1) != '/') path += '/'; + path += 'index.html' + console.log('Trying to serve: ' + path); + fs.exists(path, function(exists) { + if (exists) { + console.log(path + ' exists serving...'); + res.sendFile(path); + } + }); + } + }); + } ); app.get('/photos/*', diff --git a/schemas.js b/schemas.js index 2380d31..d56e618 100644 --- a/schemas.js +++ b/schemas.js @@ -44,7 +44,9 @@ schemas = { updatedDate: new Date(), deleted: false, published: false, + aspect: null, tags: [], + gps: {}, exif: {}, lastBuildDate: new Date("Mon Jan 1 1900 00:00:00 GMT-0500"), lastUploadDate: new Date("Mon Jan 1 1900 00:00:00 GMT-0500") diff --git a/views/admin-photo-view.jade b/views/admin-photo-view.jade index 95c15f3..b6ebd9b 100644 --- a/views/admin-photo-view.jade +++ b/views/admin-photo-view.jade @@ -9,7 +9,7 @@ block content include ./admin-messages.jade div(class='page-header row') - div(class="col-sm-6 col-sm-offset-3") + div(class="col-sm-10 col-sm-offset-1") img(class="img-responsive", src="/#{photo.get('masterPath')}") div(class='row') @@ -23,3 +23,8 @@ block content div(class='row') p #{photo.get('markdown')} + + div(class="row") + h4 Snippet for Use in Posts + div #{htmlSnippet} + diff --git a/views/admin-post-view.jade b/views/admin-post-view.jade index 087c2bc..5d8cfee 100644 --- a/views/admin-post-view.jade +++ b/views/admin-post-view.jade @@ -12,7 +12,7 @@ block content h3 #{post.get('title')} div(class='row') - | #{post.getShortDate()} -- + | #{post.getShortDate()} --  a(href="/admin/post/edit/#{post.get('uuid')}") Edit | -  a(href="/admin/post/build/#{post.get('uuid')}") Build diff --git a/views/partial-photo.jade b/views/partial-photo.jade new file mode 100644 index 0000000..ccfb62f --- /dev/null +++ b/views/partial-photo.jade @@ -0,0 +1,3 @@ +img(slug="#{photo.getURL()}", size='post', + src="/static/images/loading.gif", ext="#{photo.get('extension')}", load='lazy', + onload='changeImg(this);').img-responsive diff --git a/views/render-footer.jade b/views/render-footer.jade index cd3b40a..3c0b549 100644 --- a/views/render-footer.jade +++ b/views/render-footer.jade @@ -1 +1,2 @@ -script(type="text/javascript", src="/static/scripts/crunch.js") +script(src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js") +script(src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha256-Sk3nkD6mLTMOF0EOpNtsIry+s1CsaqQC1rVLTAy+0yc= sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous") diff --git a/views/render-layout.jade b/views/render-layout.jade index 77d71a3..f89f43f 100644 --- a/views/render-layout.jade +++ b/views/render-layout.jade @@ -1,23 +1,28 @@ doctype html html - head - title #{title} - meta(charset="utf-8") - meta(http-equiv="X-UA-Compatible", content="IE=edge") - meta(name="viewport", content="width=device-width, initial-scale=1") - link(href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css", rel="stylesheet" integrity="sha256-MfvZlkHCEqatNoGiOXveE8FIwMzZg4W85qfrfIFBfYc= sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous") - link(rel='stylesheet', href='/static/stylesheets/style.css') - block head-addition - body(role="document") - div(role="main").container-fluid - div.col-sm-3 - div.title-block - img(src="/static/images/logo.png").img-responsive - div.col-sm-8.col-sm-offset-4 - block content - div.col-sm-3.title-block-nav - ul.nav.nav-pills.nav-justified - li: a(href="/") Home - li: a(href="/blog") Blog - li: a(href="/photos") Photos + head + title #{title} + meta(charset="utf-8") + meta(http-equiv="X-UA-Compatible", content="IE=edge") + meta(name="viewport", content="width=device-width, initial-scale=1") + link(href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/simplex/bootstrap.min.css", rel="stylesheet", integrity="sha256-rgHoMgF45/9e2kvxfvR0KarwQNw5CRqgxbrthGpeUuc= sha512-CGGV53FSdrXrjyGCNk04p+xuna3CbE33n773A0EEmqtcN8W3NaFsR0vSQcbll5dpSS90d3i2Zh3jFX/j46hzJA==", crossorigin="anonymous") + link(rel='stylesheet', href='/static/stylesheets/style.css') + script(type="text/javascript", src="/static/scripts/crunch.js") + block head-addition + body(role="document") + div(class="container-fluid", role="main", style="padding-bottom: 20px;") + div.row + div(class="col-sm-3 sidebar") + div.row.visible-xs-block.col-xs-6.col-xs-offset-3 + img(src="/static/images/logo.png").img-responsive + img(src="/static/images/logo.png").img-responsive.center-block.hidden-xs + div.hidden-xs + include ./render-sidebar.jade + div(class="col-sm-7 col-sm-offset-1 col-xs-12 main") + block content + + div(style="text-align:center;").visible-xs-block.col-xs-12 + include ./render-sidebar.jade + + include ./render-footer.jade diff --git a/views/render-photo.jade b/views/render-photo.jade index 337b3c4..23bc6f1 100644 --- a/views/render-photo.jade +++ b/views/render-photo.jade @@ -1,13 +1,10 @@ extends render-layout -block head-addition - script(type="text/javascript", src="/static/scripts/crunch.js") - block content - div: img(slug='#{slug}', size='md', - src="/static/images/loading.gif", ext='#{extension}', load='lazy', - onload='changeImg(this);') - - h3: a(href="#{url}") #{title} - div !{content} + article + header + div(style="padding-top: 30px;") + include ./partial-photo.jade + h3: a(href="#{photo.getURL()}") #{photo.get('title')} + !{photo.renderMarkdown()} diff --git a/views/render-post-index.jade b/views/render-post-index.jade index 28a0f1e..68a205d 100644 --- a/views/render-post-index.jade +++ b/views/render-post-index.jade @@ -1,7 +1,19 @@ extends render-layout block content - h1 #{title} + h1 #{pageTitle} each post in posts include ./partial-post.jade + + div + if prev == 0 + a(href="/blog/") Newer + if prev > 0 + a(href="/blog/#{prev}/") Newer + + if prev >= 0 && next > 0 + |  —  + + if next > 0 + a(href="/blog/#{next}/") Older diff --git a/views/render-sidebar.jade b/views/render-sidebar.jade new file mode 100644 index 0000000..da5e4cb --- /dev/null +++ b/views/render-sidebar.jade @@ -0,0 +1,3 @@ +ul.nav.nav-sidebar + li: a(href="/blog/") Blog + li: a(href='/photos/') Photos