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 var _urlRegexp = /^(https?:)?\/\//;
85 Handlebars.registerHelper('mkws-best-url', function(items) {
86   for (var i in items) {
87     var item = items[i]
88     if (item.match(_urlRegexp)) {
89       mkws.debug("'" + item + "' *is* a URL");
90       return item;
91     }
92     mkws.debug("'" + item + "' is not a URL");
93   }
94   return "";
95 });
96 Handlebars.registerHelper('mkws-other-urls', function(items) {
97   var res = [];
98   for (var i in items) {
99     var item = items[i]
100     if (item.match(_urlRegexp)) {
101       res.push(item);
102     }
103   }
104   return res;
105 });
106
107
108
109 Handlebars.registerHelper('mkws-commaList', function(items, options) {
110   var out = "";
111
112   for (var i in items) {
113     if (i > 0) out += ", ";
114     out += options.fn(items[i])
115   }
116
117   return out;
118 });
119
120
121 Handlebars.registerHelper('mkws-index1', function(obj) {
122   return obj.data.index + 1;
123 });
124
125 Handlebars.registerHelper('mkws-indexplus', function(delta, obj) {
126   return obj.data.index + delta;
127 });
128
129 Handlebars.registerHelper('mkws-repeat', function(count, options) {
130   var out = "";
131   for (var i = 0; i < count; i++) {
132     out += options.fn(this);
133   }
134   return out;
135 });
136
137 // Ridiculous that Handlebars has no way to do "or"
138 Handlebars.registerHelper('mkws-if-either', function(cond1, cond2, options) {
139   if (typeof cond1 === 'function') { cond1 = cond1.call(this); }
140   if (typeof cond2 === 'function') { cond2 = cond2.call(this); }
141
142   if (cond1 || cond2) {
143     return options.fn(this);
144   } else {
145     return options.inverse(this);
146   }
147 });
148
149 // Ridiculous that this, too, is not part of regular Handlebars
150 // This code is by Mike Griffin, taken from this blog comment:
151 //      http://doginthehat.com.au/2012/02/comparison-block-helper-for-handlebars-templates/#comment-44
152
153 Handlebars.registerHelper('compare', function (lvalue, operator, rvalue, options) {
154   var operators, result;
155
156   if (arguments.length < 3) {
157     throw new Error("Handlerbars Helper 'compare' needs 2 parameters");
158   }
159
160   if (options === undefined) {
161     options = rvalue;
162     rvalue = operator;
163     operator = "===";
164   }
165
166   operators = {
167     '==': function (l, r) { return l == r; },
168     '===': function (l, r) { return l === r; },
169     '!=': function (l, r) { return l != r; },
170     '!==': function (l, r) { return l !== r; },
171     '<': function (l, r) { return l < r; },
172     '>': function (l, r) { return l > r; },
173     '<=': function (l, r) { return l <= r; },
174     '>=': function (l, r) { return l >= r; },
175     'typeof': function (l, r) { return typeof l == r; },
176     'matches': function (l, r) { return l.match(r); }
177   };
178
179   if (!operators[operator]) {
180     throw new Error("Handlerbars Helper 'compare' doesn't know the operator " + operator);
181   }
182
183   result = operators[operator](lvalue, rvalue);
184
185   if (result) {
186     return options.fn(this);
187   } else {
188     return options.inverse(this);
189   }
190 });