Skip to content

Commit 87a0bc9

Browse files
committed
Merge pull request #23 from cloudfour/feat-dummyImgSrc
Add dummyImgSrc helper
2 parents 698d1f5 + 7e0c928 commit 87a0bc9

File tree

3 files changed

+128
-2
lines changed

3 files changed

+128
-2
lines changed

lib/dummyImgSrc.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
'use strict';
2+
3+
var R = require('ramda');
4+
var Handlebars = require('handlebars');
5+
var tinycolor = require('tinycolor2');
6+
7+
var source = '<svg xmlns="http://www.w3.org/2000/svg" width="{{width}}" height="{{height}}" viewBox="0 0 {{width}} {{height}}">' +
8+
'<rect fill="{{bg}}" width="100%" height="100%"/>' +
9+
'<text fill="{{fg}}" font-family="{{font}}" font-size="{{size}}" dy="{{dy}}" font-weight="{{weight}}" x="50%" y="50%" text-anchor="middle">{{{text}}}</text>' +
10+
'</svg>';
11+
12+
var template = Handlebars.compile(source);
13+
14+
function encode (svgString) {
15+
// Thanks to: filamentgroup/directory-encoder
16+
return 'data:image/svg+xml;charset=US-ASCII,' + encodeURIComponent(svgString
17+
// strip newlines and tabs
18+
.replace(/[\n\r]/gmi, '')
19+
.replace(/\t/gmi, ' ')
20+
// strip comments
21+
.replace(/<\!\-\-(.*(?=\-\->))\-\->/gmi, '')
22+
// replace
23+
.replace(/'/gmi, '\\i'))
24+
// encode brackets
25+
.replace(/\(/g, '%28').replace(/\)/g, '%29');
26+
}
27+
28+
function create (width, height, options) {
29+
options = R.merge({
30+
width: width,
31+
height: height,
32+
text: width + ' &#215; ' + height,
33+
bg: '#ddd',
34+
size: Math.floor(height * 0.2),
35+
dy: Math.floor(height * 0.2 * 0.4),
36+
weight: 'bold',
37+
font: 'sans-serif'
38+
}, options || {});
39+
40+
if (R.isNil(options.fg)) {
41+
options.fg = (function (bg) {
42+
var color = tinycolor(bg);
43+
var method = color.isDark() ? 'lighten' : 'darken';
44+
return color[method](50).toString();
45+
})(options.bg);
46+
}
47+
48+
return template(options);
49+
}
50+
51+
/**
52+
* Returns an escaped data URI for a placeholder image that can be used as the
53+
* src attribute of an img element.
54+
*
55+
* @since v0.3.0
56+
* @param {Number} width
57+
* @param {Number} height
58+
* @param {Object} options
59+
* @return {String}
60+
* @example
61+
*
62+
* <img src="{{placeholder 150 50}}">
63+
*
64+
* <img src="{{placeholder 150 50 text="foo"}}">
65+
*
66+
* <img src="{{placeholder 150 50 bg="#000"}}">
67+
*
68+
* <img src="{{placeholder 150 50 fg="pink"}}">
69+
*/
70+
71+
module.exports = function dummyImgSrc (width, height, options) {
72+
if (!R.is(Number, width) || !R.is(Number, height)) {
73+
throw new Error('The "dummyImgSrc" helper must be passed two numeric dimensions.');
74+
}
75+
76+
var result = encode(create(width, height, options.hash));
77+
78+
return new Handlebars.SafeString(result);
79+
};

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "core-hbs-helpers",
3-
"version": "0.2.0",
3+
"version": "0.3.0",
44
"description": "Handlebars helpers that we usually need.",
55
"main": "index.js",
66
"files": [
@@ -30,7 +30,8 @@
3030
"handlebars": "^4.0.3",
3131
"moment": "^2.10.6",
3232
"ramda": "^0.18.0",
33-
"require-dir": "^0.3.0"
33+
"require-dir": "^0.3.0",
34+
"tinycolor2": "^1.3.0"
3435
},
3536
"devDependencies": {
3637
"html-entities": "^1.2.0",

test/dummyImgSrc.spec.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
'use strict';
2+
3+
var dummyImgSrc = require('../').dummyImgSrc;
4+
var tape = require('tape');
5+
var Handlebars = require('handlebars');
6+
7+
Handlebars.registerHelper(dummyImgSrc.name, dummyImgSrc);
8+
9+
tape('dummyImgSrc', function (test) {
10+
var template;
11+
var expected;
12+
var actual;
13+
14+
test.plan(5);
15+
16+
template = Handlebars.compile('{{dummyImgSrc 48 48}}');
17+
expected = 'data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2248%22%20height%3D%2248%22%20viewBox%3D%220%200%2048%2048%22%3E%3Crect%20fill%3D%22%23ddd%22%20width%3D%22100%25%22%20height%3D%22100%25%22%2F%3E%3Ctext%20fill%3D%22%235d5d5d%22%20font-family%3D%22sans-serif%22%20font-size%3D%229%22%20dy%3D%223%22%20font-weight%3D%22bold%22%20x%3D%2250%25%22%20y%3D%2250%25%22%20text-anchor%3D%22middle%22%3E48%20%26%23215%3B%2048%3C%2Ftext%3E%3C%2Fsvg%3E';
18+
actual = template();
19+
test.equal(actual, expected, 'Works with width and height');
20+
21+
template = Handlebars.compile('{{dummyImgSrc 48 48 text="foo" bg="#333" fg="#fff" font="serif"}}');
22+
expected = 'data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2248%22%20height%3D%2248%22%20viewBox%3D%220%200%2048%2048%22%3E%3Crect%20fill%3D%22%23333%22%20width%3D%22100%25%22%20height%3D%22100%25%22%2F%3E%3Ctext%20fill%3D%22%23fff%22%20font-family%3D%22serif%22%20font-size%3D%229%22%20dy%3D%223%22%20font-weight%3D%22bold%22%20x%3D%2250%25%22%20y%3D%2250%25%22%20text-anchor%3D%22middle%22%3Efoo%3C%2Ftext%3E%3C%2Fsvg%3E';
23+
actual = template();
24+
test.equal(actual, expected, 'Works with options');
25+
26+
template = Handlebars.compile('{{dummyImgSrc}}');
27+
test.throws(
28+
template,
29+
/two numeric dimensions\.$/,
30+
'Errors when passed no dimensions'
31+
);
32+
33+
template = Handlebars.compile('{{dummyImgSrc 48}}');
34+
test.throws(
35+
template,
36+
/two numeric dimensions\.$/,
37+
'Errors when passed only one dimension'
38+
);
39+
40+
template = Handlebars.compile('{{dummyImgSrc "foo" "bar"}}');
41+
test.throws(
42+
template,
43+
/two numeric dimensions\.$/,
44+
'Errors when passed non-numeric dimensions'
45+
);
46+
});

0 commit comments

Comments
 (0)