Skip to content

Commit cf6a83c

Browse files
committed
feat: formatNumber in Stats widget
1 parent 4cc2a5b commit cf6a83c

13 files changed

+59
-21
lines changed

components/Stats.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var Template = require('./Template');
55
class Stats extends React.Component {
66
render() {
77
var template = this.props.template;
8+
var templateHelpers = this.props.templateHelpers;
89
var data = {
910
nbHits: this.props.nbHits,
1011
hasNoResults: this.props.nbHits === 0,
@@ -17,6 +18,7 @@ class Stats extends React.Component {
1718
<Template
1819
data={data}
1920
template={template}
21+
templateHelpers={templateHelpers}
2022
/>
2123
);
2224
}
@@ -28,7 +30,8 @@ Stats.propTypes = {
2830
template: React.PropTypes.oneOfType([
2931
React.PropTypes.func,
3032
React.PropTypes.string
31-
]).isRequired
33+
]).isRequired,
34+
templateHelpers: React.PropTypes.object
3235
};
3336

3437
module.exports = Stats;

components/Template.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ var renderTemplate = require('../lib/utils').renderTemplate;
44

55
class Template {
66
render() {
7-
var content = renderTemplate(this.props.template, this.props.data);
7+
var content = renderTemplate({
8+
template: this.props.template,
9+
templateHelpers: this.props.templateHelpers,
10+
data: this.props.data
11+
});
812

913
return <div dangerouslySetInnerHTML={{__html: content}} />;
1014
}
@@ -15,6 +19,7 @@ Template.propTypes = {
1519
React.PropTypes.string,
1620
React.PropTypes.func
1721
]).isRequired,
22+
templateHelpers: React.PropTypes.object,
1823
data: React.PropTypes.object
1924
};
2025

example/app.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ var instantsearch = require('../');
33
var search = instantsearch({
44
appId: 'latency',
55
apiKey: '6be0576ff61c053d5f9a3225e2a90f76',
6-
indexName: 'instant_search'
6+
indexName: 'instant_search',
7+
numberLocale: 'fr-FR'
78
});
89

