From 12f8f990887527b35f925b525b8917aecdcbd03c Mon Sep 17 00:00:00 2001 From: Fabian Becker Date: Sat, 8 Feb 2014 21:12:04 +0100 Subject: [PATCH] Implements the #has Block helper closes #2115 - Added new #has block helper - Added several tests for #has helper --- core/server/helpers/index.js | 33 ++++++++++++ core/test/unit/server_helpers_index_spec.js | 58 +++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/core/server/helpers/index.js b/core/server/helpers/index.js index f34c9b2b16..73d1d63641 100644 --- a/core/server/helpers/index.js +++ b/core/server/helpers/index.js @@ -572,6 +572,37 @@ coreHelpers.foreach = function (context, options) { return ret; }; +// ### Has Helper +// `{{#has tag="video, music"}}` +// Checks whether a post has at least one of the tags +coreHelpers.has = function (options) { + var tags = _.pluck(this.tags, 'name'), + tagList = options && options.hash ? options.hash.tag : false; + + function evaluateTagList(expr, tags) { + return expr.split(',').map(function (v) { + return v.trim(); + }).reduce(function (p, c) { + return p || (_.findIndex(tags, function (item) { + // Escape regex special characters + item = item.replace(/[\-\/\\\^$*+?.()|\[\]{}]/g, '\\$&'); + item = new RegExp(item, 'i'); + return item.test(c); + }) !== -1); + }, false); + } + + if (!tagList) { + errors.logWarn("Invalid or no attribute given to has helper"); + return; + } + + if (tagList && evaluateTagList(tagList, tags)) { + return options.fn(this); + } + return options.inverse(this); +}; + // ### Pagination Helper // `{{pagination}}` // Outputs previous and next buttons, along with info about the current page @@ -702,6 +733,8 @@ registerHelpers = function (adminHbs, assetHash) { registerThemeHelper('foreach', coreHelpers.foreach); + registerThemeHelper('has', coreHelpers.has); + registerThemeHelper('page_url', coreHelpers.page_url); registerThemeHelper('pageUrl', coreHelpers.pageUrl); diff --git a/core/test/unit/server_helpers_index_spec.js b/core/test/unit/server_helpers_index_spec.js index abb78ba6c9..5e64ef5fdc 100644 --- a/core/test/unit/server_helpers_index_spec.js +++ b/core/test/unit/server_helpers_index_spec.js @@ -427,6 +427,64 @@ describe('Core Helpers', function () { }); }); + describe('has Block Helper', function () { + it('has loaded has block helper', function () { + should.exist(handlebars.helpers.has); + }); + + it('should handle tag list that validates true', function () { + var fn = sinon.spy(), + inverse = sinon.spy(); + + helpers.has.call( + {tags: [{ name: 'foo'}, { name: 'bar'}, { name: 'baz'}]}, + {hash: { tag: 'invalid, bar, wat'}, fn: fn, inverse: inverse} + ); + + fn.called.should.be.true; + inverse.called.should.be.false; + }); + + it('should handle tags with case-insensitivity', function () { + var fn = sinon.spy(), + inverse = sinon.spy(); + + helpers.has.call( + {tags: [{ name: 'ghost'}]}, + {hash: { tag: 'GhoSt'}, fn: fn, inverse: inverse} + ); + + fn.called.should.be.true; + inverse.called.should.be.false; + }); + + it('should handle tag list that validates false', function () { + var fn = sinon.spy(), + inverse = sinon.spy(); + + helpers.has.call( + {tags: [{ name: 'foo'}, { name: 'bar'}, { name: 'baz'}]}, + {hash: { tag: 'much, such, wow'}, fn: fn, inverse: inverse} + ); + + fn.called.should.be.false; + inverse.called.should.be.true; + }); + + it('should not do anything when an invalid attribute is given', function () { + var fn = sinon.spy(), + inverse = sinon.spy(); + + helpers.has.call( + {tags: [{ name: 'foo'}, { name: 'bar'}, { name: 'baz'}]}, + {hash: { invalid: 'nonsense'}, fn: fn, inverse: inverse} + ); + + fn.called.should.be.false; + inverse.called.should.be.false; + }); + }); + describe('url Helper', function () { it('has loaded url helper', function () { should.exist(handlebars.helpers.url);