Skip to content

Commit

Permalink
feat(currentRefinedValues): new widget
Browse files Browse the repository at this point in the history
Closes #404
  • Loading branch information
Jerska committed Dec 3, 2015
1 parent 706316d commit 6c926d0
Show file tree
Hide file tree
Showing 11 changed files with 1,913 additions and 1 deletion.
30 changes: 30 additions & 0 deletions dev/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,36 @@ search.addWidget(
})
);

search.addWidget(
instantsearch.widgets.currentRefinedValues({
container: '#current-refined-values',
cssClasses: {
header: 'facet-title',
link: 'facet-value facet-value-removable',
count: 'facet-count pull-right'
},
templates: {
header: 'Current refinements'
},
attributes: [
{
name: 'price',
label: 'Price',
transformData: (data) => { data.name = `$${data.name}`; return data; }
},
{
name: 'price_range',
label: 'Price range',
transformData: (data) => { data.name = data.name.replace(/(\d+)/g, '$$$1'); return data; }
},
{
name: 'free_shipping',
transformData: (data) => { if (data.name === 'true') data.name = 'Free shipping'; return data; }
}
]
})
);

search.addWidget(
instantsearch.widgets.refinementList({
container: '#brands',
Expand Down
3 changes: 2 additions & 1 deletion dev/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ <h1><a href="./">Instant search demo</a> <small>using instantsearch.js</small></

<div class="row search search--hidden">
<div class="col-md-3">
<div id="clear-all"></div>
<div class="facet" id="current-refined-values"></div>
<div class="facet" id="hierarchical-categories"></div>
<div class="facet" id="brands"></div>
<div class="facet" id="price-range"></div>
Expand All @@ -30,6 +30,7 @@ <h1><a href="./">Instant search demo</a> <small>using instantsearch.js</small></
<div class="facet" id="categories"></div>
<div class="facet" id="price-ranges"></div>
<div class="facet" id="price-numeric-list"></div>
<div id="clear-all"></div>
</div>
<div class="col-md-9">
<div class="form-group">
Expand Down
5 changes: 5 additions & 0 deletions dev/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ body {
padding-left: 10px;
}

.facet-value-removable:hover {
text-decoration: line-through;
font-weight: normal;
}

.ais-refinement-list--label,
.ais-toggle--label {
display: block;
Expand Down
132 changes: 132 additions & 0 deletions src/components/CurrentRefinedValues/CurrentRefinedValues.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
let React = require('react');

let Template = require('../Template.js');

let {isSpecialClick} = require('../../lib/utils.js');
let map = require('lodash/collection/map');
let cloneDeep = require('lodash/lang/cloneDeep');

class CurrentRefinedValues extends React.Component {
_clearAllElement(position, requestedPosition) {
if (requestedPosition !== position) {
return undefined;
}
return (
<a
className={this.props.cssClasses.clearAll}
href={this.props.clearAllURL}
onClick={handleClick(this.props.clearAllClick)}
>
<Template templateKey="clearAll" {...this.props.templateProps} />
</a>
);
}

_refinementElement(refinement, i) {
const attribute = this.props.attributes[refinement.attributeName] || {};
const templateData = getTemplateData(attribute, refinement, this.props.cssClasses);
const customTemplateProps = getCustomTemplateProps(attribute);
const key = refinement.attributeName +
(refinement.operator ? refinement.operator : ':') +
(refinement.exclude ? refinement.exclude : '') +
refinement.name;
return (
<div
className={this.props.cssClasses.item}
key={key}
>
<a
className={this.props.cssClasses.link}
href={this.props.clearRefinementURLs[i]}
onClick={handleClick(this.props.clearRefinementClicks[i])}
>
<Template data={templateData} templateKey="item" {...this.props.templateProps} {...customTemplateProps} />
</a>
</div>
);
}

render() {
return (
<div>
{this._clearAllElement('before', this.props.clearAllPosition)}
<div className={this.props.cssClasses.list}>
{map(this.props.refinements, this._refinementElement, this)}
</div>
{this._clearAllElement('after', this.props.clearAllPosition)}
</div>
);
}
}

function getCustomTemplateProps(attribute) {
let customTemplateProps = {};
if (attribute.template !== undefined) {
customTemplateProps.templates = {
item: attribute.template
};
}
if (attribute.transformData !== undefined) {
customTemplateProps.transformData = attribute.transformData;
}
return customTemplateProps;
}

function getTemplateData(attribute, _refinement, cssClasses) {
let templateData = cloneDeep(_refinement);

templateData.cssClasses = cssClasses;
if (attribute.label !== undefined) {
templateData.label = attribute.label;
}
if (templateData.operator !== undefined) {
templateData.displayOperator = templateData.operator;
if (templateData.operator === '>=') {
templateData.displayOperator = '&ge;';
}
if (templateData.operator === '<=') {
templateData.displayOperator = '&le;';
}
}

return templateData;
}

function handleClick(cb) {
return (e) => {
if (isSpecialClick(e)) {
// do not alter the default browser behavior
// if one special key is down
return;
}
e.preventDefault();
cb();
};
}

CurrentRefinedValues.propTypes = {
attributes: React.PropTypes.object,
clearAllClick: React.PropTypes.func,
clearAllPosition: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.bool
]),
clearAllURL: React.PropTypes.string,
clearRefinementClicks: React.PropTypes.arrayOf(
React.PropTypes.func
),
clearRefinementURLs: React.PropTypes.arrayOf(
React.PropTypes.string
),
cssClasses: React.PropTypes.shape({
clearAll: React.PropTypes.string,
list: React.PropTypes.string,
item: React.PropTypes.string,
link: React.PropTypes.string,
count: React.PropTypes.string
}).isRequired,
refinements: React.PropTypes.array,
templateProps: React.PropTypes.object.isRequired
};

module.exports = CurrentRefinedValues;
Loading

0 comments on commit 6c926d0

Please sign in to comment.