Part of ACREP-32.
[mkws-moved-to-github.git] / src / mkws-handlebars.js
1 // Handlebars helpers
2
3 Handlebars.registerHelper('mkws-json', function(obj) {
4   return mkws.$.toJSON(obj);
5 });
6
7
8 // This is intended to handle paragraphs from Wikipedia, hence the
9 // rather hacky code to remove numbered references.
10 //
11 Handlebars.registerHelper('mkws-paragraphs', function(obj, nPara, nSent) {
12   var acc = [];
13
14   // For some reason, Handlebars provides the value
15   // {"hash":{},"data":{}} for parameters that are not provided. So we
16   // have to be prepared for actual numbers, explicitly undefined
17   // values and this dumb magic value.
18   if (obj && (nPara === undefined || nPara.hasOwnProperty('hash') || nPara == 0 || nPara > obj.length)) {
19     nPara = obj.length;
20   }
21   if (nSent === undefined || nSent.hasOwnProperty('hash') || nSent == 0) {
22     nSent = Infinity;
23   }
24
25   for (var i = 0; i < nPara; i++) {
26     // Remove numbered references such as "[1,3,4]" from text
27     var text = obj[i].replace(/\[[0-9,]+\]/g, '');
28     // Next line from http://stackoverflow.com/questions/18914629/split-string-into-sentences-in-javascript
29     var sentences = text.replace(/([.?!])\s*(?=[A-Z])/g, "$1|").split("|");
30     if (sentences.length > nSent)
31       sentences.length = nSent;
32
33     acc.push('<p>', sentences.join(' '), '</p>');
34     nSent -= sentences.length;
35     if (nSent == 0)
36       break;
37   }
38
39   return acc.join('');
40 });
41
42
43 Handlebars.registerHelper('mkws-translate', function(s) {
44   return mkws.M(s);
45 });
46
47
48 // We need {{mkws-attr '@name'}} because Handlebars can't parse {{@name}}
49 Handlebars.registerHelper('mkws-attr', function(attrName) {
50   return this[attrName];
51 });
52
53
54 /*
55  * Use as follows: {{#mkws-if-any NAME1 having="NAME2"}}
56  * Applicable when NAME1 is the name of an array
57  * The guarded code runs only if at least one element of the NAME1
58  * array has a subelement called NAME2.
59  */
60 Handlebars.registerHelper('mkws-if-any', function(items, options) {
61   var having = options.hash.having;
62   for (var i in items) {
63     var item = items[i]
64     if (!having || item[having]) {
65       return options.fn(this);
66     }
67   }
68   return "";
69 });
70
71
72 Handlebars.registerHelper('mkws-first', function(items, options) {
73   var having = options.hash.having;
74   for (var i in items) {
75     var item = items[i]
76     if (!having || item[having]) {
77       return options.fn(item);
78     }
79   }
80   return "";
81 });
82
83
84 Handlebars.registerHelper('mkws-commaList', function(items, options) {
85   var out = "";
86
87   for (var i in items) {
88     if (i > 0) out += ", ";
89     out += options.fn(items[i])
90   }
91
92   return out;
93 });
94
95
96 Handlebars.registerHelper('mkws-index1', function(obj) {
97   return obj.data.index + 1;
98 });
99
100 Handlebars.registerHelper('mkws-indexplus', function(delta, obj) {
101   return obj.data.index + delta;
102 });
103
104 Handlebars.registerHelper('mkws-repeat', function(count, options) {
105   var out = "";
106   for (var i = 0; i < count; i++) {
107     out += options.fn(this);
108   }
109   return out;
110 });
111
112 // Ridiculous that Handlebars has no way to do "or"
113 Handlebars.registerHelper('mkws-if-either', function(cond1, cond2, options) {
114   if (typeof cond1 === 'function') { cond1 = cond1.call(this); }
115   if (typeof cond2 === 'function') { cond2 = cond2.call(this); }
116
117   if (cond1 || cond2) {
118     return options.fn(this);
119   } else {
120     return options.inverse(this);
121   }
122 });
123
124 // Ridiculous that this, too, is not part of regular Handlebars
125 // This code is by Mike Griffin, taken from this blog comment:
126 //      http://doginthehat.com.au/2012/02/comparison-block-helper-for-handlebars-templates/#comment-44
127
128 Handlebars.registerHelper('compare', function (lvalue, operator, rvalue, options) {
129   var operators, result;
130
131   if (arguments.length < 3) {
132     throw new Error("Handlerbars Helper 'compare' needs 2 parameters");
133   }
134
135   if (options === undefined) {
136     options = rvalue;
137     rvalue = operator;
138     operator = "===";
139   }
140
141   operators = {
142     '==': function (l, r) { return l == r; },
143     '===': function (l, r) { return l === r; },
144     '!=': function (l, r) { return l != r; },
145     '!==': function (l, r) { return l !== r; },
146     '<': function (l, r) { return l < r; },
147     '>': function (l, r) { return l > r; },
148     '<=': function (l, r) { return l <= r; },
149     '>=': function (l, r) { return l >= r; },
150     'typeof': function (l, r) { return typeof l == r; },
151     'matches': function (l, r) { return l.match(r); }
152   };
153
154   if (!operators[operator]) {
155     throw new Error("Handlerbars Helper 'compare' doesn't know the operator " + operator);
156   }
157
158   result = operators[operator](lvalue, rvalue);
159
160   if (result) {
161     return options.fn(this);
162   } else {
163     return options.inverse(this);
164   }
165 });