├── .travis.yml ├── .gitignore ├── index.js ├── lib ├── urlify.js ├── subtract.js ├── calendar.js ├── encodeURIComponent.js ├── title-case.js ├── capitalize.js ├── possessive.js ├── number.js ├── paragraphify.js ├── join.js ├── abbr-count.js ├── indefinite-article.js ├── if-lt.js ├── if-gt.js ├── firstof.js ├── not-eq.js ├── repeat.js ├── eq.js ├── chr-gt.js ├── chr-lt.js ├── neither.js ├── either.js ├── each-reverse.js ├── each-key.js ├── each-limit.js ├── iter.js ├── truncate.js ├── input-select.js └── pack-it.js ├── test ├── subtract.js ├── urlify.js ├── join.js ├── title-case.js ├── bin │ ├── hash.js │ └── build.js ├── calendar.js ├── capitalize.js ├── possessive.js ├── paragraphify.js ├── abbr-count.js ├── indefinite-article.js ├── repeat.js ├── each-reverse.js ├── firstof.js ├── eq.js ├── not-eq.js ├── each-limit.js ├── either.js ├── neither.js ├── each-key.js ├── pack-it.js ├── number.js ├── if-gt.js ├── if-lt.js ├── chr-lt.js ├── chr-gt.js ├── iter.js ├── truncate.js └── input-select.js ├── makefile ├── bin ├── hash.js └── build.js ├── package.json ├── LICENSE.md ├── register.js └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.6 4 | - 0.8 5 | - 0.10 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /* MacOS */ 2 | .DS_Store 3 | 4 | /* NPM */ 5 | /node_modules 6 | npm* 7 | 8 | /* Other */ 9 | .notes.txt -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var helpers = require('require-all')({ 2 | 'dirname': __dirname + '/lib', 3 | 'filter': /(.+)\.js$/ 4 | }); 5 | 6 | module.exports = helpers; 7 | -------------------------------------------------------------------------------- /lib/urlify.js: -------------------------------------------------------------------------------- 1 | module.exports = function urlify (string) { 2 | if (!string) return ''; 3 | return string.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9\-]/g, ''); 4 | }; 5 | -------------------------------------------------------------------------------- /lib/subtract.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Reduces a number by given amount 3 | * {{subtract a.length 2}} 4 | */ 5 | module.exports = function subtract (object, reducer) { 6 | return object - reducer; 7 | }; 8 | -------------------------------------------------------------------------------- /lib/calendar.js: -------------------------------------------------------------------------------- 1 | var moment = require('moment'); 2 | 3 | module.exports = function calendar (timestamp) { 4 | var time = moment.utc(timestamp); 5 | return '' + time.format('MMM DD, YYYY') + ''; 6 | } 7 | -------------------------------------------------------------------------------- /lib/encodeURIComponent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Proxy for the native js `encodeURIComponent`. 3 | * 4 | * @param {string} str 5 | */ 6 | module.exports = function encodeURIComponentHelper (str) { 7 | return encodeURIComponent(str); 8 | }; 9 | -------------------------------------------------------------------------------- /test/subtract.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var subtract = require('../lib/subtract'); 4 | 5 | test('subtract', function (t) { 6 | t.plan(1); 7 | 8 | t.equals(subtract(10, 5), 5, 'should be 5'); 9 | }); 10 | -------------------------------------------------------------------------------- /test/urlify.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var urlify = require('../lib/urlify'); 4 | 5 | test('urlify', function (t) { 6 | t.plan(1); 7 | 8 | t.equals(urlify('Beep Boop'), 'beep-boop', 'urlified'); 9 | }); 10 | -------------------------------------------------------------------------------- /lib/title-case.js: -------------------------------------------------------------------------------- 1 | module.exports = function titleCase (str) { 2 | if (typeof str === 'undefined') return ''; 3 | 4 | return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}); 5 | }; 6 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | build: 2 | node ./bin/build.js 3 | 4 | hash: 5 | node ./bin/hash.js 6 | 7 | browserify: 8 | browserify -x ../../node_modules/lodash -x ../../node_modules/handlebars-runtime -x ../pack-it -r ./register.js > ./helpers.bundled.js 9 | -------------------------------------------------------------------------------- /test/join.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var join = require('../lib/join'); 4 | 5 | test('non array', function (t) { 6 | t.plan(1); 7 | 8 | t.equal(join(false), '', 'should return empty string for non arrays'); 9 | }); 10 | -------------------------------------------------------------------------------- /lib/capitalize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Capitalizes a word 3 | * {{capitalize lowercase.word}} 4 | * 5 | * @param {string} word 6 | */ 7 | module.exports = function capitalize (word) { 8 | return word.charAt(0).toUpperCase() + word.slice(1); 9 | }; 10 | -------------------------------------------------------------------------------- /test/title-case.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var titleCase = require('../lib/title-case'); 4 | 5 | test('title case', function (t) { 6 | t.plan(1); 7 | 8 | t.equals(titleCase('beep boop'), 'Beep Boop', 'title case works'); 9 | }); 10 | -------------------------------------------------------------------------------- /lib/possessive.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Someone -> Someone's 3 | * Alexis -> Alexis' 4 | * {{posessive maker.name}} 5 | * 6 | @ @param {string} str 7 | */ 8 | module.exports = function possessive (str) { 9 | return str + (str.charAt(str.length - 1) === 's' ? '\'' : '\'s'); 10 | }; 11 | -------------------------------------------------------------------------------- /lib/number.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Pretty prints a number with commas. 3 | * See: http://stackoverflow.com/a/2901298/147471 4 | * 5 | * @param {number} number 6 | */ 7 | module.exports = function number (value) { 8 | return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); 9 | }; 10 | -------------------------------------------------------------------------------- /bin/hash.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | var helpersPath = './lib'; 4 | 5 | fs.readdir(helpersPath, function componentsDir (err, files) { 6 | files.forEach(function (file) { 7 | console.log('\'' + file.replace('.js', '') + '\': require(\'./lib/' + file + '\'),'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /test/bin/hash.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | var helpersPath = './helpers'; 4 | 5 | fs.readdir(helpersPath, function componentsDir (err, files) { 6 | files.forEach(function (file) { 7 | console.log('\'' + file.replace('.js', '') + '\': require(\'./helpers/' + file + '\'),'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /lib/paragraphify.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Replaces line breaks with paragraphs 3 | * 4 | * @param {string} str 5 | */ 6 | module.exports = function paragraphify (str) { 7 | return '

