From 456d7816e87f5b5697e1ec2554402e5ba615b054 Mon Sep 17 00:00:00 2001 From: Matthieu Dumont Date: Fri, 25 Sep 2015 18:46:31 +0200 Subject: [PATCH] feat(templatesConfig): helpers and options transferred to Template New parameter passed to the `init` and `render` method: `templatesConfig`. It replaces `templateHelpers`. This parameter embeds both the `helpers` and the `Hogan` options. It uses the same chain that the `templateHelpers` previously used to be passed from a widget to the `Template` component. The `Template` component now also accepts a `templateDefault` parameter which allows us to ignore `Hogan`'s `options` if there is no `template` provided Closes #99. --- README.md | 14 +++++++++-- components/Hits.js | 5 ++++ components/RefinementList.js | 11 ++++++++- components/Stats.js | 12 +++++++--- components/Template.js | 17 +++++++++++--- decorators/headerFooter.js | 17 +++++++++++--- example/app.js | 5 ++++ example/templates/free-shipping.html | 1 + lib/InstantSearch.js | 17 ++++++++------ lib/utils.js | 23 ++++++++++++++---- scripts/lint.sh | 2 +- test/InstantSearch/lifecycle.js | 6 ++--- widgets/hits.js | 3 ++- widgets/menu.js | 23 +++++++----------- widgets/range-slider.js | 16 +++++++------ widgets/refinement-list.js | 26 +++++++++------------ widgets/stats/index.js | 9 +++---- widgets/toggle.js | 35 ++++++++++++++-------------- 18 files changed, 157 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index 93063f5fc2..9ad416fe48 100644 --- a/README.md +++ b/README.md @@ -143,13 +143,13 @@ search.addWidget( ); ``` -### Template helpers +### Template configuration In order to help you when defining your templates, `instantsearch.js` exposes a few helpers. All helpers are accessible in the Mustache templating through `{{#helpers.nameOfTheHelper}}{{valueToFormat}}{{/helpers.nameOfTheHelper}}`. To use them in the function templates, you'll have to call -`search.templateHelpers.nameOfTheHelper` where `search` is your current +`search.templatesConfig.helpers.nameOfTheHelper` where `search` is your current `instantsearch` instance. Here is the list of the currently available helpers: @@ -159,6 +159,16 @@ Here is the list of the currently available helpers: option (defaults to `en-EN`). eg. `100000` will be formatted as `100 000` with `en-EN` +`instantsearch.js` also provides the ability to set options to use with your +templating engine. These options are accessible through +`search.templatesConfig.options`. +With the embedded widgets using our `Template` component (widgets with +`template(s)` parameter), we're passing these options to `Hogan.compile` +if you're not using the default `template`. +```js +search.templatesConfig.options.delimiters = '[[ ]]'; +``` + ## Development workflow ```sh diff --git a/components/Hits.js b/components/Hits.js index 832a9d82f9..0809de9848 100644 --- a/components/Hits.js +++ b/components/Hits.js @@ -6,6 +6,7 @@ var Template = require('./Template'); class Hits extends React.Component { renderWithResults() { var template = this.props.hitTemplate; + var templatesConfig = this.props.templatesConfig; var transformData = this.props.hitTransformData; var renderedHits = map(this.props.hits, function(hit) { @@ -15,6 +16,7 @@ class Hits extends React.Component { transformData={transformData} key={hit.objectID} template={template} + config={templatesConfig} /> ); }, this); @@ -25,6 +27,7 @@ class Hits extends React.Component { renderNoResults() { var data = this.props.results; var template = this.props.noResultsTemplate; + var templatesConfig = this.props.templatesConfig; var transformData = this.props.noResultsTransformData; return ( @@ -33,6 +36,7 @@ class Hits extends React.Component { data={data} transformData={transformData} template={template} + config={templatesConfig} /> ); @@ -57,6 +61,7 @@ Hits.propTypes = { React.PropTypes.string, React.PropTypes.func ]).isRequired, + templatesConfig: React.PropTypes.object.isRequired, noResultsTransformData: React.PropTypes.func }; diff --git a/components/RefinementList.js b/components/RefinementList.js index e6d7b9a872..64c8b47f53 100644 --- a/components/RefinementList.js +++ b/components/RefinementList.js @@ -55,6 +55,8 @@ class RefinementList extends React.Component { data={facetValue} transformData={this.props.transformData} template={this.props.templates.item} + defaultTemplate={this.props.defaultTemplates.item} + config={this.props.templatesConfig} /> ); @@ -80,8 +82,15 @@ RefinementList.propTypes = { item: React.PropTypes.oneOfType([ React.PropTypes.string, React.PropTypes.func - ]).isRequired + ]) + }), + defaultTemplates: React.PropTypes.shape({ + item: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.func + ]) }), + templatesConfig: React.PropTypes.object.isRequired, transformData: React.PropTypes.func, toggleRefinement: React.PropTypes.func.isRequired }; diff --git a/components/Stats.js b/components/Stats.js index 6ac637d755..f74e08bec1 100644 --- a/components/Stats.js +++ b/components/Stats.js @@ -5,7 +5,8 @@ var Template = require('./Template'); class Stats extends React.Component { render() { var template = this.props.template; - var templateHelpers = this.props.templateHelpers; + var defaultTemplate = this.props.defaultTemplate; + var templatesConfig = this.props.templatesConfig; var transformData = this.props.transformData; var data = { hasManyResults: this.props.nbHits > 1, @@ -24,7 +25,8 @@ class Stats extends React.Component { data={data} transformData={transformData} template={template} - templateHelpers={templateHelpers} + defaultTemplate={defaultTemplate} + config={templatesConfig} /> ); } @@ -39,9 +41,13 @@ Stats.propTypes = { template: React.PropTypes.oneOfType([ React.PropTypes.func, React.PropTypes.string + ]), + defaultTemplate: React.PropTypes.oneOfType([ + React.PropTypes.func, + React.PropTypes.string ]).isRequired, transformData: React.PropTypes.func, - templateHelpers: React.PropTypes.object, + templatesConfig: React.PropTypes.object.isRequired, query: React.PropTypes.string }; diff --git a/components/Template.js b/components/Template.js index 5fe9b0f69e..9dff6c6265 100644 --- a/components/Template.js +++ b/components/Template.js @@ -6,10 +6,17 @@ class Template { render() { var content = renderTemplate({ template: this.props.template, - templateHelpers: this.props.templateHelpers, + defaultTemplate: this.props.defaultTemplate, + config: this.props.config, data: this.props.transformData ? this.props.transformData(this.props.data) : this.props.data }); + if (content === null) { + // Adds a noscript to the DOM but virtual DOM is null + // See http://facebook.github.io/react/docs/component-specs.html#render + return null; + } + return
; } } @@ -18,8 +25,12 @@ Template.propTypes = { template: React.PropTypes.oneOfType([ React.PropTypes.string, React.PropTypes.func - ]).isRequired, - templateHelpers: React.PropTypes.object, + ]), + defaultTemplate: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.func + ]), + config: React.PropTypes.object.isRequired, transformData: React.PropTypes.func, data: React.PropTypes.object }; diff --git a/decorators/headerFooter.js b/decorators/headerFooter.js index 18e03b7544..232c6ef7a5 100644 --- a/decorators/headerFooter.js +++ b/decorators/headerFooter.js @@ -9,9 +9,9 @@ function headerFooter(ComposedComponent) { render() { return (
-