From 6f457768a2427ae70faa889f1debe3ad6cc455a5 Mon Sep 17 00:00:00 2001 From: Marcos Ojeda Date: Tue, 27 Jan 2015 21:57:19 -0800 Subject: [PATCH] Update `urlFor` to handle 'nav' contexts needed for #4852 Before this, calling `{{url}}` with a nav context from #4541 would output `/`. This adds a check in `urlFor` that looks for keys in a nav context object, namely `slug`, `current`, `label`, & `url`. This change allows for a url to pass through if used in a nav context. * adds `schema.isNav()` * adds tests to `url_spec.js` * handles absolute urls correctly even if `absolute=true` --- core/server/config/url.js | 17 +++++++- core/server/data/schema.js | 8 +++- core/server/helpers/url.js | 4 ++ core/test/unit/server_helpers/url_spec.js | 49 +++++++++++++++++++++++ 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/core/server/config/url.js b/core/server/config/url.js index 0d78b58660..406c3a4e73 100644 --- a/core/server/config/url.js +++ b/core/server/config/url.js @@ -102,7 +102,8 @@ function urlPathForPost(post, permalinks) { function urlFor(context, data, absolute) { var urlPath = '/', secure, imagePathRe, - knownObjects = ['post', 'tag', 'author', 'image'], baseUrl, + knownObjects = ['post', 'tag', 'author', 'image', 'nav'], baseUrl, + hostname, // this will become really big knownPaths = { @@ -151,6 +152,20 @@ function urlFor(context, data, absolute) { } else if (context === 'sitemap-xsl') { absolute = true; urlPath = '/sitemap.xsl'; + } else if (context === 'nav' && data.nav) { + urlPath = data.nav.url; + baseUrl = (secure && ghostConfig.urlSSL) ? ghostConfig.urlSSL : ghostConfig.url; + hostname = baseUrl.split('//')[1] + ghostConfig.paths.subdir; + if (urlPath.indexOf(hostname) > -1) { + // make link relative to account for possible + // mismatch in http/https etc, force absolute + urlPath = '/' + urlPath.split(hostname)[1]; + absolute = true; + } else { // not hosted on this ghost instance, so + // urls with protocols are already absolute + // and otherwise respect the passed in value + absolute = (urlPath.indexOf('://') === -1) && absolute; + } } // other objects are recognised but not yet supported } else if (_.isString(context) && _.indexOf(_.keys(knownPaths), context) !== -1) { diff --git a/core/server/data/schema.js b/core/server/data/schema.js index d33780fa03..4087622be6 100644 --- a/core/server/data/schema.js +++ b/core/server/data/schema.js @@ -198,9 +198,15 @@ function isUser(jsonData) { jsonData.hasOwnProperty('status') && jsonData.hasOwnProperty('location'); } +function isNav(jsonData) { + return jsonData.hasOwnProperty('label') && jsonData.hasOwnProperty('url') && + jsonData.hasOwnProperty('slug') && jsonData.hasOwnProperty('current'); +} + module.exports.tables = db; module.exports.checks = { isPost: isPost, isTag: isTag, - isUser: isUser + isUser: isUser, + isNav: isNav }; diff --git a/core/server/helpers/url.js b/core/server/helpers/url.js index 74de3cdd0b..69c7451783 100644 --- a/core/server/helpers/url.js +++ b/core/server/helpers/url.js @@ -23,6 +23,10 @@ url = function (options) { return config.urlFor('author', {author: this}, absolute); } + if (schema.isNav(this)) { + return config.urlFor('nav', {nav: this}, absolute); + } + return config.urlFor(this, absolute); }; diff --git a/core/test/unit/server_helpers/url_spec.js b/core/test/unit/server_helpers/url_spec.js index fcd215a987..b3f90e7293 100644 --- a/core/test/unit/server_helpers/url_spec.js +++ b/core/test/unit/server_helpers/url_spec.js @@ -93,4 +93,53 @@ describe('{{url}} helper', function () { should.exist(rendered); rendered.should.equal('/'); }); + + it('should return a relative url if passed through a nav context', function () { + var rendered = helpers.url.call( + {url: '/foo', label: 'Foo', slug: 'foo', current: true}); + should.exist(rendered); + rendered.should.equal('/foo'); + }); + + it('should return an absolute url if passed through a nav context', function () { + var rendered = helpers.url.call( + {url: '/bar', label: 'Bar', slug: 'bar', current: true}, + {hash: {absolute: 'true'}}); + should.exist(rendered); + rendered.should.equal('http://testurl.com/bar'); + }); + + it('external urls should be retained in a nav context', function () { + var rendered = helpers.url.call( + {url: 'http://casper.website/baz', label: 'Baz', slug: 'baz', current: true}, + {hash: {absolute: 'true'}}); + should.exist(rendered); + rendered.should.equal('http://casper.website/baz'); + }); + + it('should handle hosted urls in a nav context', function () { + var rendered = helpers.url.call( + {url: 'http://testurl.com/qux', label: 'Qux', slug: 'qux', current: true}, + {hash: {absolute: 'true'}}); + should.exist(rendered); + rendered.should.equal('http://testurl.com/qux'); + }); + + it('should handle hosted urls with the wrong protocol in a nav context', function () { + var rendered = helpers.url.call( + {url: 'https://testurl.com/quux', label: 'Quux', slug: 'quux', current: true}, + {hash: {absolute: 'true'}}); + should.exist(rendered); + rendered.should.equal('http://testurl.com/quux'); + }); + + it('should handle subdir being set in nav context', function () { + utils.overrideConfig({url: 'http://testurl.com/blog'}); + + var rendered = helpers.url.call( + {url: '/xyzzy', label: 'xyzzy', slug: 'xyzzy', current: true}, + {hash: {absolute: 'true'}}); + should.exist(rendered); + rendered.should.equal('http://testurl.com/blog/xyzzy'); + }); });