' + str 8 | .replace(/^\s\s/, '') 9 | .replace(/\s*\s$/, '') 10 | .replace(/(\r?\n)+/, '

') + '

'; 11 | }; 12 | -------------------------------------------------------------------------------- /bin/build.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | var helpersPath = './lib'; 4 | 5 | fs.readdir(helpersPath, function componentsDir (err, files) { 6 | files.forEach(function (file) { 7 | console.log('Handlebars.registerHelper(\'' + file.replace('.js', '') + '\', require(\'./lib/' + file + '\'));'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /test/calendar.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var calendar = require('../lib/calendar.js'); 4 | var date = '2013-10-09T21:43:33.396Z'; 5 | 6 | test('calendar', function (t) { 7 | t.plan(1); 8 | 9 | t.equal(calendar(date), 'Oct 09, 2013', 'should be the correct date'); 10 | }); -------------------------------------------------------------------------------- /lib/join.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Joins an array by a delimiter. 3 | * {{join array ","}} 4 | * 5 | * @param {array} array 6 | @ @param {string} delimiter 7 | */ 8 | module.exports = function join (array, delimiter) { 9 | return typeof array.join === 'function' ? array.join((typeof delimiter === 'string') ? delimiter : ',') : ''; 10 | }; 11 | -------------------------------------------------------------------------------- /lib/abbr-count.js: -------------------------------------------------------------------------------- 1 | module.exports = function abbrCount (val) { 2 | var count = parseInt(val, 10); 3 | var countString = val + ''; 4 | var symbol = ''; 5 | 6 | if (count >= 1000) { 7 | symbol = 'k+'; 8 | return countString.substring(0, 1) + symbol; 9 | } 10 | 11 | return countString; 12 | }; 13 | -------------------------------------------------------------------------------- /test/bin/build.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | var helpersPath = './helpers'; 4 | 5 | fs.readdir(helpersPath, function componentsDir (err, files) { 6 | files.forEach(function (file) { 7 | console.log('Handlebars.registerHelper(\'' + file.replace('.js', '') + '\', require(\'./helpers/' + file + '\'));'); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /test/capitalize.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var capitalize = require('../lib/capitalize'); 4 | 5 | test('capitalize', function (t) { 6 | t.plan(2); 7 | 8 | t.equals(capitalize('bleep'), 'Bleep', 'should capitalize'); 9 | t.equals(capitalize('bleep bloop'), 'Bleep bloop', 'should capitalize first word only'); 10 | }); 11 | -------------------------------------------------------------------------------- /lib/indefinite-article.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Oceanographer -> 'an' 3 | * Maker -> 'a' 4 | * Aquarium -> 'an' 5 | * 6 | * @param {string} str 7 | */ 8 | module.exports = function indefiniteArticle (str) { 9 | if (!str || !str.length) return 'a'; 10 | return (['a','e','i','o','u'].indexOf(str.charAt(0).toLowerCase()) === -1) ? 'a' : 'an'; 11 | }; 12 | -------------------------------------------------------------------------------- /test/possessive.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var possessive = require('../lib/possessive'); 4 | 5 | test('possessive', function (t) { 6 | t.plan(2); 7 | 8 | t.equal(possessive('Beep'), 'Beep\'s', 'beep should add \'s at end'); 9 | t.equal(possessive('Boops'), 'Boops\'', 'boops should add \' before trailing s'); 10 | }); 11 | -------------------------------------------------------------------------------- /lib/if-lt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * If Less-Than Helper. Renders the block none of the first 3 | * argument is less than the second. 4 | * 5 | * {{#if-lt a 5}} content {{/if-lt}} 6 | */ 7 | module.exports = function ifLt (a, b) { 8 | var options = arguments[arguments.length - 1]; 9 | if (a < b) { return options.fn(this); } 10 | else { return options.inverse(this); } 11 | }; 12 | -------------------------------------------------------------------------------- /lib/if-gt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * If Greater-Than Helper. Renders the block none of the first 3 | * argument is greater than the second. 4 | * 5 | * {{#if-lt a 5}} content {{/if-lt}} 6 | */ 7 | module.exports = function ifGt (a, b) { 8 | var options = arguments[arguments.length - 1]; 9 | if (a > b) { return options.fn(this); } 10 | else { return options.inverse(this); } 11 | }; 12 | -------------------------------------------------------------------------------- /lib/firstof.js: -------------------------------------------------------------------------------- 1 | // Will return the first turthy value. 2 | // Handy for setting default values. 3 | module.exports = function firstof () { 4 | // Use everything, but the options object 5 | var valuesLength = arguments.length - 1; 6 | 7 | for (var i = 0; i < valuesLength; i++) { 8 | var value = arguments[i]; 9 | if (value) return value; 10 | } 11 | 12 | return ''; 13 | }; 14 | -------------------------------------------------------------------------------- /lib/not-eq.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Inverse of of #eq block helper. 3 | * {{#not-eq a b}} content {{/not-eq}} 4 | * 5 | * @param {object} obj3 6 | * @param {object} obj2 7 | * @param {object} options 8 | */ 9 | module.exports = function notEqual (obj1, obj2, options) { 10 | if (obj1 !== obj2) { 11 | return options.fn(this); 12 | } else { 13 | return options.inverse(this); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /lib/repeat.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Repeats a block `n` times. 3 | * {{#repeat 5}} Hello! {{/repeat}} 4 | * 5 | * @param {number} n 6 | */ 7 | module.exports = function repeat (n) { 8 | var options = arguments[arguments.length - 1], ret = ''; 9 | if (typeof n === 'string') n = parseInt(n, 10); 10 | for (var i = 0; i < n; i++) { 11 | ret += options.fn(this); 12 | } 13 | return ret; 14 | }; 15 | -------------------------------------------------------------------------------- /test/paragraphify.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var paragraphify = require('../lib/paragraphify'); 4 | 5 | test('paragraphify', function (t) { 6 | t.plan(1); 7 | 8 | var testStr = 'Line1\n' + 'Line2\n' + 'Line3'; 9 | var expected = '

Line1

Line2\nLine3

'; 10 | var result = paragraphify(testStr); 11 | 12 | t.equals(result, expected, 'should create 2 paragraphs'); 13 | }); 14 | -------------------------------------------------------------------------------- /test/abbr-count.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var abbrCount = require('../lib/abbr-count'); 4 | 5 | test('less than 1000', function (t) { 6 | t.plan(1); 7 | 8 | t.equals(abbrCount(999), '999', 'value should remain uncahnged'); 9 | }); 10 | 11 | test('greater than 1000', function (t) { 12 | t.plan(1); 13 | 14 | t.equals(abbrCount(2000), '2k+', 'should abbreviate and append symbol'); 15 | }); 16 | -------------------------------------------------------------------------------- /lib/eq.js: -------------------------------------------------------------------------------- 1 | /** 2 | * If equality block helper. Renders the block if `obj1` equals `obj2` (strict). 3 | * {{#eq a b}} content {{/eq}} 4 | * 5 | * @param {object} obj1 6 | * @param {object} obj2 7 | * @param {object} options 8 | */ 9 | module.exports = function eq (obj1, obj2, options) { 10 | if (obj1 === obj2) { 11 | return options.fn(this); 12 | } else { 13 | return options.inverse(this); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /lib/chr-gt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Conditional for determining if the character length of a string 3 | * is greater than the provided max value. 4 | * {{#chr-gt someString 10}}...{{/chr-gt}} 5 | * 6 | * @param {string} Any string. 7 | * @param {int} The max number of characters. 8 | */ 9 | 10 | module.exports = function chrGt (str, length, options) { 11 | if (str.length > length) { 12 | return options.fn(this); 13 | } else { 14 | return options.inverse(this); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /lib/chr-lt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Conditional for determining if the character length of a string 3 | * is less than the provided min value. 4 | * {{#chr-lt someString 10}}...{{/chr-lt}} 5 | * 6 | * @param {string} Any string. 7 | * @param {int} The min number of characters. 8 | */ 9 | 10 | module.exports = function chrLt (str, length, options) { 11 | if (str.length < length) { 12 | return options.fn(this); 13 | } else { 14 | return options.inverse(this); 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /lib/neither.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Neither Helper. Renders the block if all arguments have 3 | * a falsey value. 4 | * 5 | * {{#neither a b c}} content {{/neither}} 6 | */ 7 | module.exports = function neither () { 8 | var options = arguments[arguments.length - 1]; 9 | 10 | for (var i = 0; i < arguments.length - 1; i++) { 11 | if (typeof arguments[i] !== 'undefined' && !arguments[i]) { 12 | return options.fn(this); 13 | } 14 | } 15 | return options.inverse(this); 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /lib/either.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Either Helper. Renders the block if any one of the 3 | * arguments has a truthy value. 4 | * 5 | * {{#either a b c}} content {{/either}} 6 | */ 7 | module.exports = function either () { 8 | var options = arguments[arguments.length - 1]; 9 | 10 | for (var i = 0; i < arguments.length - 1; i++) { 11 | if (typeof arguments[i] !== 'undefined' && arguments[i]) { 12 | return options.fn(this); 13 | } 14 | } 15 | return options.inverse(this); 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /test/indefinite-article.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var idefiniteArticle = require('../lib/indefinite-article'); 4 | 5 | test('an', function (t) { 6 | t.plan(2); 7 | 8 | t.equal(idefiniteArticle('Oceanographer'), 'an', 'should be an'); 9 | t.equal(idefiniteArticle('Aquarium'), 'an', 'should be an'); 10 | }); 11 | 12 | test('a', function (t) { 13 | t.plan(2); 14 | 15 | t.equal(idefiniteArticle('Maker'), 'a', 'should be a'); 16 | t.equal(idefiniteArticle('Poop'), 'a', 'should be a'); 17 | }); 18 | -------------------------------------------------------------------------------- /test/repeat.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var repeat = require('../lib/repeat'); 4 | 5 | test('repeat', function (t) { 6 | t.plan(1); 7 | 8 | var callCount = 0; 9 | 10 | var subject = 'hey'; 11 | var expected = 'heyheyheyheyheyheyhey'; 12 | 13 | var result = repeat(7, { 14 | 'fn': function repeatCallback (scope) { 15 | callCount++; 16 | 17 | return subject; 18 | } 19 | }); 20 | 21 | t.equals(expected, result, 'there should be 7 heys'); 22 | }); 23 | -------------------------------------------------------------------------------- /test/each-reverse.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var eachReverse = require('../lib/each-reverse'); 4 | 5 | test('each limit', function (t) { 6 | t.plan(2); 7 | 8 | var callCount = 0; 9 | 10 | var obj = ['bleep', 'bloop']; 11 | var reverse = ['bloop', 'bleep']; 12 | 13 | eachReverse(obj, 1, { 14 | 'fn': function eachReverseCallback (scope) { 15 | t.equals(scope, reverse[callCount], 'should match reverse array item'); 16 | 17 | callCount++; 18 | } 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /test/firstof.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var firstof = require('../lib/firstof'); 4 | 5 | // Stub out the options object passed to all helpers 6 | var stub = {}; 7 | 8 | test('firstof', function (t) { 9 | t.plan(3); 10 | 11 | t.equals(firstof(null, null, 'test', 'test2', stub), 'test', 'should return third position "test"'); 12 | t.equals(firstof('test', null, null, 'test2', stub), 'test', 'should return first position "test"'); 13 | t.equals(firstof(null, null, 'test', stub), 'test', 'should return last position "test"'); 14 | }); 15 | -------------------------------------------------------------------------------- /test/eq.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var eq = require('../lib/eq'); 4 | 5 | test('equal arguments', function (t) { 6 | t.plan(1); 7 | 8 | eq(true, true, { 9 | 'fn': function trueCallback () { 10 | t.ok(true, 'truthy callback was called'); 11 | } 12 | }); 13 | }); 14 | 15 | test('NOT equal arguments', function (t) { 16 | t.plan(1); 17 | 18 | eq(true, false, { 19 | 'inverse': function trueCallback () { 20 | t.ok(true, 'falsey callback was called'); 21 | } 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /lib/each-reverse.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Each Helper (in reverse). 3 | * 4 | * {{#each-reverse items 3}} 5 | * {{/each-reverse}} 6 | * 7 | * @param {array} context 8 | */ 9 | module.exports = function eachReverse (context) { 10 | var options = arguments[arguments.length - 1]; 11 | var ret = ''; 12 | 13 | if (context && context.length > 0) { 14 | for (var i = context.length - 1; i >= 0; i--) { 15 | ret += options.fn(context[i]); 16 | } 17 | } else { 18 | ret = options.inverse(this); 19 | } 20 | 21 | return ret; 22 | }; 23 | -------------------------------------------------------------------------------- /test/not-eq.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var notEq = require('../lib/not-eq'); 4 | 5 | test('not equal arguments', function (t) { 6 | t.plan(1); 7 | 8 | notEq(true, true, { 9 | 'inverse': function trueCallback () { 10 | t.ok(true, 'falsey callback was called'); 11 | } 12 | }); 13 | }); 14 | 15 | test('NOT equal arguments', function (t) { 16 | t.plan(1); 17 | 18 | notEq(true, false, { 19 | 'fn': function trueCallback () { 20 | t.ok(true, 'truthy callback was called'); 21 | } 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /lib/each-key.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Object Iteration Helper (w/key extraction). 3 | * 4 | * {{#each-key object}} 5 | * Key: {{this.key}} Value: {{this.value}} 6 | * {{/each-key}} 7 | * 8 | * @param {object} object 9 | */ 10 | module.exports = function eachKey (object) { 11 | var options = arguments[arguments.length - 1]; 12 | var ret = ''; 13 | for (var key in object) { 14 | if (object.hasOwnProperty(key)) { 15 | ret += options.fn({ 16 | key: key, 17 | value: object[key] 18 | }); 19 | } 20 | } 21 | return ret; 22 | }; 23 | -------------------------------------------------------------------------------- /test/each-limit.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var eachLimit = require('../lib/each-limit'); 4 | 5 | test('each limit', function (t) { 6 | t.plan(1); 7 | 8 | var callCount = 0; 9 | 10 | var obj = ['bleep', 'bloop']; 11 | 12 | eachLimit(obj, 1, { 13 | 'fn': function eachLimitCallback (scope) { 14 | if (callCount > 1) { 15 | t.notOk(true, 'This should have iterated once'); 16 | } 17 | 18 | t.equals(scope, obj[callCount], 'should match first array item'); 19 | 20 | callCount++; 21 | } 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/either.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var either = require('../lib/either'); 4 | 5 | test('with a truthy argument', function (t) { 6 | t.plan(1); 7 | 8 | either(false, true, false, { 9 | 'fn': function trueCallback () { 10 | t.ok(true, 'truthy callback was called'); 11 | } 12 | }); 13 | }); 14 | 15 | test('with no truthy arguments', function (t) { 16 | t.plan(1); 17 | 18 | either(false, false, false, { 19 | 'inverse': function trueCallback () { 20 | t.ok(true, 'falsey callback was called'); 21 | } 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/neither.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var neither = require('../lib/neither'); 4 | 5 | test('with a falsey arguments', function (t) { 6 | t.plan(1); 7 | 8 | neither(true, false, true, { 9 | 'fn': function trueCallback () { 10 | t.ok(true, 'truthy callback was called'); 11 | } 12 | }); 13 | }); 14 | 15 | test('with no falsey arguments', function (t) { 16 | t.plan(1); 17 | 18 | neither(true, true, true, { 19 | 'inverse': function trueCallback () { 20 | t.ok(true, 'falsey callback was called'); 21 | } 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /lib/each-limit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Each Helper (w/limit). 3 | * 4 | * {{#each-limit items 3}} 5 | * {{/each-limit}} 6 | * 7 | * @param {array} context 8 | * @param {number} limit 9 | */ 10 | module.exports = function eachLimit (context, limit) { 11 | var options = arguments[arguments.length - 1]; 12 | var ret = ''; 13 | 14 | if (context && context.length > 0) { 15 | var max = Math.min(context.length, limit); 16 | for (var i = 0; i < max; i++) { 17 | ret += options.fn(context[i]); 18 | } 19 | } else { 20 | ret = options.inverse(this); 21 | } 22 | 23 | return ret; 24 | }; 25 | -------------------------------------------------------------------------------- /lib/iter.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | 3 | /** 4 | * Adds the current index and next index to iteration scope. 5 | * 6 | * {{#iter items}} 7 | * {{/iter}} 8 | * 9 | * @param {array} context 10 | */ 11 | module.exports = function iter (context, options) { 12 | var fn = options.fn, inverse = options.inverse; 13 | var ret = ""; 14 | 15 | if (context && context.length > 0) { 16 | for (var i = 0, j = context.length; i < j; i++) { 17 | ret = ret + fn(_.extend({}, context[i], { i: i, iPlus1: i + 1 })); 18 | } 19 | } else { 20 | ret = inverse(this); 21 | } 22 | return ret; 23 | }; 24 | -------------------------------------------------------------------------------- /lib/truncate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Truncates string to first 10 characters and appends an ellipses. 3 | * Can override truncate length and appending string. 4 | * 5 | * {{truncate someLongString}} 6 | * 7 | * @param {string} subject 8 | * @param {number} truncation amount (how many characters to print) 9 | * @param {string} string to append (can provide empty string to remove everything) 10 | */ 11 | module.exports = function capitalize (str, length, append) { 12 | str = str || ''; 13 | length = length || 10; 14 | append = typeof append === 'undefined' ? '…' : append; 15 | 16 | if (str.length === length) return str; 17 | 18 | return str.substring(0, length).replace(/\s+$|\.+$/, '') + append; 19 | }; 20 | -------------------------------------------------------------------------------- /test/each-key.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var eachKey = require('../lib/each-key'); 4 | 5 | test('each item calls callback with `key` `value` in scope', function (t) { 6 | t.plan(4); 7 | 8 | var callCount = 0; 9 | 10 | var obj = { 11 | 'bleep': 'bloop', 12 | 'zip': 'zap' 13 | }; 14 | 15 | eachKey(obj, { 16 | 'fn': function eachKeyCallback (scope) { 17 | t.ok(obj.hasOwnProperty(scope.key), scope.key + ' key exist in original object'); 18 | t.equal(obj[scope.key], scope.value, scope.key + ' value matches original object'); 19 | 20 | if (callCount === 2) return t.end(); 21 | callCount++; 22 | } 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /test/pack-it.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var packIt = require('../lib/pack-it'); 4 | 5 | test('iteration scope', function (t) { 6 | t.plan(6); 7 | 8 | var callCount = 1; // start at 1 since the first item is skipped in pack-it 9 | 10 | var obj = [ 11 | 'bleep', 12 | 'bloop', 13 | 'zip', 14 | 'zap' 15 | ]; 16 | 17 | packIt(obj, { 18 | 'fn': function packItCallback (scope) { 19 | t.equals(scope.content, obj[callCount], callCount + ' content is correct'); 20 | t.type(scope.size, 'number', ' size is number'); 21 | 22 | if (callCount === 3) return t.end(); 23 | callCount++; 24 | } 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/number.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var number = require('../lib/number'); 4 | 5 | test('hundreds', function (t) { 6 | t.plan(1); 7 | 8 | t.equal(number(100), '100', 'should be the same'); 9 | }); 10 | 11 | test('thousands', function (t) { 12 | t.plan(1); 13 | 14 | t.equal(number(1000), '1,000', 'should add a comma at thousands place'); 15 | }); 16 | 17 | test('tens of thousands', function (t) { 18 | t.plan(1); 19 | 20 | t.equal(number(10000), '10,000', 'should add a comma at ten-thounsands place'); 21 | }); 22 | 23 | test('hudreds of thousands', function (t) { 24 | t.plan(1); 25 | 26 | t.equal(number(100000), '100,000', 'should add a comma at hundred-thounsands place'); 27 | }); 28 | -------------------------------------------------------------------------------- /test/if-gt.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var ifGt = require('../lib/if-gt'); 4 | 5 | test('obj1 gt obj2', function (t) { 6 | t.plan(1); 7 | 8 | ifGt(10, 5, { 9 | 'fn': function trueCallback () { 10 | t.ok(true, 'truthy callback was called'); 11 | } 12 | }); 13 | }); 14 | 15 | test('obj1 lt obj2', function (t) { 16 | t.plan(1); 17 | 18 | ifGt(5, 10, { 19 | 'inverse': function trueCallback () { 20 | t.ok(true, 'falsey callback was called'); 21 | } 22 | }); 23 | }); 24 | 25 | test('obj1 eq obj2', function (t) { 26 | t.plan(1); 27 | 28 | ifGt(5, 5, { 29 | 'inverse': function trueCallback () { 30 | t.ok(true, 'falsey callback was called'); 31 | } 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/if-lt.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var ifLt = require('../lib/if-lt'); 4 | 5 | test('obj1 lt obj2', function (t) { 6 | t.plan(1); 7 | 8 | ifLt(5, 10, { 9 | 'fn': function trueCallback () { 10 | t.ok(true, 'truthy callback was called'); 11 | } 12 | }); 13 | }); 14 | 15 | test('obj1 gt obj2', function (t) { 16 | t.plan(1); 17 | 18 | ifLt(10, 5, { 19 | 'inverse': function trueCallback () { 20 | t.ok(true, 'falsey callback was called'); 21 | } 22 | }); 23 | }); 24 | 25 | test('obj1 eq obj2', function (t) { 26 | t.plan(1); 27 | 28 | ifLt(5, 5, { 29 | 'inverse': function trueCallback () { 30 | t.ok(true, 'falsey callback was called'); 31 | } 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /lib/input-select.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Builds a ']; 15 | for (var i = 0; i < options.length; i++) { 16 | html.push(''); 17 | } 18 | html.push(''); 19 | return html.join(''); 20 | }; 21 | -------------------------------------------------------------------------------- /test/chr-lt.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var chrLt = require('../lib/chr-lt'); 4 | 5 | test('character length less than', function (t) { 6 | t.plan(1); 7 | 8 | chrLt('beepbooplol', 20, { 9 | 'fn': function gtCallback () { 10 | t.ok(true, 'character length is less than 20'); 11 | } 12 | }); 13 | }); 14 | 15 | test('character length equal', function (t) { 16 | t.plan(1); 17 | 18 | chrLt('beepbooplol', 11, { 19 | 'inverse': function gtCallback () { 20 | t.ok(true, 'equal length calls inverse'); 21 | } 22 | }); 23 | }); 24 | 25 | test('character length greater than', function (t) { 26 | t.plan(1); 27 | 28 | chrLt('beepbooplol', 10, { 29 | 'inverse': function gtCallback () { 30 | t.ok(true, 'greater length calls inverse'); 31 | } 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/chr-gt.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var chrGt = require('../lib/chr-gt'); 4 | 5 | test('character length greater than', function (t) { 6 | t.plan(1); 7 | 8 | chrGt('beepbooplol', 10, { 9 | 'fn': function gtCallback () { 10 | t.ok(true, 'character length is greater than 10'); 11 | } 12 | }); 13 | }); 14 | 15 | test('character length equal', function (t) { 16 | t.plan(1); 17 | 18 | chrGt('beepbooplol', 11, { 19 | 'inverse': function gtCallback () { 20 | t.ok(true, 'equal length calls inverse'); 21 | } 22 | }); 23 | }); 24 | 25 | test('character length less than', function (t) { 26 | t.plan(1); 27 | 28 | chrGt('beepbooplol', 20, { 29 | 'inverse': function gtCallback () { 30 | t.ok(true, 'less than length calls inverse'); 31 | } 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/iter.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var iter = require('../lib/iter'); 4 | 5 | test('each iteration adds index to scope', function (t) { 6 | t.plan(4); 7 | 8 | var callCount = 0; 9 | 10 | var obj = [ 11 | 'bleep', 12 | 'bloop' 13 | ]; 14 | 15 | iter(obj, { 16 | 'fn': function eachKeyCallback (scope) { 17 | t.ok(scope.hasOwnProperty('i'), 'scope has i'); 18 | t.equals(scope.i, callCount, obj[scope.i] + ' correct iteration ' + scope.i); 19 | 20 | if (callCount === 2) return t.end(); 21 | callCount++; 22 | } 23 | }); 24 | }); 25 | 26 | test('empty iterator', function (t) { 27 | t.plan(1); 28 | 29 | iter([], { 30 | 'inverse': function inverseCallback () { 31 | t.ok(true, 'inverse callback called') 32 | } 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Derek Reynolds (http://diy.org/drk)", 3 | "name": "diy-handlebars-helpers", 4 | "description": "Collection of generic handlebars helpers.", 5 | "license": { 6 | "type": "Apache-2.0", 7 | "url": "http://www.apache.org/licenses/LICENSE-2.0" 8 | }, 9 | "version": "1.0.10", 10 | "homepage": "https://github.com/diy/handlebars-helpers", 11 | "repository": { 12 | "type": "git", 13 | "url": "diy/handlebars-helpers" 14 | }, 15 | "main": "./index.js", 16 | "scripts": { 17 | "test": "tap ./test/*.js" 18 | }, 19 | "dependencies": { 20 | "lodash": "~1.3.1", 21 | "pack-it": "~1.0.0", 22 | "require-all": "0.0.8", 23 | "moment": "~2.3.1" 24 | }, 25 | "devDependencies": { 26 | "tap": "~0.3.1", 27 | "codebux": "~0.1.2" 28 | }, 29 | "optionalDependencies": {}, 30 | "engines": { 31 | "node": ">=0.6" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/truncate.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var truncate = require('../lib/truncate'); 4 | 5 | var testString = 'This is longer than 10 characters'; 6 | 7 | test('default', function (t) { 8 | t.plan(1); 9 | 10 | t.equals(truncate(testString), 'This is lo…', 'should truncate to 10 characters and append hellip'); 11 | }); 12 | 13 | test('provided truncate amount', function (t) { 14 | t.plan(1); 15 | 16 | t.equals(truncate(testString, 15), 'This is longer…', 'should truncate to 15 characters and append hellip'); 17 | }); 18 | 19 | test('custom append', function (t) { 20 | t.plan(2); 21 | 22 | t.equals(truncate(testString, 10, ''), 'This is lo', 'should not append anything'); 23 | t.equals(truncate(testString, 10, 'hey'), 'This is lohey', 'should append "hey"'); 24 | }); 25 | 26 | test('email addresses', function (t) { 27 | t.plan(1); 28 | 29 | t.equals(truncate('something@example.com', 18), 'something@example…', 'should remove trailing dots'); 30 | }); 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Derek Reynolds. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /test/input-select.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test; 2 | 3 | var inputSelect = require('../lib/input-select'); 4 | 5 | test('input select', function (t) { 6 | t.plan(2); 7 | 8 | var options = [ 9 | {'label': 'Option 1', 'value': 'option-1'}, 10 | {'label': 'Option 2', 'value': 'option-2', 'selected': true} 11 | ]; 12 | var expected = ''; 13 | 14 | var result = inputSelect('test', options); 15 | 16 | t.equals(expected, result, 'expected output'); 17 | t.ok(result.indexOf('value="option-2" selected="selected"'), 'option 2 should be selected'); 18 | }); 19 | 20 | test('provided selected value', function (t) { 21 | t.plan(1); 22 | 23 | var options = [ 24 | {'label': 'Option 1', 'value': 'option-1'}, 25 | {'label': 'Option 2', 'value': 'option-2'} 26 | ]; 27 | 28 | var result = inputSelect('test', options, 'option-2'); 29 | 30 | t.ok(result.indexOf('value="option-2" selected="selected"'), 'option 2 should be selected'); 31 | }); 32 | -------------------------------------------------------------------------------- /register.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return { 3 | 'abbr-count': require('./lib/abbr-count.js'), 4 | 'calendar': require('./lib/calendar.js'), 5 | 'capitalize': require('./lib/capitalize.js'), 6 | 'chr-gt': require('./lib/chr-gt.js'), 7 | 'chr-lt': require('./lib/chr-lt.js'), 8 | 'each-key': require('./lib/each-key.js'), 9 | 'each-limit': require('./lib/each-limit.js'), 10 | 'each-reverse': require('./lib/each-reverse.js'), 11 | 'either': require('./lib/either.js'), 12 | 'encodeURIComponent': require('./lib/encodeURIComponent.js'), 13 | 'eq': require('./lib/eq.js'), 14 | 'firstof': require('./lib/firstof.js'), 15 | 'if-gt': require('./lib/if-gt.js'), 16 | 'if-lt': require('./lib/if-lt.js'), 17 | 'indefinite-article': require('./lib/indefinite-article.js'), 18 | 'input-select': require('./lib/input-select.js'), 19 | 'iter': require('./lib/iter.js'), 20 | 'join': require('./lib/join.js'), 21 | 'neither': require('./lib/neither.js'), 22 | 'not-eq': require('./lib/not-eq.js'), 23 | 'number': require('./lib/number.js'), 24 | 'pack-it': require('./lib/pack-it.js'), 25 | 'paragraphify': require('./lib/paragraphify.js'), 26 | 'possessive': require('./lib/possessive.js'), 27 | 'repeat': require('./lib/repeat.js'), 28 | 'subtract': require('./lib/subtract.js'), 29 | 'title-case': require('./lib/title-case.js'), 30 | 'urlify': require('./lib/urlify.js') 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /lib/pack-it.js: -------------------------------------------------------------------------------- 1 | var _ = require('lodash'); 2 | var packIt = require('pack-it'); 3 | 4 | /** 5 | * Iterator that will produce a context w/ the size the content takes up 6 | * in a grid based on the number of items. 7 | * 8 | * {{#pack-it items}} 9 | * {{/pack-it}} 10 | * 11 | * @param {array} context 12 | */ 13 | module.exports = function packItHelper (context, options) { 14 | var packingStructure = []; 15 | 16 | if (context.length <= 1) { 17 | return options.fn({ 'content': context[0], 'size': 1 }); 18 | } 19 | 20 | if (context && context.length > 2) 21 | packingStructure = packIt.getStructure(context, 3, 1); 22 | else 23 | packingStructure = [1,1]; 24 | 25 | var currRowIndex = 1; 26 | var packed = _.reduce(context, function (memo, content, i) { 27 | // First pass of memo is the content object and needs to be run through options.fn 28 | // i is one ahead at this point so to get the correct packing size we subtract by 1 29 | memo = typeof memo !== 'string' ? options.fn({ 'content': memo, 'size': packingStructure[i - 1] }) : memo; 30 | 31 | var size = packingStructure[i]; 32 | var cell = Object.create(null); 33 | 34 | cell.content = content; 35 | cell.size = size; 36 | 37 | if (currRowIndex === 1) { 38 | cell['position-class'] = 'range-start'; 39 | } 40 | 41 | if (currRowIndex === size) { 42 | cell['position-class'] = 'range-end'; 43 | } 44 | 45 | if (currRowIndex === size) { 46 | currRowIndex = 1; 47 | } else { 48 | currRowIndex++; 49 | } 50 | 51 | return memo + options.fn(cell); 52 | }); 53 | 54 | return packed; 55 | }; 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/diy/handlebars-helpers.png?branch=master)](https://travis-ci.org/diy/handlebars-helpers) 2 | 3 | ## diy-handlebars-helpers 4 | #### Collection of generic handlebars helpers. 5 | 6 | ### Installation 7 | ```bash 8 | npm install diy-handlebars-helpers 9 | ``` 10 | 11 | ### Basic Use 12 | ```javascript 13 | var helpers = require('diy-handlebars-helpers'); 14 | helpers(); // returns a dictionary of helpers { name: function () {} } 15 | ``` 16 | 17 | Registering helpers w/ handlebars 18 | 19 | ```javascript 20 | var hbs = require('handlebars-runtime'); 21 | var _ = require('lodash'); 22 | 23 | _.extend(hbs.helpers, require('diy-handlebars-helpers')()); 24 | ``` 25 | 26 | ### Testing 27 | ```bash 28 | npm test 29 | ``` 30 | 31 | ### Helpers 32 | 33 | #### abbr-count 34 | ``` 35 | {{abbr-count 4000}} // 4k+ 36 | ``` 37 | 38 | #### captialize 39 | ``` 40 | {{capitalize 'hey dude'}} // Hey dude 41 | ``` 42 | 43 | #### chr-gt 44 | ``` 45 | {{chr-gt 'hey dude' 3}} 46 | // WOO! string is greater than 3 47 | {{else}} 48 | // string is not longer than 3 49 | {{/chr-gt}} 50 | ``` 51 | 52 | #### chr-lt 53 | ``` 54 | {{chr-lt 'hey dude' 3}} 55 | // string is less than 3 56 | {{else}} 57 | // WOO! string is not less than 3 58 | {{/chr-lt}} 59 | ``` 60 | 61 | #### each-key 62 | ``` 63 | {{#each-key object}} 64 | Key: {{this.key}} Value: {{this.value}} 65 | {{/each-key}} 66 | ``` 67 | 68 | #### each-limit 69 | ``` 70 | {{#each-limit items 3}} 71 | // will only iterate 3 times even if items is longer 72 | {{/each-limit}} 73 | ``` 74 | 75 | #### each-reverse 76 | ``` 77 | {{#each-reverse items}} 78 | // iterating backwards! 79 | {{/each-reverse}} 80 | ``` 81 | 82 | #### either 83 | ``` 84 | {{either false true false}} 85 | // at least one value was true 86 | {{else}} 87 | // none were true 88 | {{/either}} 89 | ``` 90 | 91 | #### encodeURIComponent 92 | ``` 93 | {{encodeURIComponent exactlyWhatYouThink}} 94 | ``` 95 | 96 | #### eq 97 | ``` 98 | {{#eq val1 val2}} 99 | // absolute comparision was true === 100 | {{else}} 101 | // here not so much 102 | {{/eq}} 103 | ``` 104 | 105 | #### firstof 106 | ``` 107 | {{firstof false false 'real value' false}} // "real value" great for picking default text for empty variables 108 | ``` 109 | 110 | #### if-gt 111 | ``` 112 | {{#if-gt 10 5}} 113 | // of course 10 is greater than 5 114 | {{else}} 115 | // this wouldn't execute 116 | {{/if-gt}} 117 | ``` 118 | 119 | #### if-lt 120 | ``` 121 | {{#if-lt 5 10}} 122 | // of course 5 is less than 10 123 | {{else}} 124 | // this wouldn't execute 125 | {{/if-lt}} 126 | ``` 127 | 128 | #### indefinite-article 129 | ``` 130 | {{indefinite-article 'apple'}} // an 131 | {{indefinite-article 'pineapple'}} // a 132 | ``` 133 | 134 | #### input-select 135 | ``` 136 | {{{input-select "month" options "05"}}} // builds an 137 | ``` 138 | 139 | `options` should be a multi-dimentional array: `[['val1', 'text1'], ['val2', 'text2']]`. If no 140 | text is provided, the value will be used for the option text. 141 | 142 | The third optional argument is the default value. (will get the `selected` attribute.) 143 | 144 | #### iter 145 | ``` 146 | {{#iter items}} 147 | {{i}} //index 148 | {{iPlus1}} // index + 1 149 | {{/iter}} 150 | ``` 151 | 152 | #### join 153 | ``` 154 | {{join array ","}} // "item1, item2" 155 | ``` 156 | 157 | #### neither 158 | ``` 159 | {{neither false false false}} 160 | // all must be false for this to execute 161 | {{else}} 162 | // at least one was true 163 | {{/neither}} 164 | ``` 165 | 166 | #### not-eq 167 | ``` 168 | {{#not-eq val1 val2}} 169 | // absolute not comparision was true !== 170 | {{else}} 171 | // here not so much 172 | {{/not-eq}} 173 | ``` 174 | 175 | #### number 176 | ``` 177 | {{number 100000}} // "100,000" 178 | ``` 179 | 180 | #### pack-it 181 | ``` 182 | {{#pack-it items}} 183 | {{content}} // original item 184 | {{size}} // pack size 185 | {{/pack-it}} 186 | ``` 187 | 188 | #### paragraphify 189 | ``` 190 | {{paragraphify textWithNewLines}} //

first line

second line

191 | ``` 192 | 193 | #### possessive 194 | ``` 195 | {{possessive 'john'}} // "john's" 196 | ``` 197 | 198 | #### repeat 199 | ``` 200 | {{#repeat 5}}Hello!{{/repeat}} // "Hello!Hello!Hello!Hello!Hello!" 201 | ``` 202 | 203 | #### subtract 204 | ``` 205 | {{subtract a.length 2}} 206 | ``` 207 | 208 | #### title-case 209 | ``` 210 | {{title-case 'hey hey hey'}} // "Hey Hey Hey" 211 | ``` 212 | 213 | #### truncate 214 | ``` 215 | {{truncate 'mysuperlongemail@example.com'}} // "mysuperlon…" 216 | {{truncate 'mysuperlongemail@example.com' 16}} // "mysuperlongemail…" 217 | {{truncate 'mysuperlongemail@example.com' 16 ''}} // "mysuperlongemail" 218 | {{truncate 'Some sente nce with a space at truncation index.'}} // "Some sente…" - trims trailing whitespace before appending 219 | ``` 220 | 221 | #### urlify 222 | ``` 223 | {{urlify 'Hey Hey'}} // "hey-hey" 224 | ``` 225 | --------------------------------------------------------------------------------