Skip to content

Commit 6c926d0

Browse files
committed
feat(currentRefinedValues): new widget
Closes #404
1 parent 706316d commit 6c926d0

File tree

11 files changed

+1913
-1
lines changed

11 files changed

+1913
-1
lines changed

dev/app.js

+30
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,36 @@ search.addWidget(
8181
})
8282
);
8383

84+
search.addWidget(
85+
instantsearch.widgets.currentRefinedValues({
86+
container: '#current-refined-values',
87+
cssClasses: {
88+
header: 'facet-title',
89+
link: 'facet-value facet-value-removable',
90+
count: 'facet-count pull-right'
91+
},
92+
templates: {
93+
header: 'Current refinements'
94+
},
95+
attributes: [
96+
{
97+
name: 'price',
98+
label: 'Price',
99+
transformData: (data) => { data.name = `$${data.name}`; return data; }
100+
},
101+
{
102+
name: 'price_range',
103+
label: 'Price range',
104+
transformData: (data) => { data.name = data.name.replace(/(\d+)/g, '$$$1'); return data; }
105+
},
106+
{
107+
name: 'free_shipping',
108+
transformData: (data) => { if (data.name === 'true') data.name = 'Free shipping'; return data; }
109+
}
110+
]
111+
})
112+
);
113+
84114
search.addWidget(
85115
instantsearch.widgets.refinementList({
86116
container: '#brands',

dev/index.html

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ <h1><a href="./">Instant search demo</a> <small>using instantsearch.js</small></
2121

2222
<div class="row search search--hidden">
2323
<div class="col-md-3">
24-
<div id="clear-all"></div>
24+
<div class="facet" id="current-refined-values"></div>
2525
<div class="facet" id="hierarchical-categories"></div>
2626
<div class="facet" id="brands"></div>
2727
<div class="facet" id="price-range"></div>
@@ -30,6 +30,7 @@ <h1><a href="./">Instant search demo</a> <small>using instantsearch.js</small></
3030
<div class="facet" id="categories"></div>
3131
<div class="facet" id="price-ranges"></div>
3232
<div class="facet" id="price-numeric-list"></div>
33+
<div id="clear-all"></div>
3334
</div>
3435
<div class="col-md-9">
3536
<div class="form-group">

dev/style.css

+5
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ body {
101101
padding-left: 10px;
102102
}
103103

104+
.facet-value-removable:hover {
105+
text-decoration: line-through;
106+
font-weight: normal;
107+
}
108+
104109
.ais-refinement-list--label,
105110
.ais-toggle--label {
106111
display: block;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
let React = require('react');
2+
3+
let Template = require('../Template.js');
4+
5+
let {isSpecialClick} = require('../../lib/utils.js');
6+
let map = require('lodash/collection/map');
7+
let cloneDeep = require('lodash/lang/cloneDeep');
8+
9+
class CurrentRefinedValues extends React.Component {
10+
_clearAllElement(position, requestedPosition) {
11+
if (requestedPosition !== position) {
12+
return undefined;
13+
}
14+
return (
15+
<a
16+
className={this.props.cssClasses.clearAll}
17+
href={this.props.clearAllURL}
18+
onClick={handleClick(this.props.clearAllClick)}
19+
>
20+
<Template templateKey="clearAll" {...this.props.templateProps} />
21+
</a>
22+
);
23+
}
24+
25+
_refinementElement(refinement, i) {
26+
const attribute = this.props.attributes[refinement.attributeName] || {};
27+
const templateData = getTemplateData(attribute, refinement, this.props.cssClasses);
28+
const customTemplateProps = getCustomTemplateProps(attribute);
29+
const key = refinement.attributeName +
30+
(refinement.operator ? refinement.operator : ':') +
31+
(refinement.exclude ? refinement.exclude : '') +
32+
refinement.name;
33+
return (
34+
<div
35+
className={this.props.cssClasses.item}
36+
key={key}
37+
>
38+
<a
39+
className={this.props.cssClasses.link}
40+
href={this.props.clearRefinementURLs[i]}
41+
onClick={handleClick(this.props.clearRefinementClicks[i])}
42+
>
43+
<Template data={templateData} templateKey="item" {...this.props.templateProps} {...customTemplateProps} />
44+
</a>
45+
</div>
46+
);
47+
}
48+
49+
render() {
50+
return (
51+
<div>
52+
{this._clearAllElement('before', this.props.clearAllPosition)}
53+
<div className={this.props.cssClasses.list}>
54+
{map(this.props.refinements, this._refinementElement, this)}
55+
</div>
56+
{this._clearAllElement('after', this.props.clearAllPosition)}
57+
</div>
58+
);
59+
}
60+
}
61+
62+
function getCustomTemplateProps(attribute) {
63+
let customTemplateProps = {};
64+
if (attribute.template !== undefined) {
65+
customTemplateProps.templates = {
66+
item: attribute.template
67+
};
68+
}
69+
if (attribute.transformData !== undefined) {
70+
customTemplateProps.transformData = attribute.transformData;
71+
}
72+
return customTemplateProps;
73+
}
74+
75+
function getTemplateData(attribute, _refinement, cssClasses) {
76+
let templateData = cloneDeep(_refinement);
77+
78+
templateData.cssClasses = cssClasses;
79+
if (attribute.label !== undefined) {
80+
templateData.label = attribute.label;
81+
}
82+
if (templateData.operator !== undefined) {
83+
templateData.displayOperator = templateData.operator;
84+
if (templateData.operator === '>=') {
85+
templateData.displayOperator = '&ge;';
86+
}
87+
if (templateData.operator === '<=') {
88+
templateData.displayOperator = '&le;';
89+
}
90+
}
91+
92+
return templateData;
93+
}
94+
95+
function handleClick(cb) {
96+
return (e) => {
97+
if (isSpecialClick(e)) {
98+
// do not alter the default browser behavior
99+
// if one special key is down
100+
return;
101+
}
102+
e.preventDefault();
103+
cb();
104+
};
105+
}
106+
107+
CurrentRefinedValues.propTypes = {
108+
attributes: React.PropTypes.object,
109+
clearAllClick: React.PropTypes.func,
110+
clearAllPosition: React.PropTypes.oneOfType([
111+
React.PropTypes.string,
112+
React.PropTypes.bool
113+
]),
114+
clearAllURL: React.PropTypes.string,
115+
clearRefinementClicks: React.PropTypes.arrayOf(
116+
React.PropTypes.func
117+
),
118+
clearRefinementURLs: React.PropTypes.arrayOf(
119+
React.PropTypes.string
120+
),
121+
cssClasses: React.PropTypes.shape({
122+
clearAll: React.PropTypes.string,
123+
list: React.PropTypes.string,
124+
item: React.PropTypes.string,
125+
link: React.PropTypes.string,
126+
count: React.PropTypes.string
127+
}).isRequired,
128+
refinements: React.PropTypes.array,
129+
templateProps: React.PropTypes.object.isRequired
130+
};
131+
132+
module.exports = CurrentRefinedValues;

0 commit comments

Comments
 (0)