├── .travis.yml ├── package.json ├── LICENSE-MIT ├── README.md ├── test ├── inflect.js ├── numbers.js └── strings.js └── index.js /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - 5.4.1 5 | 6 | before_install: 7 | npm i -g mocha 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "handlebars-helpers-inflections", 3 | "version": "1.0.0", 4 | "description": "Handlebars helpers for inflecting text", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "github.com/fitnr/handlebars-helpers-inflect/" 9 | }, 10 | "scripts": { 11 | "test": "mocha test/*.js" 12 | }, 13 | "keywords": [ 14 | "handlebars", 15 | "helpers", 16 | "inflection", 17 | "string formatting", 18 | "ordinal" 19 | ], 20 | "author": "Neil Freeman", 21 | "license": "MIT", 22 | "devDependencies": { 23 | "handlebars": "^4.0.5", 24 | "should": "^8.3.1" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Jon Schlinkert, Brian Woodward, contributors 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | handlebars-helpers-inflect 2 | ========================== 3 | 4 | A collection of Handlebars helpers for inflecting and formatting strings and numbers. 5 | 6 | A subset of [handlebars-helpers](https://github.com/assemble/handlebars-helpers). 7 | 8 | `{{inflect}}`: format a string into singular or plural forms 9 | 10 | `{{ordinalize}}`: add ordinal suffixes to numbers (7 => '7th') 11 | 12 | `{{addCommas}}`: Group numbers with commas (9000 => "9,000") 13 | 14 | `{{toFixed}}`: Convert to a float to a decimal precision. 15 | 16 | `{{toFloat}}`: Convert a string or integer to a floating-point number. 17 | 18 | `{{toInt}}`: Convert a string or float to an integer. 19 | 20 | `{{toPrecision}}`: Convert a number to a given precision. 21 | 22 | `{{capitalizeFirst}}`: Capitalize first word in a sentence 23 | 24 | `{{capitalizeEach}}`: Capitalize each word in a sentence 25 | 26 | `{{center}}`: Center a string using non-breaking spaces 27 | 28 | `{{dashify}}`: Replace periods in string with hyphens. 29 | 30 | `{{hyphenate}}`: Replace spaces in string with hyphens. 31 | 32 | `{{lowercase}}`: Make all letters in the string lowercase 33 | 34 | `{{plusify}}`: Replace spaces in string with pluses. 35 | 36 | `{{sentence}}`: Sentence case 37 | 38 | `{{titleize}}`: Title case. "This is Title Case" 39 | 40 | `{{uppercase}}`: 41 | 42 | `{{reverse}}`: 43 | 44 | `{{count}}`: Return the number of occurrences of a string, within a string 45 | 46 | `{{replace}}`: Replace occurrences of string "A" with string "B" 47 | 48 | `{{truncate}}`: * Truncates a string given a specified `length`. 49 | 50 | `{{startsWith}}`: Tests whether a string begins with the given prefix. 51 | 52 | 53 | License 54 | ------- 55 | 56 | MIT. 57 | 58 | -------------------------------------------------------------------------------- /test/inflect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Handlebars Helpers Tests: Inflections Helpers 3 | * Copyright (c) 2013 Jon Schlinkert, Brian Woodward, contributors 4 | * Licensed under the MIT License (MIT). 5 | */ 6 | 7 | require('should'); 8 | var Handlebars = require('handlebars'); 9 | 10 | require('../').register(Handlebars); 11 | 12 | describe('inflect', function() { 13 | describe('{{inflect enemies "enemy" "enemies"}}', function() { 14 | it('should return the plural or singular form of a word based on a value.', function() { 15 | var source = '{{inflect enemies "enemy" "enemies"}}'; 16 | var template = Handlebars.compile(source); 17 | var context = { 18 | enemies: 3 19 | }; 20 | template(context).should.equal('enemies'); 21 | }); 22 | }); 23 | describe('{{inflect friends "friend" "friends" include=true}}', function() { 24 | it('should return the plural or singular form of a word based on a value and include the count.', function() { 25 | var source = '{{inflect friends "friend" "friends" include=true}}'; 26 | var template = Handlebars.compile(source); 27 | var context = { 28 | friends: 1 29 | }; 30 | template(context).should.equal('1 friend'); 31 | }); 32 | }); 33 | }); 34 | 35 | describe('ordinalize', function() { 36 | describe('{{ordinalize 22}}', function() { 37 | it('should return the number converted into an ordinal string.', function() { 38 | var source = '{{ordinalize 22}}'; 39 | var template = Handlebars.compile(source); 40 | template().should.equal('22nd'); 41 | }); 42 | it('should return the number converted into an ordinal string.', function() { 43 | var source = '{{ordinalize 11}}'; 44 | var template = Handlebars.compile(source); 45 | template().should.equal('11th'); 46 | }); 47 | it('should return the number converted into an ordinal string.', function() { 48 | var source = '{{ordinalize 1}}'; 49 | var template = Handlebars.compile(source); 50 | template().should.equal('1st'); 51 | }); 52 | }); 53 | }); -------------------------------------------------------------------------------- /test/numbers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Handlebars Helpers Tests: Numbers Helpers 3 | * http://github.com/assemble/handlebars-helpers 4 | * Copyright (c) 2013 Jon Schlinkert, Brian Woodward, contributors 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | require('should'); 8 | var Handlebars = require('handlebars'); 9 | require('../').register(Handlebars, {}); 10 | 11 | var context, source, template; 12 | 13 | describe('toFixed', function() { 14 | describe('{{toFixed value}}', function() { 15 | it('should return the value rounded to the nearest integer.', function() { 16 | source = '{{toFixed value}}'; 17 | template = Handlebars.compile(source); 18 | context = { 19 | value: 5.53231 20 | }; 21 | template(context).should.equal('6'); 22 | }); 23 | }); 24 | describe('{{toFixed value 3}}', function() { 25 | it('should return the value rounded exactly n digits after the decimal place.', function() { 26 | source = '{{toFixed value 3}}'; 27 | template = Handlebars.compile(source); 28 | context = { 29 | value: 5.53231 30 | }; 31 | template(context).should.equal('5.532'); 32 | }); 33 | }); 34 | }); 35 | 36 | describe('toPrecision', function() { 37 | describe('{{toPrecision value}}', function() { 38 | it('Returns the number in fixed-point or exponential notation rounded to n significant digits.', function() { 39 | source = '{{toPrecision value}}'; 40 | template = Handlebars.compile(source); 41 | context = { 42 | value: 555.322 43 | }; 44 | template(context).should.equal('6e+2'); 45 | }); 46 | }); 47 | describe('{{toPrecision value 4}}', function() { 48 | it('should return the value rounded exactly n digits after the decimal place.', function() { 49 | source = '{{toPrecision value 4}}'; 50 | template = Handlebars.compile(source); 51 | context = { 52 | value: 555.322 53 | }; 54 | template(context).should.equal('555.3'); 55 | }); 56 | }); 57 | }); 58 | 59 | describe('toExponential', function() { 60 | describe('{{toExponential value}}', function() { 61 | it('should return the number in fixed-point or exponential notation rounded to n significant digits.', function() { 62 | source = '{{toExponential value}}'; 63 | template = Handlebars.compile(source); 64 | context = { 65 | value: 5 66 | }; 67 | template(context).should.equal('5e+0'); 68 | }); 69 | }); 70 | describe('{{toExponential value 5}}', function() { 71 | it('should return the number in fixed-point or exponential notation rounded to exactly n significant digits.', function() { 72 | source = '{{toExponential value 5}}'; 73 | template = Handlebars.compile(source); 74 | context = { 75 | value: 5 76 | }; 77 | template(context).should.equal('5.00000e+0'); 78 | }); 79 | }); 80 | }); 81 | 82 | describe('toInt', function() { 83 | describe('{{toInt value}}', function() { 84 | it('should return an integer.', function() { 85 | source = '{{toInt value}}'; 86 | template = Handlebars.compile(source); 87 | context = { 88 | value: '3cc' 89 | }; 90 | template(context).should.equal('3'); 91 | }); 92 | }); 93 | }); 94 | 95 | describe('toFloat', function() { 96 | describe('{{toFloat value}}', function() { 97 | it('should return a floating point number.', function() { 98 | source = '{{toFloat value}}'; 99 | template = Handlebars.compile(source); 100 | context = { 101 | value: '3.1cc' 102 | }; 103 | template(context).should.equal('3.1'); 104 | }); 105 | }); 106 | }); 107 | 108 | describe('addCommas', function() { 109 | describe('{{addCommas value}}', function() { 110 | it('should add commas to a number.', function() { 111 | source = '{{addCommas value}}'; 112 | template = Handlebars.compile(source); 113 | context = { 114 | value: 2222222 115 | }; 116 | template(context).should.equal('2,222,222'); 117 | }); 118 | }); 119 | }); 120 | 121 | describe('toAbbr', function() { 122 | describe('{{toAbbr value}}', function() { 123 | it('should formats (and approximates) a number into abbreviation based on a value.', function() { 124 | source = '{{toAbbr value}}'; 125 | template = Handlebars.compile(source); 126 | context = { 127 | value: 123456789 128 | }; 129 | template(context).should.equal('123.46m'); 130 | }); 131 | }); 132 | describe('{{toAbbr value 3}}', function() { 133 | it('should formats (and approximates) a number into abbreviation based on a value and include decimal.', function() { 134 | source = '{{toAbbr value 3}}'; 135 | template = Handlebars.compile(source); 136 | context = { 137 | value: 123456789 138 | }; 139 | template(context).should.equal('123.457m'); 140 | }); 141 | }); 142 | }); 143 | -------------------------------------------------------------------------------- /test/strings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Handlebars Helpers Tests: String Helpers 3 | * http://github.com/assemble/handlebars-helpers 4 | * Copyright (c) 2013 Jon Schlinkert, Brian Woodward, contributors 5 | * Licensed under the MIT License (MIT). 6 | */ 7 | require('should'); 8 | var Handlebars = require('handlebars'); 9 | require('../').register(Handlebars, {}); 10 | 11 | var source, template; 12 | 13 | describe('lowercase', function() { 14 | describe('{{lowercase string}}', function() { 15 | it('should return the string in lowercase', function() { 16 | source = '{{lowercase "BENDER SHOULD NOT BE ALLOWED ON TV"}}'; 17 | template = Handlebars.compile(source); 18 | template().should.equal('bender should not be allowed on tv'); 19 | }); 20 | }); 21 | }); 22 | 23 | describe('uppercase', function() { 24 | describe('{{uppercase string}}', function() { 25 | it('should return the string in uppercase', function() { 26 | source = '{{uppercase "bender should not be allowed on tv"}}'; 27 | template = Handlebars.compile(source); 28 | template().should.equal('BENDER SHOULD NOT BE ALLOWED ON TV'); 29 | }); 30 | }); 31 | }); 32 | 33 | describe('uppercase_block', function() { 34 | describe('{{#uppercase}}string{{/uppercase}}', function() { 35 | it('should return the string in uppercase', function() { 36 | source = '{{#uppercase}}bender should not be allowed on tv{{/uppercase}}'; 37 | template = Handlebars.compile(source); 38 | template().should.equal('BENDER SHOULD NOT BE ALLOWED ON TV'); 39 | }); 40 | }); 41 | }); 42 | 43 | describe('capitalizeFirst', function() { 44 | describe('{{capitalizeFirst string}}', function() { 45 | it('should return the string with the first word capitalized.', function() { 46 | source = '{{capitalizeFirst "bender should not be allowed on tv"}}'; 47 | template = Handlebars.compile(source); 48 | template().should.equal('Bender should not be allowed on tv'); 49 | }); 50 | }); 51 | }); 52 | 53 | describe('capitalizeEach', function() { 54 | describe('{{capitalizeEach string}}', function() { 55 | it('should return the string with the every word capitalized.', function() { 56 | source = '{{capitalizeEach "bender should not bE allowed on tV"}}'; 57 | template = Handlebars.compile(source); 58 | template().should.equal('Bender Should Not BE Allowed On TV'); 59 | }); 60 | }); 61 | }); 62 | 63 | describe('titleize', function() { 64 | describe('{{titleize string}}', function() { 65 | it('should return the string in title case.', function() { 66 | source = '{{titleize "Bender-should-Not-be-allowed_on_Tv"}}'; 67 | template = Handlebars.compile(source); 68 | template().should.equal('Bender Should Not Be Allowed On Tv'); 69 | }); 70 | }); 71 | }); 72 | 73 | describe('sentence', function() { 74 | describe('{{sentence string}}', function() { 75 | it('should capitalize the first word of each sentence in a string and convert the rest of the sentence to lowercase.', function() { 76 | source = '{{sentence "bender should NOT be allowed on TV. fry SHOULD be allowed on TV."}}'; 77 | template = Handlebars.compile(source); 78 | template().should.equal('Bender should not be allowed on tv. Fry should be allowed on tv.'); 79 | }); 80 | }); 81 | }); 82 | 83 | describe('reverse', function() { 84 | describe('{{reverse string}}', function() { 85 | it('should return the string in reverse.', function() { 86 | source = '{{reverse "bender should NOT be allowed on TV."}}'; 87 | template = Handlebars.compile(source); 88 | template().should.equal('.VT no dewolla eb TON dluohs redneb'); 89 | }); 90 | }); 91 | }); 92 | 93 | describe('truncate', function() { 94 | describe('{{truncate string 31}}', function() { 95 | it('should return the string truncated by a specified length.', function() { 96 | source = '{{truncate "Bender should not be allowed on tv." 31}}'; 97 | template = Handlebars.compile(source); 98 | template().should.equal('Bender should not be allowed on'); 99 | }); 100 | }); 101 | describe('{{truncate string 31 "..."}}', function() { 102 | it('should return then string truncated by a specified length, providing a custom string to denote an omission.', function() { 103 | source = '{{truncate "Bender should not be allowed on tv." 31 "..."}}'; 104 | template = Handlebars.compile(source); 105 | template().should.equal('Bender should not be allowed...'); 106 | }); 107 | }); 108 | }); 109 | 110 | describe('center', function() { 111 | describe('{{center string}}', function() { 112 | it('should return the string centered by using non-breaking spaces.', function() { 113 | source = '{{center "Bender should not be allowed on tv." 2}}'; 114 | template = Handlebars.compile(source); 115 | template().should.equal('&nbsp;&nbsp;Bender should not be allowed on tv.&nbsp;&nbsp;'); 116 | }); 117 | }); 118 | }); 119 | 120 | describe('hyphenate', function() { 121 | describe('{{hyphenate string}}', function() { 122 | it('should return the string with spaces replaced with hyphens.', function() { 123 | source = '{{hyphenate "Bender should not be allowed on tv."}}'; 124 | template = Handlebars.compile(source); 125 | template().should.equal('Bender-should-not-be-allowed-on-tv.'); 126 | }); 127 | }); 128 | }); 129 | 130 | describe('dashify', function() { 131 | describe('{{dashify string}}', function() { 132 | it('should return the string with periods replaced with hyphens.', function() { 133 | source = '{{dashify "Bender.should.not.be.allowed.on.tv."}}'; 134 | template = Handlebars.compile(source); 135 | template().should.equal('Bender-should-not-be-allowed-on-tv-'); 136 | }); 137 | }); 138 | }); 139 | 140 | describe('plusify', function() { 141 | describe('{{plusify emptyString}}', function() { 142 | it('should return the empty string with no change.', function() { 143 | source = '{{plusify ""}}'; 144 | template = Handlebars.compile(source); 145 | template().should.equal(''); 146 | }); 147 | }); 148 | describe('{{plusify string}}', function() { 149 | it('should return the string with no change.', function() { 150 | source = '{{plusify "BenderShouldNotBeAllowedOnTv."}}'; 151 | template = Handlebars.compile(source); 152 | template().should.equal('BenderShouldNotBeAllowedOnTv.'); 153 | }); 154 | }); 155 | describe('{{plusify string}}', function() { 156 | it('should return the string with spaces replaced with pluses.', function() { 157 | source = '{{plusify "Bender should not be allowed on tv."}}'; 158 | template = Handlebars.compile(source); 159 | template().should.equal('Bender+should+not+be+allowed+on+tv.'); 160 | }); 161 | }); 162 | }); 163 | 164 | describe('startsWith', function() { 165 | describe('{{#startsWith "Bender" "Bender is great"}}Yes he is{{/startsWith}}', function() { 166 | it('should render "Yes he is", from inside the block.', function() { 167 | source = '{{#startsWith "Bender" "Bender is great"}}Yes he is{{/startsWith}}'; 168 | template = Handlebars.compile(source); 169 | template().should.equal("Yes he is"); 170 | }); 171 | }); 172 | describe('{{#startsWith somePrefix badString}}\nSuccess\n{{else}}\nInverse\n{{/startsWith}}', function() { 173 | it('should render the Inverse block.', function() { 174 | source = '{{#startsWith "Goodbye" "Hello, world!"}}Whoops{{else}}Bro, do you even hello world?{{/startsWith}}'; 175 | template = Handlebars.compile(source); 176 | template().should.equal('Bro, do you even hello world?'); 177 | }); 178 | }); 179 | describe('{{#startsWith somePrefix nullProperty}}\nSuccess\n{{else}}\nInverse\n{{/startsWith}}', function() { 180 | it("should render the Inverse block.", function() { 181 | source = '{{#startsWith "myPrefix" nullProperty}}fn block{{else}}inverse block{{/startsWith}}'; 182 | template = Handlebars.compile(source); 183 | var context = {}; 184 | template(context).should.equal('inverse block'); 185 | }); 186 | }); 187 | }); 188 | 189 | describe('count', function() { 190 | describe('{{count string substring}}', function() { 191 | it('should return the number of occurrances of a string, within a string.', function() { 192 | source = '{{count "Death by Snu-Snu" "Snu"}}'; 193 | template = Handlebars.compile(source); 194 | template().should.equal('2'); 195 | }); 196 | }); 197 | }); 198 | 199 | describe('replace', function() { 200 | describe('{{replace string}}', function() { 201 | it('should replace occurrences of string "A" with string "B"', function() { 202 | source = '{{replace "Bender Bending Rodriguez" "B" "M"}}'; 203 | template = Handlebars.compile(source); 204 | template().should.equal('Mender Mending Rodriguez'); 205 | }); 206 | }); 207 | }); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Handlebars Formatting and Inflection Helpers 3 | * Copyright (c) 2013 Jon Schlinkert, Brian Woodward, contributors 4 | * Licensed under the MIT License (MIT). 5 | */ 6 | 7 | /* jshint esversion: 6, node: true */ 8 | 9 | 'use strict'; 10 | 11 | var helpers = { 12 | /** 13 | * {{inflect}} 14 | * 15 | * Convert intger to an English-language ordinal. 16 | * @param {Number} count [description] 17 | * @param {String} singular [description] 18 | * @param {String} plural [description] 19 | * @param {Object} options [description] 20 | * @returns {String} [description] 21 | */ 22 | inflect: function(count, singular, plural, options) { 23 | var word = count > 1 || count === 0 ? plural : singular; 24 | if (options.hash && options.hash.include) 25 | return "" + count + " " + word; 26 | else 27 | return word; 28 | }, 29 | 30 | /** 31 | * {{ordinalize}} 32 | * 33 | * Convert intger to an English-language ordinal. 34 | * @param {Number} number [description] 35 | * @returns {String} [description] 36 | */ 37 | ordinalize: function(value) { 38 | var normal = Math.abs(Math.round(value)); 39 | if (Array.prototype.indexOf.call([11, 12, 13], normal % 100) >= 0) { 40 | return "" + value + "th"; 41 | } else { 42 | switch (normal % 10) { 43 | case 1: 44 | return "" + value + "st"; 45 | case 2: 46 | return "" + value + "nd"; 47 | case 3: 48 | return "" + value + "rd"; 49 | default: 50 | return "" + value + "th"; 51 | } 52 | } 53 | }, 54 | 55 | /** 56 | * {{addCommas}} 57 | * 58 | * Add commas to numbers 59 | * @param {Number} number [description] 60 | */ 61 | addCommas: function(number) { 62 | return number.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,"); 63 | }, 64 | 65 | /** 66 | * {{toAbbr}} 67 | * 68 | * Abbreviate numbers 69 | * @param {Number} number [description] 70 | * @param {Number} digits [description] 71 | * @return {String} [description] 72 | */ 73 | toAbbr: function(number, digits, opts) { 74 | if (typeof opts === 'undefined') { 75 | opts = digits; 76 | digits = undefined; 77 | } 78 | 79 | if (typeof digits === 'undefined') 80 | digits = 2; 81 | 82 | // @default: 2 decimal places => 100, 3 => 1000, etc. 83 | digits = Math.pow(10, digits); 84 | var abbr = ["k", "m", "b", "t"]; 85 | var i = abbr.length - 1; 86 | while (i >= 0) { 87 | var size = Math.pow(10, (i + 1) * 3); 88 | if (size <= number) { 89 | number = Math.round(number * digits / size) / digits; 90 | // Special case where we round up to the next abbreviation 91 | if ((number === 1000) && (i < abbr.length - 1)) { 92 | number = 1; 93 | i++; 94 | } 95 | number += abbr[i]; 96 | break; 97 | } 98 | i--; 99 | } 100 | return number; 101 | }, 102 | 103 | toExponential: function(number, fractions, options) { 104 | if (typeof fractions === 'undefined') { 105 | fractions = 0; 106 | } 107 | return number.toExponential(fractions); 108 | }, 109 | 110 | toFixed: function(number, digits, options) { 111 | if (typeof digits === 'undefined') { 112 | digits = 0; 113 | } 114 | return number.toFixed(digits); 115 | }, 116 | 117 | toFloat: function(number) { 118 | return parseFloat(number); 119 | }, 120 | 121 | toInt: function(number) { 122 | return parseInt(number, 10); 123 | }, 124 | 125 | toPrecision: function(number, precision, opts) { 126 | if (typeof opts === 'undefined') { 127 | opts = precision; 128 | precision = undefined; 129 | } 130 | if (typeof precision === 'undefined') { 131 | precision = 1; 132 | } 133 | return number.toPrecision(precision); 134 | }, 135 | 136 | /** 137 | * {{capitalizeFirst}} 138 | * Capitalize first word in a sentence 139 | * @param {String} str [description] 140 | * @return {String} [description] 141 | */ 142 | capitalizeFirst: function(str) { 143 | if (str && typeof str === "string") { 144 | return str.charAt(0).toUpperCase() + str.slice(1); 145 | } 146 | }, 147 | 148 | /** 149 | * {{capitalizeEach}} 150 | * Capitalize each word in a sentence 151 | * @param {String} str [description] 152 | * @return {String} [description] 153 | */ 154 | capitalizeEach: function(str) { 155 | if (str && typeof str === "string") { 156 | return str.replace(/\w\S*/g, function(word) { 157 | return word.charAt(0).toUpperCase() + word.substr(1); 158 | }); 159 | } 160 | }, 161 | 162 | /** 163 | * {{center}} 164 | * Center a string using non-breaking spaces 165 | * @param {String} str [description] 166 | * @param {Number} spaces [description] 167 | * @return {String} [description] 168 | */ 169 | center: function(str, spaces) { 170 | if (str && typeof str === "string") { 171 | var space = ''; 172 | var i = 0; 173 | while (i < spaces) { 174 | space += ' '; 175 | i++; 176 | } 177 | return "" + space + str + space; 178 | } 179 | }, 180 | 181 | /** 182 | * {{dashify}} 183 | * Replace periods in string with hyphens. 184 | * @param {String} str [description] 185 | * @return {String} [description] 186 | */ 187 | dashify: function(str) { 188 | if (str && typeof str === "string") { 189 | return str.split(".").join("-"); 190 | } 191 | }, 192 | 193 | /** 194 | * {{hyphenate}} 195 | * Replace spaces in string with hyphens. 196 | * @param {String} str [description] 197 | * @return {[type]} [description] 198 | */ 199 | hyphenate: function(str) { 200 | if (str && typeof str === "string") { 201 | return str.split(" ").join("-"); 202 | } 203 | }, 204 | 205 | /** 206 | * {{lowercase}} 207 | * Make all letters in the string lowercase 208 | * @param {String} str [description] 209 | * @return {[type]} [description] 210 | */ 211 | lowercase: function(str) { 212 | if (str && typeof str === "string") { 213 | return str.toLowerCase(); 214 | } 215 | }, 216 | 217 | /** 218 | * {{plusify}} 219 | * Replace spaces in string with pluses. 220 | * @author: Stephen Way 221 | * @param {String} str The input string 222 | * @return {[type]} Input string with spaces replaced by plus signs 223 | */ 224 | plusify: function(str) { 225 | if (str && typeof str === "string") { 226 | return str.split(" ").join("+"); 227 | } 228 | }, 229 | 230 | /** 231 | * {{sentence}} 232 | * Sentence case 233 | * @param {String} str [description] 234 | * @return {[type]} [description] 235 | */ 236 | sentence: function(str) { 237 | if (str && typeof str === "string") { 238 | return str.replace(/((?:\S[^\.\?\!]*)[\.\?\!]*)/g, function(txt) { 239 | return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); 240 | }); 241 | } 242 | }, 243 | 244 | /** 245 | * {{titleize}} 246 | * Title case. "This is Title Case" 247 | * @param {String} str [description] 248 | * @return {[type]} [description] 249 | */ 250 | titleize: function(str) { 251 | if (str && typeof str === "string") { 252 | var title = str.replace(/[ \-_]+/g, ' '); 253 | var words = title.match(/\w+/g); 254 | var capitalize = function(word) { 255 | return word.charAt(0).toUpperCase() + word.slice(1); 256 | }; 257 | return ((function() { 258 | var i, len, results; 259 | results = []; 260 | for (i = 0, len = words.length; i < len; i++) { 261 | var word = words[i]; 262 | results.push(capitalize(word)); 263 | } 264 | return results; 265 | })()).join(' '); 266 | } 267 | }, 268 | 269 | uppercase: function(options) { 270 | if (options && typeof options === "string") { 271 | return options.toUpperCase(); 272 | } else if (options && typeof options === "object") { 273 | return options.fn(this).toUpperCase(); 274 | } 275 | }, 276 | 277 | reverse: function(str) { 278 | if (str && typeof str === "string") { 279 | return str.split('').reverse().join(''); 280 | } 281 | }, 282 | 283 | /** 284 | * {{count}} 285 | * Return the number of occurrences of a string, within a string 286 | * @author: Jon Schlinkert 287 | * @param {String} str The haystack 288 | * @param {String} substring The needle 289 | * @return {Number} The number of times the needle is found in the haystack. 290 | */ 291 | count: function(str, substring) { 292 | if (str && typeof str === "string") { 293 | var n = 0; 294 | var pos = 0; 295 | var l = substring.length; 296 | while (true) { 297 | pos = str.indexOf(substring, pos); 298 | if (pos > -1) { 299 | n++; 300 | pos += l; 301 | } else { 302 | break; 303 | } 304 | } 305 | return n; 306 | } 307 | }, 308 | 309 | /** 310 | * {{replace}} 311 | * Replace occurrences of string "A" with string "B" 312 | * @author: Jon Schlinkert 313 | * @param {String} str [description] 314 | * @param {String} a [description] 315 | * @param {String} b [description] 316 | * @return {String} [description] 317 | */ 318 | replace: function(str, a, b) { 319 | if (str && typeof str === "string") { 320 | return str.split(a).join(b); 321 | } 322 | }, 323 | 324 | /** 325 | * {{truncate}} 326 | * Truncates a string given a specified `length`, 327 | * providing a custom string to denote an `omission`. 328 | * @param {String} str [description] 329 | * @param {[type]} length [description] 330 | * @param {[type]} omission [description] 331 | * @return {[type]} [description] 332 | */ 333 | truncate: function(str, limit, omission, options) { 334 | if (typeof options === 'undefined') { 335 | options = omission; 336 | omission = undefined; 337 | } 338 | if (typeof omission === 'undefined') 339 | omission = ''; 340 | 341 | if (str.length > limit) 342 | return str.substring(0, limit - omission.length) + omission; 343 | else 344 | return str; 345 | }, 346 | 347 | /** 348 | * {{startsWith}} 349 | * @author: Dan Fox 350 | * 351 | * Tests whether a string begins with the given prefix. 352 | * Behaves sensibly if the string is null. 353 | * @param {String} prefix [description] 354 | * @param {String} testString [description] 355 | * @param {String} options [description] 356 | * @return {String} [description] 357 | * 358 | * @example: 359 | * {{#startsWith "Goodbye" "Hello, world!"}} 360 | * Whoops 361 | * {{else}} 362 | * Bro, do you even hello world? 363 | * {{/startsWith}} 364 | */ 365 | startsWith: function(prefix, str, options) { 366 | if (typeof str !== 'undefined' && str.indexOf(prefix) === 0) { 367 | return options.fn(this); 368 | } else { 369 | return options.inverse(this); 370 | } 371 | }, 372 | }; 373 | 374 | // Export helpers 375 | module.exports.register = function(Handlebars) { 376 | for (var helper in helpers) { 377 | if (helpers.hasOwnProperty(helper)) { 378 | Handlebars.registerHelper(helper, helpers[helper]); 379 | } 380 | } 381 | }; --------------------------------------------------------------------------------