-
Notifications
You must be signed in to change notification settings - Fork 1
/
helpers.js
225 lines (214 loc) · 5.77 KB
/
helpers.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
var Handlebars = require('handlebars')
delete require.cache[require.resolve('marked')]
var marked = require('marked')
delete require.cache[require.resolve('marked')]
var cheerio = require('cheerio')
var highlight = require('highlight.js')
highlight.configure({
'useBR': true
})
var renderer = new marked.Renderer()
// Renderer for HTML-tables with Bootstrap-classes
renderer.table = function (header, body) {
return '<table class="table table-bordered">\n' +
'<thead>\n' +
header +
'</thead>\n' +
'<tbody>\n' +
body +
'</tbody>\n' +
'</table>\n'
}
marked.setOptions({
highlight: function (code, name) {
var highlighted
if (name) {
highlighted = highlight.highlight(name, code).value
} else {
highlighted = highlight.highlightAuto(code).value
}
return highlight.fixMarkup(highlighted)
},
renderer: renderer
})
/**
* Default Handlebars-helpers for `bootprint-base`
* @name helpers
*/
module.exports = {
toUpperCase,
eachSorted,
equal,
md,
ifeq,
ifcontains,
json,
htmlId
}
/**
* Converts a string to uppercase
* @param {string} value the input string
* @returns {string} the uppercase string
* @access public
* @memberOf helpers
*/
function toUpperCase (value) {
return value ? value.toUpperCase() : ''
}
/**
* This block-helper can be used to iterate objects sorted by key. It behaves like the built-in
* `{{#each ...}}`-helper except that it can only be used for objects and the output is in a
* deterministic order (i.e. sorted).
*
* Example template:
*
* ```handlebars
* {{#eachSorted obj}}
* {{@index}} of {{@length}}: {{@key}}={{.}}
* {{/eachSorted}}
* ```
*
* With the data `{ b: 'another one', a: 'first' }`, ignoring newlines and indents, this will output
*
* ```text
* 1 of 2: a=first
* 2 of 2: b=another one
* ```
*
* The helper will set the following @-values according to the Handlebars documentation:
* `@first`, `@index`, `@key`, `@last`, `@length`
* @returns {string}
* @access public
* @memberOf helpers
*/
function eachSorted (context, options) {
var ret = ''
var data
if (typeof context !== 'object') {
return ret
}
var keys = Object.keys(context)
keys.sort(function (a, b) {
// http://stackoverflow.com/questions/8996963/how-to-perform-case-insensitive-sorting-in-javascript
a = String(a).toLowerCase()
b = String(b).toLowerCase()
/* istanbul ignore next: Should never happen, since all keys are different, but just to be sure... */
if (a === b) return 0
if (a > b) return 1
return -1
}).forEach(function (key, index) {
if (options.data) {
data = Handlebars.createFrame(options.data || {})
data.index = index
data.key = key
data.length = keys.length
data.first = index === 0
data.last = index === keys.length - 1
}
ret = ret + options.fn(context[key], {data: data})
})
return ret
}
/**
* Checks whether two values a equal as in `value1 == value2` (not `===`)
* @param value1
* @param value2
* @returns {boolean}
* @access public
* @memberOf helpers
*/
function equal (value1, value2) {
return value1 == value2 // eslint-disable-line
}
/**
* Render a markdown-formatted text as HTML.
* @param {string} `value` the markdown-formatted text
* @param {boolean} `options.hash.stripParagraph` the marked-md-renderer wraps generated HTML in a <p>-tag by default.
* If this options is set to true, the <p>-tag is stripped.
* @returns {Handlebars.SafeString} a Handlebars-SafeString containing the provieded
* markdown, rendered as HTML.
* @access public
* @memberOf helpers
*/
function md (value, options) {
if (!value) {
return value
}
var html = marked(value)
// We strip the surrounding <p>-tag, if
if (options.hash && options.hash.stripParagraph) {
var $ = cheerio('<root>' + html + '</root>')
// Only strip <p>-tags and only if there is just one of them.
if ($.children().length === 1 && $.children('p').length === 1) {
html = $.children('p').html()
}
}
return new Handlebars.SafeString(html)
}
/**
* Block helper that compares to values. The body is executed if both value equal.
* Example:
*
* ```hbs
* {{#ifeq value 10}}
* Value is 10
* {{else}}
* Value is not 10
* {{/ifeq}}
* ```
*
* @param {object} `v1` the first value
* @param {object} `v2` the second value
* @access public
* @memberOf helpers
*/
function ifeq (v1, v2, options) {
// http://stackoverflow.com/questions/8853396/logical-operator-in-a-handlebars-js-if-conditional
if (v1 === v2) {
return options.fn(this)
}
return options.inverse(this)
}
/**
* Converts a javascript-object into a stringified highlighted JSON-object
* @param {object} value the javascript object
* @returns {string}
* @access public
* @memberOf helpers
*/
function json (value) {
if (!value) {
return ''
}
var schemaString = require('json-stable-stringify')(value, {space: 4})
return new Handlebars.SafeString(marked('```json\r\n' + schemaString + '\n```'))
}
/**
* Executes the block, if an object is part of an array
* @param {object[]} array the array
* @param {object} object the javascript object
* @param {object} options the Handlebars options
* @returns {string}
* @access public
* @memberOf helpers
*/
function ifcontains (array, object, options) {
if (array && array.indexOf(object) >= 0) {
return options.fn(this)
}
return options.inverse(this)
}
/**
* Replace all characters that may not be used in HTML id-attributes by '-'.
* There is still the restriction that IDs may only start with letters, which
* is not addressed by this helper.
*
* @param {string} value the input value
* @returns {string} the value after replacement and escaping
*
* @access public
* @memberOf helpers
*/
function htmlId (value) {
return value.replace(/[^A-Za-z0-9-_:.]/g, '-')
}