From 4a56d10c865e04928965c786c18e42aa75e6a24f Mon Sep 17 00:00:00 2001 From: cobbspur Date: Tue, 21 Oct 2014 12:50:34 +0200 Subject: [PATCH] Created image helper with absolute url option closes #4231 - Adds {{image}} helper - Adds image_spec test unit - Updated {{ghost_head}} to use image helper --- core/server/config/url.js | 9 ++- core/server/helpers/ghost_head.js | 21 +++--- core/server/helpers/image.js | 20 ++++++ core/server/helpers/index.js | 2 + .../unit/server_helpers/ghost_head_spec.js | 42 +++++------ core/test/unit/server_helpers/image_spec.js | 69 +++++++++++++++++++ 6 files changed, 130 insertions(+), 33 deletions(-) create mode 100644 core/server/helpers/image.js create mode 100644 core/test/unit/server_helpers/image_spec.js diff --git a/core/server/config/url.js b/core/server/config/url.js index a34257c3dc..ece88367c0 100644 --- a/core/server/config/url.js +++ b/core/server/config/url.js @@ -101,8 +101,8 @@ function urlPathForPost(post, permalinks) { // This is probably not the right place for this, but it's the best place for now function urlFor(context, data, absolute) { var urlPath = '/', - secure, - knownObjects = ['post', 'tag', 'author'], + secure, imagePathRe, + knownObjects = ['post', 'tag', 'author', 'image'], // this will become really big knownPaths = { @@ -133,6 +133,11 @@ function urlFor(context, data, absolute) { } else if (context === 'author' && data.author) { urlPath = '/author/' + data.author.slug + '/'; secure = data.author.secure; + } else if (context === 'image' && data.image) { + urlPath = data.image; + imagePathRe = new RegExp('^' + ghostConfig.paths.subdir + '/' + ghostConfig.paths.imagesRelPath); + absolute = imagePathRe.test(data.image) ? absolute : false; + secure = data.image.secure; } // other objects are recognised but not yet supported } else if (_.isString(context) && _.indexOf(_.keys(knownPaths), context) !== -1) { diff --git a/core/server/helpers/ghost_head.js b/core/server/helpers/ghost_head.js index 27f782e3f2..9b262e7a03 100644 --- a/core/server/helpers/ghost_head.js +++ b/core/server/helpers/ghost_head.js @@ -19,6 +19,7 @@ var hbs = require('express-hbs'), meta_title = require('./meta_title'), excerpt = require('./excerpt'), tagsHelper = require('./tags'), + imageHelper = require('./image'), ghost_head; ghost_head = function (options) { @@ -42,12 +43,21 @@ ghost_head = function (options) { ops.push(urlHelper.call(self, {hash: {absolute: true}})); ops.push(meta_description.call(self)); ops.push(meta_title.call(self)); + if (self.post) { + ops.push(imageHelper.call(self.post, {hash: {absolute:true}})); + + if (self.post.author) { + ops.push(imageHelper.call(self.post.author, {hash: {absolute:true}})); + } + } // Resolves promises then push pushes meta data into ghost_head return Promise.settle(ops).then(function (results) { var url = results[0].value(), metaDescription = results[1].value(), metaTitle = results[2].value(), + coverImage = results.length > 3 ? results[3].value() : null, + authorImage = results.length > 4 ? results[4].value() : null, publishedDate, modifiedDate, tags = tagsHelper.call(self.post, {hash: {autolink: 'false'}}).string.split(','), card = 'summary', @@ -80,19 +90,10 @@ ghost_head = function (options) { publishedDate = moment(self.post.published_at).toISOString(); modifiedDate = moment(self.post.updated_at).toISOString(); - if (self.post.image) { - coverImage = self.post.image; - // Test to see if image was linked by url or uploaded - coverImage = coverImage.substring(0, 4) === 'http' ? coverImage : hbs.handlebars.Utils.escapeExpression(blog.url + coverImage); + if (coverImage) { card = 'summary_large_image'; } - if (self.post.author.image) { - authorImage = self.post.author.image; - // Test to see if image was linked by url or uploaded - authorImage = authorImage.substring(0, 4) === 'http' ? authorImage : hbs.handlebars.Utils.escapeExpression(blog.url + authorImage); - } - // escaped data metaTitle = hbs.handlebars.Utils.escapeExpression(metaTitle); metaDescription = hbs.handlebars.Utils.escapeExpression(metaDescription + '...'); diff --git a/core/server/helpers/image.js b/core/server/helpers/image.js new file mode 100644 index 0000000000..7b14db0e28 --- /dev/null +++ b/core/server/helpers/image.js @@ -0,0 +1,20 @@ + +// Usage: `{{image}}`, `{{image absolute="true"}}` +// +// Returns the URL for the current object scope i.e. If inside a post scope will return image permalink +// `absolute` flag outputs absolute URL, else URL is relative. + +var Promise = require('bluebird'), + config = require('../config'), + image; + +image = function (options) { + var absolute = options && options.hash.absolute; + if (this.image) { + return Promise.resolve(config.urlFor('image', {image: this.image}, absolute)); + } else { + return Promise.resolve(); + } +}; + +module.exports = image; diff --git a/core/server/helpers/index.js b/core/server/helpers/index.js index 2b559e2fdd..1778924844 100644 --- a/core/server/helpers/index.js +++ b/core/server/helpers/index.js @@ -40,6 +40,7 @@ coreHelpers.post_class = require('./post_class'); coreHelpers.tags = require('./tags'); coreHelpers.title = require('./title'); coreHelpers.url = require('./url'); +coreHelpers.image = require('./image'); coreHelpers.ghost_script_tags = require('./ghost_script_tags'); @@ -146,6 +147,7 @@ registerHelpers = function (adminHbs) { registerAsyncThemeHelper('meta_title', coreHelpers.meta_title); registerAsyncThemeHelper('post_class', coreHelpers.post_class); registerAsyncThemeHelper('url', coreHelpers.url); + registerAsyncThemeHelper('image', coreHelpers.image); // Register admin helpers registerAdminHelper('ghost_script_tags', coreHelpers.ghost_script_tags); diff --git a/core/test/unit/server_helpers/ghost_head_spec.js b/core/test/unit/server_helpers/ghost_head_spec.js index 2e4e875e35..001f559323 100644 --- a/core/test/unit/server_helpers/ghost_head_spec.js +++ b/core/test/unit/server_helpers/ghost_head_spec.js @@ -54,7 +54,7 @@ describe('{{ghost_head}} helper', function () { var post = { meta_description: 'blog description', title: 'Welcome to Ghost', - image: '/test-image.png', + image: '/content/images/test-image.png', published_at: moment('2008-05-31T19:18:15').toISOString(), updated_at: moment('2014-10-06T15:23:54').toISOString(), tags: [{name: 'tag1'}, {name: 'tag2'}, {name: 'tag3'}], @@ -62,7 +62,7 @@ describe('{{ghost_head}} helper', function () { name: 'Author name', url: 'http//:testauthorurl.com', slug: 'Author', - image: '/test-author-image.png', + image: '/content/images/test-author-image.png', website: 'http://authorwebsite.com' } }; @@ -75,7 +75,7 @@ describe('{{ghost_head}} helper', function () { ' \n' + ' \n' + ' \n' + - ' \n' + + ' \n' + ' \n' + ' \n' + ' \n' + @@ -85,15 +85,15 @@ describe('{{ghost_head}} helper', function () { ' \n' + ' \n' + ' \n' + - ' \n \n' + + ' \n \n' + ' \n\n' + ' \n' + ' '); @@ -107,7 +107,7 @@ describe('{{ghost_head}} helper', function () { meta_description: 'blog "test" description', title: 'title', meta_title: 'Welcome to Ghost "test"', - image: '/test-image.png', + image: '/content/images/test-image.png', published_at: moment('2008-05-31T19:18:15').toISOString(), updated_at: moment('2014-10-06T15:23:54').toISOString(), tags: [{name: 'tag1'}, {name: 'tag2'}, {name: 'tag3'}], @@ -115,7 +115,7 @@ describe('{{ghost_head}} helper', function () { name: 'Author name', url: 'http//:testauthorurl.com', slug: 'Author', - image: '/test-author-image.png', + image: '/content/images/test-author-image.png', website: 'http://authorwebsite.com' } }; @@ -128,7 +128,7 @@ describe('{{ghost_head}} helper', function () { ' \n' + ' \n' + ' \n' + - ' \n' + + ' \n' + ' \n' + ' \n' + ' \n' + @@ -138,15 +138,15 @@ describe('{{ghost_head}} helper', function () { ' \n' + ' \n' + ' \n' + - ' \n \n' + + ' \n \n' + ' \n\n' + ' \n' + ' '); @@ -159,7 +159,7 @@ describe('{{ghost_head}} helper', function () { var post = { meta_description: 'blog description', title: 'Welcome to Ghost', - image: '/test-image.png', + image: '/content/images/test-image.png', published_at: moment('2008-05-31T19:18:15').toISOString(), updated_at: moment('2014-10-06T15:23:54').toISOString(), tags: [], @@ -167,7 +167,7 @@ describe('{{ghost_head}} helper', function () { name: 'Author name', url: 'http//:testauthorurl.com', slug: 'Author', - image: '/test-author-image.png', + image: '/content/images/test-author-image.png', website: 'http://authorwebsite.com' } }; @@ -180,22 +180,22 @@ describe('{{ghost_head}} helper', function () { ' \n' + ' \n' + ' \n' + - ' \n' + + ' \n' + ' \n' + ' \n \n' + ' \n' + ' \n' + ' \n' + ' \n' + - ' \n \n' + + ' \n \n' + ' \n\n' + ' \n' + ' '); @@ -204,7 +204,7 @@ describe('{{ghost_head}} helper', function () { }).catch(done); }); - it('returns structured data on post page without author image and post cover image', function (done) { + it('returns structured data on post page with null author image and post cover image', function (done) { var post = { meta_description: 'blog description', title: 'Welcome to Ghost', @@ -262,7 +262,7 @@ describe('{{ghost_head}} helper', function () { var post = { meta_description: 'blog description', title: 'Welcome to Ghost', - image: '/test-image.png', + image: 'content/images/test-image.png', published_at: moment('2008-05-31T19:18:15').toISOString(), updated_at: moment('2014-10-06T15:23:54').toISOString(), tags: [{name: 'tag1'}, {name: 'tag2'}, {name: 'tag3'}], @@ -270,7 +270,7 @@ describe('{{ghost_head}} helper', function () { name: 'Author name', url: 'http//:testauthorurl.com', slug: 'Author', - image: '/test-author-image.png', + image: 'content/images/test-author-image.png', website: 'http://authorwebsite.com' } }; diff --git a/core/test/unit/server_helpers/image_spec.js b/core/test/unit/server_helpers/image_spec.js new file mode 100644 index 0000000000..d6fb40b1ea --- /dev/null +++ b/core/test/unit/server_helpers/image_spec.js @@ -0,0 +1,69 @@ +/*globals describe, before, afterEach, after, it*/ +/*jshint expr:true*/ +var should = require('should'), + sinon = require('sinon'), + hbs = require('express-hbs'), + utils = require('./utils'), + +// Stuff we are testing + handlebars = hbs.handlebars, + helpers = require('../../../server/helpers'); + +describe('{{image}} helper', function () { + var sandbox; + + before(function () { + sandbox = sinon.sandbox.create(); + utils.overrideConfig({url: 'http://testurl.com/'}); + utils.loadHelpers(); + }); + + afterEach(function () { + sandbox.restore(); + }); + + after(function () { + utils.restoreConfig(); + }); + + it('has loaded image helper', function () { + should.exist(handlebars.helpers.image); + }); + + it('should output relative url of image', function (done) { + helpers.image.call({ + image: '/content/images/image-relative-url.png', + author: { + image: '/content/images/author-image-relatve-url.png' + } + }).then(function (rendered) { + should.exist(rendered); + rendered.should.equal('/content/images/image-relative-url.png'); + done(); + }).catch(done); + }); + + it('should output absolute url of image if the option is present ', function (done) { + helpers.image.call({image: '/content/images/image-relative-url.png', + author: {image: '/content/images/author-image-relatve-url.png'}}, + {hash: {absolute: 'true'}}).then(function (rendered) { + should.exist(rendered); + rendered.should.equal('http://testurl.com/content/images/image-relative-url.png'); + done(); + }).catch(done); + }); + + it('should have no output if there is no image ', function (done) { + helpers.image.call({image: null}, {hash: {absolute: 'true'}}).then(function (rendered) { + should.not.exist(rendered); + done(); + }).catch(done); + }); + + it('should have no output if there is no image property ', function (done) { + helpers.image.call({}, {hash: {absolute: 'true'}}).then(function (rendered) { + should.not.exist(rendered); + done(); + }).catch(done); + }); +});