UNPKG

37.2 kBJavaScriptView Raw
1/*
2 * helper-lib
3 * https://github.com/assemble/helper-lib
4 *
5 * Copyright (c) 2013 Assemble, Brian Woodward, contributors.
6 * Licensed under the MIT license.
7 */
8
9if(!define || typeof define !== 'function') {
10 var define = require('amdefine')(module);
11}
12
13/*
14 * Add any handlebars helpers here and they'll
15 * be loaded into templates.js so they can
16 * be used inside your handlebars templates
17 */
18
19define([], function() {
20
21 // figure out if this is node or browser
22 var isServer = (typeof process !== 'undefined');
23
24 var register = function(Handlebars) {
25
26 var Dates = {};
27 var HTML = {};
28 var Utils = {};
29 var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) { return i; } } return -1; };
30
31 // if(isServer) {
32 var assemble = require('../../../assemble.js');
33 var fs = require('fs');
34 var util = require('util');
35 var path = require('path');
36 var dest = './';
37 var markdown = assemble.Markdown({gfm: true, highlight: 'auto'});
38 // }
39
40
41 /*************************************************************
42 * Utils
43 *************************************************************/
44 Utils.toString = Object.prototype.toString;
45
46 Utils.isUndefined = function(value) {
47 return value === 'undefined' || Utils.toString.call(value) === '[object Function]' || (value.hash != null);
48 };
49
50 Utils.safeString = function(str) {
51 return new Handlebars.SafeString(str);
52 };
53
54 Utils.trim = function(str) {
55 var trim;
56 trim = /\S/.test("\xA0") ? /^[\s\xA0]+|[\s\xA0]+$/g : /^\s+|\s+$/g;
57 return str.toString().replace(trim, '');
58 };
59
60 // Normalize slashes in URLs
61 Utils.urlNormalize = function(urlString) {
62 return urlString.replace(/\\/g, '/');
63 };
64
65
66
67 /*************************************************************
68 * HTML
69 *************************************************************/
70 HTML.parseAttributes = function(hash) {
71 return Object.keys(hash).map(function(key) {
72 return "" + key + "=\"" + hash[key] + "\"";
73 }).join(' ');
74 };
75
76
77 /*************************************************************
78 * Dates
79 *************************************************************/
80 Dates.padNumber = function(num, count, padCharacter) {
81 var lenDiff, padding;
82 if (typeof padCharacter === 'undefined') {
83 padCharacter = '0';
84 }
85 lenDiff = count - String(num).length;
86 padding = '';
87 if (lenDiff > 0) {
88 while (lenDiff--) {
89 padding += padCharacter;
90 }
91 }
92 return padding + num;
93 };
94
95 Dates.dayOfYear = function(date) {
96 var oneJan;
97 oneJan = new Date(date.getFullYear(), 0, 1);
98 return Math.ceil((date - oneJan) / 86400000);
99 };
100
101 Dates.weekOfYear = function(date) {
102 var oneJan;
103 oneJan = new Date(date.getFullYear(), 0, 1);
104 return Math.ceil((((date - oneJan) / 86400000) + oneJan.getDay() + 1) / 7);
105 };
106
107 Dates.isoWeekOfYear = function(date) {
108 var dayDiff, dayNr, jan4, target;
109 target = new Date(date.valueOf());
110 dayNr = (date.getDay() + 6) % 7;
111 target.setDate(target.getDate() - dayNr + 3);
112 jan4 = new Date(target.getFullYear(), 0, 4);
113 dayDiff = (target - jan4) / 86400000;
114 return 1 + Math.ceil(dayDiff / 7);
115 };
116
117 Dates.tweleveHour = function(date) {
118 if (date.getHours() > 12) {
119 return date.getHours() - 12;
120 } else {
121 return date.getHours();
122 }
123 };
124
125 Dates.timeZoneOffset = function(date) {
126 var hoursDiff, result;
127 hoursDiff = -date.getTimezoneOffset() / 60;
128 result = Dates.padNumber(Math.abs(hoursDiff), 4);
129 return (hoursDiff > 0 ? '+' : '-') + result;
130 };
131
132 Dates.format = function(date, format) {
133 return format.replace(Dates.formats, function(m, p) {
134 switch (p) {
135 case 'a':
136 return Dates.abbreviatedWeekdays[date.getDay()];
137 case 'A':
138 return Dates.fullWeekdays[date.getDay()];
139 case 'b':
140 return Dates.abbreviatedMonths[date.getMonth()];
141 case 'B':
142 return Dates.fullMonths[date.getMonth()];
143 case 'c':
144 return date.toLocaleString();
145 case 'C':
146 return Math.round(date.getFullYear() / 100);
147 case 'd':
148 return Dates.padNumber(date.getDate(), 2);
149 case 'D':
150 return Dates.format(date, '%m/%d/%y');
151 case 'e':
152 return Dates.padNumber(date.getDate(), 2, ' ');
153 case 'F':
154 return Dates.format(date, '%Y-%m-%d');
155 case 'h':
156 return Dates.format(date, '%b');
157 case 'H':
158 return Dates.padNumber(date.getHours(), 2);
159 case 'I':
160 return Dates.padNumber(Dates.tweleveHour(date), 2);
161 case 'j':
162 return Dates.padNumber(Dates.dayOfYear(date), 3);
163 case 'k':
164 return Dates.padNumber(date.getHours(), 2, ' ');
165 case 'l':
166 return Dates.padNumber(Dates.tweleveHour(date), 2, ' ');
167 case 'L':
168 return Dates.padNumber(date.getMilliseconds(), 3);
169 case 'm':
170 return Dates.padNumber(date.getMonth() + 1, 2);
171 case 'M':
172 return Dates.padNumber(date.getMinutes(), 2);
173 case 'n':
174 return '\n';
175 case 'p':
176 if (date.getHours() > 11) {
177 return 'PM';
178 } else {
179 return 'AM';
180 }
181 break;
182 case 'P':
183 return Dates.format(date, '%p').toLowerCase();
184 case 'r':
185 return Dates.format(date, '%I:%M:%S %p');
186 case 'R':
187 return Dates.format(date, '%H:%M');
188 case 's':
189 return date.getTime() / 1000;
190 case 'S':
191 return Dates.padNumber(date.getSeconds(), 2);
192 case 't':
193 return '\t';
194 case 'T':
195 return Dates.format(date, '%H:%M:%S');
196 case 'u':
197 if (date.getDay() === 0) {
198 return 7;
199 } else {
200 return date.getDay();
201 }
202 break;
203 case 'U':
204 return Dates.padNumber(Dates.weekOfYear(date), 2);
205 case 'v':
206 return Dates.format(date, '%e-%b-%Y');
207 case 'V':
208 return Dates.padNumber(Dates.isoWeekOfYear(date), 2);
209 case 'W':
210 return Dates.padNumber(Dates.weekOfYear(date), 2);
211 case 'w':
212 return Dates.padNumber(date.getDay(), 2);
213 case 'x':
214 return date.toLocaleDateString();
215 case 'X':
216 return date.toLocaleTimeString();
217 case 'y':
218 return String(date.getFullYear()).substring(2);
219 case 'Y':
220 return date.getFullYear();
221 case 'z':
222 return Dates.timeZoneOffset(date);
223 default:
224 return match;
225 }
226 });
227 };
228
229 Dates.formats = /%(a|A|b|B|c|C|d|D|e|F|h|H|I|j|k|l|L|m|M|n|p|P|r|R|s|S|t|T|u|U|v|V|W|w|x|X|y|Y|z)/g;
230
231 Dates.abbreviatedWeekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat'];
232
233 Dates.fullWeekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
234
235 Dates.abbreviatedMonths = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
236
237 Dates.fullMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
238
239
240 /* Handlebars Helpers - Dan Harper (http://github.com/danharper) */
241
242 /* This program is free software. It comes without any warranty, to
243 * the extent permitted by applicable law. You can redistribute it
244 * and/or modify it under the terms of the Do What The Fuck You Want
245 * To Public License, Version 2, as published by Sam Hocevar. See
246 * http://sam.zoy.org/wtfpl/COPYING for more details. */
247
248 /**
249 * If Equals
250 * if_eq this compare=that
251 */
252 Handlebars.registerHelper('if_eq', function(context, options) {
253 if (context === options.hash.compare) {
254 return options.fn(this);
255 }
256 return options.inverse(this);
257 });
258
259 /**
260 * Unless Equals
261 * unless_eq this compare=that
262 */
263 Handlebars.registerHelper('unless_eq', function(context, options) {
264 if (context === options.hash.compare) {
265 return options.inverse(this);
266 }
267 return options.fn(this);
268 });
269
270
271 /**
272 * If Greater Than
273 * if_gt this compare=that
274 */
275 Handlebars.registerHelper('if_gt', function(context, options) {
276 if (context > options.hash.compare) {
277 return options.fn(this);
278 }
279 return options.inverse(this);
280 });
281
282 /**
283 * Unless Greater Than
284 * unless_gt this compare=that
285 */
286 Handlebars.registerHelper('unless_gt', function(context, options) {
287 if (context > options.hash.compare) {
288 return options.inverse(this);
289 }
290 return options.fn(this);
291 });
292
293
294 /**
295 * If Less Than
296 * if_lt this compare=that
297 */
298 Handlebars.registerHelper('if_lt', function(context, options) {
299 if (context < options.hash.compare) {
300 return options.fn(this);
301 }
302 return options.inverse(this);
303 });
304
305 /**
306 * Unless Less Than
307 * unless_lt this compare=that
308 */
309 Handlebars.registerHelper('unless_lt', function(context, options) {
310 if (context < options.hash.compare) {
311 return options.inverse(this);
312 }
313 return options.fn(this);
314 });
315
316
317 /**
318 * If Greater Than or Equal To
319 * if_gteq this compare=that
320 */
321 Handlebars.registerHelper('if_gteq', function(context, options) {
322 if (context >= options.hash.compare) {
323 return options.fn(this);
324 }
325 return options.inverse(this);
326 });
327
328 /**
329 * Unless Greater Than or Equal To
330 * unless_gteq this compare=that
331 */
332 Handlebars.registerHelper('unless_gteq', function(context, options) {
333 if (context >= options.hash.compare) {
334 return options.inverse(this);
335 }
336 return options.fn(this);
337 });
338
339
340 /**
341 * If Less Than or Equal To
342 * if_lteq this compare=that
343 */
344 Handlebars.registerHelper('if_lteq', function(context, options) {
345 if (context <= options.hash.compare) {
346 return options.fn(this);
347 }
348 return options.inverse(this);
349 });
350
351 /**
352 * Unless Less Than or Equal To
353 * unless_lteq this compare=that
354 */
355 Handlebars.registerHelper('unless_lteq', function(context, options) {
356 if (context <= options.hash.compare) {
357 return options.inverse(this);
358 }
359 return options.fn(this);
360 });
361
362 /**
363 * Convert new line (\n) to <br>
364 * from http://phpjs.org/functions/nl2br:480
365 */
366 Handlebars.registerHelper('nl2br', function(text) {
367 var nl2br = (text + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br>' + '$2');
368 return new Handlebars.SafeString(nl2br);
369 });
370
371 /**
372 * Hyphenate
373 * Replace spaces in string with hyphens.
374 */
375 Handlebars.registerHelper('hyphenate', function(tag) {
376 return tag.split(' ').join('-');
377 });
378
379 /**
380 * Dashify
381 * Replace periods in string with hyphens.
382 */
383 Handlebars.registerHelper('dashify', function(tag) {
384 return tag.split('.').join('-');
385 });
386
387 /**
388 * To Lower Case
389 * Turns a string to lowercase.
390 */
391 Handlebars.registerHelper('lowercase', function(str) {
392 return str.toLowerCase();
393 });
394
395 /**
396 * To Upper Case
397 * Turns a string to uppercase.
398 */
399 Handlebars.registerHelper('uppercase', function(str) {
400 return str.toUpperCase();
401 });
402
403 /**
404 * Capitalize First
405 *
406 */
407 Handlebars.registerHelper('capitalizeFirst', function(str) {
408 return str.charAt(0).toUpperCase() + str.slice(1);
409 });
410
411 /**
412 * Capitalize Each
413 *
414 */
415 Handlebars.registerHelper('capitalizeEach', function(str) {
416 return str.replace(/\w\S*/g, function(txt) {
417 return txt.charAt(0).toUpperCase() + txt.substr(1);
418 });
419 });
420
421 /**
422 * Title Case
423 *
424 */
425 Handlebars.registerHelper('titleize', function(str) {
426 var capitalize, title, word, words;
427 title = str.replace(/[ \-_]+/g, ' ');
428 words = title.match(/\w+/g);
429 capitalize = function(word) {
430 return word.charAt(0).toUpperCase() + word.slice(1);
431 };
432 return ((function() {
433 var _i, _len, _results;
434 _results = [];
435 for (_i = 0, _len = words.length; _i < _len; _i++) {
436 word = words[_i];
437 _results.push(capitalize(word));
438 }
439 return _results;
440 })()).join(' ');
441 });
442
443 /**
444 * Sentence
445 *
446 */
447 Handlebars.registerHelper('sentence', function(str) {
448 return str.replace(/((?:\S[^\.\?\!]*)[\.\?\!]*)/g, function(txt) {
449 return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
450 });
451 });
452
453 /**
454 * Reverse
455 * Reverses a string.
456 */
457 Handlebars.registerHelper('reverse', function(str) {
458 return str.split('').reverse().join('');
459 });
460
461 /**
462 * Truncate
463 * Truncates a string given a specified `length`, providing a custom string to denote an `omission`.
464 *
465 * Parameters:
466 *
467 * length [int] - The number of characters to keep (Required)
468 * omission [string] - A string to denote an omission (Optional)
469 *
470 * Usage:
471 * {{truncate "Bender should not be allowed on tv." 31 "..."}}
472 * Bender should not be allowed...
473 */
474 Handlebars.registerHelper('truncate', function(str, length, omission) {
475 if (Utils.isUndefined(omission)) {
476 omission = '';
477 }
478 if (str.length > length) {
479 return str.substring(0, length - omission.length) + omission;
480 } else {
481 return str;
482 }
483 });
484
485 /**
486 * Center
487 * Centers a string using non-breaking spaces.
488 */
489 Handlebars.registerHelper('center', function(str, spaces) {
490 var i, space;
491 space = '';
492 i = 0;
493 while (i < spaces) {
494 space += '&nbsp;';
495 i++;
496 }
497 return "" + space + str + space;
498 });
499
500
501 // ==========================================================
502 //
503 // COLLECTIONS
504 //
505 // ==========================================================
506
507
508 /**
509 * First
510 * Returns the first item in a collection.
511 */
512 Handlebars.registerHelper('first', function(array, count) {
513 if (Utils.isUndefined(count)) {
514 return array[0];
515 } else {
516 return array.slice(0, count);
517 }
518 });
519
520 /**
521 * withFirst
522 * Use the first item in a collection inside a block.
523 */
524 Handlebars.registerHelper('withFirst', function(array, count, options) {
525 var item, result;
526 if (Utils.isUndefined(count)) {
527 options = count;
528 return options.fn(array[0]);
529 } else {
530 array = array.slice(0, count);
531 result = '';
532 for (item in array) {
533 result += options.fn(array[item]);
534 }
535 return result;
536 }
537 });
538
539 /**
540 * Last
541 * Returns the last item in a collection. Opposite of `first`.
542 */
543 Handlebars.registerHelper('last', function(array, count) {
544 if (Utils.isUndefined(count)) {
545 return array[array.length - 1];
546 } else {
547 return array.slice(-count);
548 }
549 });
550
551 /**
552 * With Last
553 * Use the last item in a collection inside a block. Opposite of `withFirst`.
554 */
555 Handlebars.registerHelper('withLast', function(array, count, options) {
556 var item, result;
557 if (Utils.isUndefined(count)) {
558 options = count;
559 return options.fn(array[array.length - 1]);
560 } else {
561 array = array.slice(-count);
562 result = '';
563 for (item in array) {
564 result += options.fn(array[item]);
565 }
566 return result;
567 }
568 });
569
570 /**
571 * After
572 * Returns all of the items in the collection after the specified count.
573 */
574 Handlebars.registerHelper('after', function(array, count) {
575 return array.slice(count);
576 });
577
578 /**
579 * With After
580 * Use all of the items in the collection after the specified count inside a block.
581 */
582 Handlebars.registerHelper('withAfter', function(array, count, options) {
583 var item, result;
584 array = array.slice(count);
585 result = '';
586 for (item in array) {
587 result += options.fn(array[item]);
588 }
589 return result;
590 });
591
592 /**
593 * Before
594 * Returns all of the items in the collection before the specified count. Opposite of `after`.
595 */
596 Handlebars.registerHelper('before', function(array, count) {
597 return array.slice(0, -count);
598 });
599
600 /**
601 * With Before
602 * Use all of the items in the collection before the specified count inside a block. Opposite of `withAfter`.
603 */
604 Handlebars.registerHelper('withBefore', function(array, count, options) {
605 var item, result;
606 array = array.slice(0, -count);
607 result = '';
608 for (item in array) {
609 result += options.fn(array[item]);
610 }
611 return result;
612 });
613
614 /**
615 * Join
616 * Joins all elements of a collection into a string using a separator if specified.
617 */
618 Handlebars.registerHelper('join', function(array, separator) {
619 return array.join(Utils.isUndefined(separator) ? ' ' : separator);
620 });
621
622 /**
623 * Sort
624 * Returns the collection sorted.
625 */
626 Handlebars.registerHelper('sort', function(array, field) {
627 if (Utils.isUndefined(field)) {
628 return array.sort();
629 } else {
630 return array.sort(function(a, b) {
631 return a[field] > b[field];
632 });
633 }
634 });
635
636 /**
637 * With Sort
638 * Uses the sorted collection inside the block.
639 */
640 Handlebars.registerHelper('withSort', function(array, field, options) {
641 var item, result, _i, _len;
642 result = '';
643 if (Utils.isUndefined(field)) {
644 options = field;
645 array = array.sort();
646 for (_i = 0, _len = array.length; _i < _len; _i++) {
647 item = array[_i];
648 result += options.fn(item);
649 }
650 } else {
651 array = array.sort(function(a, b) {
652 return a[field] > b[field];
653 });
654 for (item in array) {
655 result += options.fn(array[item]);
656 }
657 }
658 return result;
659 });
660
661 /**
662 * Length
663 * Returns the length of the collection.
664 */
665 Handlebars.registerHelper('length', function(array) {
666 return array.length;
667 });
668
669 /**
670 * Length Equal
671 * Conditionally render a block based on the length of a collection.
672 */
673 Handlebars.registerHelper('lengthEqual', function(array, length, options) {
674 if (array.length === length) {
675 return options.fn(this);
676 } else {
677 return options.inverse(this);
678 }
679 });
680
681 /**
682 * Empty
683 * Conditionally render a block if the collection is empty.
684 */
685 Handlebars.registerHelper('empty', function(array, options) {
686 if (array.length <= 0) {
687 return options.fn(this);
688 } else {
689 return options.inverse(this);
690 }
691 });
692
693 /**
694 * Any
695 * Conditionally render a block if the collection isn't empty. Opposite of `empty`
696 */
697 Handlebars.registerHelper('any', function(array, options) {
698 if (array.length > 0) {
699 return options.fn(this);
700 } else {
701 return options.inverse(this);
702 }
703 });
704
705 /**
706 * inArray
707 * Conditionally render a block if a specified value is in the collection.
708 */
709 Handlebars.registerHelper('inArray', function(array, value, options) {
710 if (array.indexOf(value) !== -1) {
711 return options.fn(this);
712 } else {
713 return options.inverse(this);
714 }
715 });
716
717 /**
718 * eachIndex
719 * Current implementation of the default Handlebars loop
720 * helper {{#each}} adding index (0-based index) to the loop context.
721 */
722 Handlebars.registerHelper('eachIndex', function(context, options) {
723 var data, i, j, ret;
724 ret = '';
725 if (options.data != null) {
726 data = Handlebars.createFrame(options.data);
727 }
728 if (context && context.length > 0) {
729 i = 0;
730 j = context.length;
731 while (i < j) {
732 if (data) {
733 data.index = i;
734 }
735 context[i].index = i;
736 ret = ret + options.fn(context[i]);
737 i++;
738 }
739 } else {
740 ret = options.inverse(this);
741 }
742 return ret;
743 });
744
745
746 /**
747 * Relative path
748 * Returns the derived relative path from one to the other.
749 */
750 Handlebars.registerHelper('relative', function(from, to) {
751 var relativePath = path.relative(from, to);
752
753 if(relativePath === "." || relativePath.length === 0) {
754 relativePath = dest;
755 }
756 relativePath = Utils.urlNormalize(path.relative(
757 path.resolve(path.join(dest, relative)),
758 path.resolve(relativePath)
759 ));
760 return relativePath;
761 });
762
763 /**
764 * Add
765 * Returns the sum of two numbers.
766 */
767 Handlebars.registerHelper('add', function(value, addition) {
768 return value + addition;
769 });
770
771 /**
772 * Subtract
773 * Returns the difference of two numbers. Opposite of `add`
774 */
775 Handlebars.registerHelper('subtract', function(value, substraction) {
776 return value - substraction;
777 });
778
779 /**
780 * Divide
781 * Returns the division of two numbers.
782 */
783 Handlebars.registerHelper('divide', function(value, divisor) {
784 return value / divisor;
785 });
786
787 /**
788 * Multiply
789 * Returns the multiplication of two numbers.
790 */
791 Handlebars.registerHelper('multiply', function(value, multiplier) {
792 return value * multiplier;
793 });
794
795 /**
796 * Floor
797 * Returns the value rounded down to the nearest integer.
798 */
799 Handlebars.registerHelper('floor', function(value) {
800 return Math.floor(value);
801 });
802
803 /**
804 * Ceil
805 * Returns the value rounded up to the nearest integer.
806 */
807 Handlebars.registerHelper('ceil', function(value) {
808 return Math.ceil(value);
809 });
810
811 /**
812 * Round
813 * Returns the value rounded to the nearest integer.
814 */
815 Handlebars.registerHelper('round', function(value) {
816 return Math.round(value);
817 });
818
819 /**
820 * To Fixed
821 * Returns exactly `digits` after the decimal place.
822 * The number is rounded if necessary, and the fractional
823 * part is padded with zeros if necessary so that it has the specified length.
824 */
825 Handlebars.registerHelper('toFixed', function(number, digits) {
826 if (Utils.isUndefined(digits)) {
827 digits = 0;
828 }
829 return number.toFixed(digits);
830 });
831
832 /**
833 * To Precision
834 * Returns the number in fixed-point or exponential
835 * notation rounded to `precision` significant digits.
836 */
837 Handlebars.registerHelper('toPrecision', function(number, precision) {
838 if (Utils.isUndefined(precision)) {
839 precision = 1;
840 }
841 return number.toPrecision(precision);
842 });
843
844 /**
845 * To Exponential
846 * Returns the number in exponential notation with one
847 * digit before the decimal point, rounded to `fractions`
848 * digits after the decimal point.
849 */
850 Handlebars.registerHelper('toExponential', function(number, fractions) {
851 if (Utils.isUndefined(fractions)) {
852 fractions = 0;
853 }
854 return number.toExponential(fractions);
855 });
856
857 /**
858 * To Int
859 * Returns an integer.
860 */
861 Handlebars.registerHelper('toInt', function(number) {
862 return parseInt(number, 10);
863 });
864
865 /**
866 * To Float
867 * Returns a floating point number.
868 */
869 Handlebars.registerHelper('toFloat', function(number) {
870 return parseFloat(number);
871 });
872
873 /**
874 * Add Commas
875 * Adds commas to a number.
876 */
877 Handlebars.registerHelper('addCommas', function(number) {
878 return number.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
879 });
880
881 /**
882 * Is
883 * Conditionally render a block if the condition is true.
884 */
885 Handlebars.registerHelper('is', function(value, test, options) {
886 if (value === test) {
887 return options.fn(this);
888 } else {
889 return options.inverse(this);
890 }
891 });
892
893 /**
894 * Isn't
895 * Conditionally render a block if the condition is false. Opposite of `is`.
896 */
897 Handlebars.registerHelper('isnt', function(value, test, options) {
898 if (value !== test) {
899 return options.fn(this);
900 } else {
901 return options.inverse(this);
902 }
903 });
904
905 /**
906 * Greater Than
907 * Conditionally render a block if the value is greater than a given number.
908 */
909 Handlebars.registerHelper('gt', function(value, test, options) {
910 if (value > test) {
911 return options.fn(this);
912 } else {
913 return options.inverse(this);
914 }
915 });
916
917 /**
918 * Greater than or equal to
919 * Conditionally render a block if the value is greater than
920 * or equal to a given number.
921 */
922 Handlebars.registerHelper('gte', function(value, test, options) {
923 if (value >= test) {
924 return options.fn(this);
925 } else {
926 return options.inverse(this);
927 }
928 });
929
930 /**
931 * Less Than
932 * Conditionally render a block if the value is less than
933 * a given number. Opposite of `gt`.
934 */
935 Handlebars.registerHelper('lt', function(value, test, options) {
936 if (value < test) {
937 return options.fn(this);
938 } else {
939 return options.inverse(this);
940 }
941 });
942
943 /**
944 * Conditionally render a block if the value is less than or
945 * equal to a given number. Opposite of `gte`.
946 *
947 */
948 Handlebars.registerHelper('lte', function(value, test, options) {
949 if (value <= test) {
950 return options.fn(this);
951 } else {
952 return options.inverse(this);
953 }
954 });
955
956 /**
957 * Or
958 * Conditionally render a block if one of the values is truthy.
959 */
960 Handlebars.registerHelper('or', function(testA, testB, options) {
961 if (testA || testB) {
962 return options.fn(this);
963 } else {
964 return options.inverse(this);
965 }
966 });
967
968 /**
969 * And
970 * Conditionally render a block if both values are truthy.
971 */
972 Handlebars.registerHelper('and', function(testA, testB, options) {
973 if (testA && testB) {
974 return options.fn(this);
975 } else {
976 return options.inverse(this);
977 }
978 });
979
980
981
982 /**
983 * Format Phone Number
984 * from: http://blog.teamtreehouse.com/handlebars-js-part-2-partials-and-helpers
985 * Helper function to output a formatted phone number
986 *
987 * Usage:
988 *
989 * {{formatPhoneNumber phoneNumber}}
990 */
991 Handlebars.registerHelper("formatPhoneNumber", function(phoneNumber) {
992 phoneNumber = phoneNumber.toString();
993 return "(" + phoneNumber.substr(0,3) + ") " + phoneNumber.substr(3,3) + "-" + phoneNumber.substr(6,4);
994 });
995
996
997 /**
998 * Format Date
999 * Formats a date into a string given a format. Accepts any
1000 * value that can be passed to `new Date()`. This helper is a port of
1001 * [formatDate-js](http://https://github.com/michaelbaldry/formatDate-js)
1002 * by [Michael Baldry](https://github.com/michaelbaldry).
1003 */
1004 Handlebars.registerHelper('formatDate', function(date, format) {
1005 date = new Date(date);
1006 return Dates.format(date, format);
1007 });
1008
1009 /**
1010 * Now
1011 * Returns the current date.
1012 */
1013 Handlebars.registerHelper('now', function(format) {
1014 var date;
1015 date = new Date();
1016 if (Utils.isUndefined(format)) {
1017 return date;
1018 } else {
1019 return Dates.format(date, format);
1020 }
1021 });
1022
1023 /**
1024 * Time Ago
1025 * Returns a human-readable time phrase from the given date.
1026 */
1027 Handlebars.registerHelper('timeago', function(date) {
1028 var interval, seconds;
1029 date = new Date(date);
1030 seconds = Math.floor((new Date() - date) / 1000);
1031 interval = Math.floor(seconds / 31536000);
1032 if (interval > 1) {
1033 return "" + interval + " years ago";
1034 }
1035 interval = Math.floor(seconds / 2592000);
1036 if (interval > 1) {
1037 return "" + interval + " months ago";
1038 }
1039 interval = Math.floor(seconds / 86400);
1040 if (interval > 1) {
1041 return "" + interval + " days ago";
1042 }
1043 interval = Math.floor(seconds / 3600);
1044 if (interval > 1) {
1045 return "" + interval + " hours ago";
1046 }
1047 interval = Math.floor(seconds / 60);
1048 if (interval > 1) {
1049 return "" + interval + " minutes ago";
1050 }
1051 if (Math.floor(seconds) === 0) {
1052 return 'Just now';
1053 } else {
1054 return Math.floor(seconds) + ' seconds ago';
1055 }
1056 });
1057
1058
1059
1060 // ==========================================================
1061 //
1062 // INFLECTIONS
1063 //
1064 // ==========================================================
1065
1066
1067 /**
1068 * Inflect
1069 * Returns the plural or singular form of a word based on a count.
1070 *
1071 * Parameters:
1072 *
1073 * singular [string] - The singular form of the word. (Required)
1074 * plural [string] - The plural form of the word. (Required)
1075 * include [boolean] - whether or not to include the count before the word. (Optional)
1076 *
1077 * Usage:
1078 *
1079 * enemies = 0
1080 * friends = 1
1081 *
1082 * {{inflect enemies "enemy" "enemies"}}
1083 * {{inflect friends "friend" "friends" true}}
1084 *
1085 * enemies
1086 * 1 friend
1087 */
1088 Handlebars.registerHelper('inflect', function(count, singular, plural, include) {
1089 var word;
1090 word = count > 1 || count === 0 ? plural : singular;
1091 if (Utils.isUndefined(include) || include === false) {
1092 return word;
1093 } else {
1094 return "" + count + " " + word;
1095 }
1096 });
1097
1098 /**
1099 * Ordinalize
1100 * Turns a number into an ordinal string.
1101 * Taken from the templating library
1102 * [Walrus](https://github.com/jeremyruppel/walrus)
1103 * by [Jeremy Ruppel](https://github.com/jeremyruppel).
1104 *
1105 * Usage:
1106 *
1107 * {{ordinalize 3}}
1108 * {{ordinalize 1}}
1109 * {{ordinalize 22}}
1110 *
1111 * 3rd
1112 * 1st
1113 * 22nd
1114 */
1115 Handlebars.registerHelper('ordinalize', function(value) {
1116 var normal, _ref;
1117 normal = Math.abs(Math.round(value));
1118 _ref = normal % 100;
1119 if (__indexOf.call([11, 12, 13], _ref) >= 0) {
1120 return "" + value + "th";
1121 } else {
1122 switch (normal % 10) {
1123 case 1:
1124 return "" + value + "st";
1125 case 2:
1126 return "" + value + "nd";
1127 case 3:
1128 return "" + value + "rd";
1129 default:
1130 return "" + value + "th";
1131 }
1132 }
1133 });
1134
1135
1136
1137
1138 /**
1139 * <ul>
1140 * Creates an unordered list.
1141 * Parameters:
1142 *
1143 * hash [html attributes] - HTML attributes to use on the ul element. (Optional)
1144 *
1145 * Usage:
1146 *
1147 * // Data
1148 * collection = [
1149 * name: 'Leela'
1150 * deliveries: 8021,
1151 * name: 'Bender'
1152 * deliveries: 239,
1153 * name: 'Fry'
1154 * deliveries: 1
1155 * ]
1156 *
1157 * // Template
1158 * {{#ul collection class="deliveries-list"}}
1159 * {{name}} - {{inflect deliveries "delivery" "deliveries" true}}
1160 * {{/ul}}
1161 *
1162 *
1163 * // Result:
1164 * <ul class="deliveries-list">
1165 * <li> Leela - 8021 deliveries </li>
1166 * <li> Bender - 239 deliveries </li>
1167 * <li> Fry - 1 delivery </li>
1168 * </ul>
1169 */
1170 Handlebars.registerHelper('ul', function(context, options) {
1171 return ("<ul " + (HTML.parseAttributes(options.hash)) + ">") + context.map(function(item) {
1172 return "<li>" + (options.fn(item)) + "</li>";
1173 }).join('\n') + "</ul>";
1174 });
1175
1176
1177 /**
1178 * <ol>
1179 * Same as the `ul` helper but creates and ordered list.
1180 */
1181 Handlebars.registerHelper('ol', function(context, options) {
1182 return ("<ol " + (HTML.parseAttributes(options.hash)) + ">") + context.map(function(item) {
1183 return "<li>" + (options.fn(item)) + "</li>";
1184 }).join('\n') + "</ol>";
1185 });
1186
1187 /**
1188 * <br>
1189 * Returns `<br>` tags based on a count.
1190 * Usage:
1191 *
1192 * {{br 5}}
1193 *
1194 * <br><br><br><br><br>
1195 */
1196 Handlebars.registerHelper('br', function(count, options) {
1197 var br, i;
1198 br = '<br>';
1199 if (!Utils.isUndefined(count)) {
1200 i = 0;
1201 while (i < count - 1) {
1202 br += '<br>';
1203 i++;
1204 }
1205 }
1206 return Utils.safeString(br);
1207 });
1208
1209 /**
1210 * Each Property
1211 * Loop through an objects properties
1212 * Usage:
1213 *
1214 * {{#eachProperty object}}
1215 * {{property}}: {{value}}<br/>
1216 * {{/eachProperty }}
1217 */
1218 Handlebars.registerHelper('eachProperty', function(context, options) {
1219 var ret = "";
1220 for (var prop in context) {
1221 ret = ret + options.fn({
1222 property: prop,
1223 value: context[prop]
1224 });
1225 }
1226 return ret;
1227 });
1228
1229
1230 /**
1231 * Inline Partials
1232 * Loop through an objects properties
1233 * Usage:
1234 *
1235 * {{{include "scripts"}}}
1236 *
1237 * and then:
1238 *
1239 * {{#extend "scripts"}}
1240 * <script>
1241 * document.write('foo bar!');
1242 * </script>
1243 * {{/extend}}
1244 */
1245
1246 var inlinePartials = {};
1247
1248 Handlebars.registerHelper('extend', function(name, context) {
1249 var include = inlinePartials[name];
1250 if (!include) {
1251 include = inlinePartials[name] = [];
1252 }
1253
1254 include.push(context.fn(this));
1255 });
1256 Handlebars.registerHelper('include', function(name) {
1257 var val = (inlinePartials[name] || []).join('\n');
1258
1259 // clear the include
1260 inlinePartials[name] = [];
1261 return val;
1262 });
1263
1264
1265 // ==========================================================
1266 //
1267 // LOGGING
1268 //
1269 // ==========================================================
1270
1271
1272 /**
1273 * Log
1274 * Simple console.log()
1275 *
1276 * Parameters: none.
1277 *
1278 * Usage:
1279 *
1280 * {{log "Hi console :)"}}
1281 *
1282 * Hi console :)
1283 */
1284 Handlebars.registerHelper('log', function(value) {
1285 return console.log(value);
1286 });
1287
1288 /**
1289 * Debug
1290 * Simple console.debug() that shows the current context.
1291
1292 * Parameters: none.
1293 *
1294 * Usage:
1295 *
1296 * collection = [
1297 * name: 'Leela'
1298 * deliveries: 8021
1299 * ,
1300 * name: 'Bender'
1301 * deliveries: 239
1302 * ,
1303 * name: 'Fry'
1304 * deliveries: 1
1305 * ]
1306 *
1307 * {{#withFirst collection}}
1308 * {{debug name}}
1309 * {{/withFirst}}
1310 *
1311 * Context: { deliveries: 8021, name: "Leela" }
1312 * Value: Leela
1313 */
1314 Handlebars.registerHelper('debug', function(value) {
1315 console.log('Context: ', this);
1316 if (!Utils.isUndefined(value)) {
1317 console.log('Value: ', value);
1318 }
1319 return console.log('-----------------------------------------------');
1320 });
1321
1322
1323
1324
1325 // ==========================================================
1326 //
1327 // MISCELLANEOUS
1328 //
1329 // ==========================================================
1330
1331 /**
1332 * Default
1333 * Provides a default or fallback value if a value doesn't exist.
1334 *
1335 * Usage:
1336 *
1337 * title = ''
1338 *
1339 * {{default title "Not title available."}}
1340 *
1341 * Not title available.
1342 *
1343 */
1344 Handlebars.registerHelper('default', function(value, defaultValue) {
1345 return value != null ? value : defaultValue;
1346 });
1347
1348
1349 /**
1350 * Markdown
1351 *
1352 * Markdown helper used to write markdown inside and
1353 * rendered the markdown inline with the HTML
1354 *
1355 * Usage:
1356 *
1357 * {{#markdown}}
1358 * # This is a title.
1359 * {{/markdown}}
1360 *
1361 * Renders to:
1362 * <h1>This is a title </h1>
1363 *
1364 */
1365 Handlebars.registerHelper('markdown', function(options) {
1366 var content = options.fn(this);
1367 return markdown.convert(content);
1368 });
1369
1370
1371 if(isServer) {
1372 /******************************
1373 * Markdown helper used to read in a file and inject
1374 * the rendered markdown into the HTML.
1375 *
1376 * Usage:
1377 *
1378 * {{md ../path/to/file.md}}
1379 *
1380 *******************************/
1381 Handlebars.registerHelper('md', function(path) {
1382 var content = markdown.read(path);
1383 return content;
1384 });
1385
1386 }
1387
1388 };
1389
1390 return {
1391 register: register
1392 };
1393
1394});
\No newline at end of file