910
search.addWidget(

lib/InstantSearch.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class InstantSearch {
1010
appId = null,
1111
apiKey = null,
1212
indexName = null,
13+
numberLocale = 'en-EN',
1314
searchParameters = {}
1415
}) {
1516
if (appId === null || apiKey === null || indexName === null) {
@@ -22,14 +23,18 @@ Usage: instantsearch({
2223
throw new Error(usage);
2324
}
2425

25-
2626
var client = algoliasearch(appId, apiKey);
2727

2828
this.client = client;
2929
this.helper = null;
3030
this.indexName = indexName;
3131
this.searchParameters = searchParameters || {};
3232
this.widgets = [];
33+
this.templateHelpers = {
34+
formatNumber(number) {
35+
return Number(number).toLocaleString(numberLocale);
36+
}
37+
};
3338
}
3439

3540
addWidget(widgetDefinition) {
@@ -67,10 +72,16 @@ Usage: instantsearch({
6772

6873
_render(helper, results, state) {
6974
forEach(this.widgets, function(widget) {
70-
if (widget.render) {
71-
widget.render(results, state, helper);
75+
if (!widget.render) {
76+
return;
7277
}
73-
});
78+
widget.render({
79+
templateHelpers: this.templateHelpers,
80+
results,
81+
state,
82+
helper
83+
});
84+
}, this);
7485
}
7586

7687
_init(state, helper) {

lib/utils.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,35 @@ function isDomElement(o) {
1414
return o instanceof HTMLElement || o && o.nodeType > 0;
1515
}
1616

17-
function renderTemplate(template, data) {
17+
function renderTemplate({template, templateHelpers, data}) {
1818
var hogan = require('hogan.js');
19+
var forEach = require('lodash/collection/forEach');
1920
var content;
2021

21-
if (typeof template === 'string') {
22-
content = hogan.compile(template).render(data);
23-
} else if (typeof template === 'function') {
24-
content = template(data);
25-
} else {
22+
if (typeof template !== 'string' && typeof template !== 'function') {
2623
throw new Error('Template must be `string` or `function`');
2724
}
2825

26+
if (typeof template === 'function') {
27+
content = template(data);
28+
}
29+
30+
if (typeof template === 'string') {
31+
// We add all our template helper methods to the template as lambdas. Note
32+
// that lambdas in Mustache are supposed to accept a second argument of
33+
// `render` to get the rendered value, not the literal `{{value}}`. But
34+
// this is currently broken (see
35+
// https://github.com/twitter/hogan.js/issues/222).
36+
forEach(templateHelpers, function(method, name) {
37+
data['_' + name] = function() {
38+
return function(value) {
39+
return method(hogan.compile(value).render(data));
40+
};
41+
};
42+
});
43+
content = hogan.compile(this.props.template).render(data);
44+
}
45+
2946
return content;
3047
}
3148

widgets/hits.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ function hits({container = null, templates = {}, hitsPerPage = 20}) {
99

1010
return {
1111
getConfiguration: () => ({hitsPerPage}),
12-
render: function(results, state, helper) {
12+
render: function({results, helper}) {
1313
React.render(
1414
<Hits
1515
hits={results.hits}

widgets/index-selector.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function indexSelector({
3232
}
3333
},
3434

35-
render: function(results, state, helper) {
35+
render: function({helper}) {
3636
var containerId = containerNode.id;
3737
React.render(
3838
<IndexSelector

widgets/menu.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ function menu({
4747
attributes: [facetName]
4848
}]
4949
}),
50-
render: function(results, state, helper) {
50+
render: function({results, helper}) {
5151
React.render(
5252
<RefinementList
5353
rootClass={cx(rootClass)}

widgets/pagination.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function pagination({container, cssClass, labels, maxPages} = {}) {
88
var containerNode = utils.getContainerNode(container);
99

1010
return {
11-
render: function(results, state, helper) {
11+
render: function({results, helper}) {
1212
var nbPages = results.nbPages;
1313
if (maxPages !== undefined) {
1414
nbPages = Math.min(maxPages, results.nbPages);

widgets/refinement-list.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ function refinementList({
5555
getConfiguration: () => ({
5656
[operator === 'and' ? 'facets' : 'disjunctiveFacets']: [facetName]
5757
}),
58-
render: function(results, state, helper) {
58+
render: function({results, helper}) {
5959
React.render(
6060
<RefinementList
6161
rootClass={cx(rootClass)}

widgets/stats/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ function stats({container = null, template = defaultTemplate}) {
1212
}
1313

1414
return {
15-
render: function(results) {
15+
render: function({results, templateHelpers}) {
1616
React.render(
1717
<Stats
1818
nbHits={results.nbHits}
1919
processingTimeMS={results.processingTimeMS}
2020
template={template}
21+
templateHelpers={templateHelpers}
2122
/>,
2223
containerNode
2324
);

widgets/stats/template.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div>
22
{{#hasNoResults}}No results{{/hasNoResults}}
33
{{#hasOneResult}}1 result{{/hasOneResult}}
4-
{{#hasManyResults}}{{nbHits}} results{{/hasManyResults}}
4+
{{#hasManyResults}}{{#_formatNumber}}{{nbHits}}{{/_formatNumber}} results{{/hasManyResults}}
55
<small>found in {{processingTimeMS}}ms</small>
66
</div>

widgets/toggle.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function toggle({
3232
getConfiguration: () => ({
3333
facets: [facetName]
3434
}),
35-
render: function(results, state, helper) {
35+
render: function({helper}) {
3636
var isRefined = helper.hasRefinements(facetName);
3737

3838
function toggleFilter() {

0 commit comments

Comments
 (0)