|
1 | | -import { |
2 | | - bemHelper, |
3 | | - prepareTemplateProps, |
4 | | - getContainerNode, |
5 | | -} from '../../lib/utils.js'; |
6 | | -import find from 'lodash/find'; |
7 | | -import cx from 'classnames'; |
8 | | - |
9 | | -const bem = bemHelper('ais-range-slider'); |
10 | | -const defaultTemplates = { |
11 | | - header: '', |
12 | | - footer: '', |
13 | | -}; |
| 1 | +import {checkRendering} from '../../lib/utils.js'; |
| 2 | + |
| 3 | +const usage = `Usage: |
| 4 | +var customRangeSlider = connectRangeSlider(function render(params, isFirstRendering) { |
| 5 | + // params = { |
| 6 | + // refine, |
| 7 | + // range, |
| 8 | + // start, |
| 9 | + // instantSearchInstance, |
| 10 | + // } |
| 11 | +}); |
| 12 | +search.addWidget( |
| 13 | + customRangeSlider({ |
| 14 | + attributeName, |
| 15 | + min, |
| 16 | + max, |
| 17 | + precision |
| 18 | + }); |
| 19 | +); |
| 20 | +Full documentation available at https://community.algolia.com/instantsearch.js/connectors/connectRangeSlider.html |
| 21 | +`; |
14 | 22 |
|
15 | 23 | /** |
16 | 24 | * Instantiate a slider based on a numeric attribute. |
@@ -40,165 +48,118 @@ const defaultTemplates = { |
40 | 48 | * @param {number} [options.max] Maximal slider value, defaults to automatically computed from the result set |
41 | 49 | * @return {Object} |
42 | 50 | */ |
43 | | -const usage = `Usage: |
44 | | -rangeSlider({ |
45 | | - container, |
46 | | - attributeName, |
47 | | - [ tooltips=true ], |
48 | | - [ templates.{header, footer} ], |
49 | | - [ cssClasses.{root, header, body, footer} ], |
50 | | - [ step=1 ], |
51 | | - [ pips=true ], |
52 | | - [ autoHideContainer=true ], |
53 | | - [ collapsible=false ], |
54 | | - [ min ], |
55 | | - [ max ] |
56 | | -}); |
57 | | -`; |
58 | | -const connectRangeSlider = rangeSliderRendering => ({ |
59 | | - container, |
| 51 | + |
| 52 | +export default function connectRangeSlider(renderFn) { |
| 53 | + checkRendering(renderFn, usage); |
| 54 | + |
| 55 | + return ({ |
60 | 56 | attributeName, |
61 | | - tooltips = true, |
62 | | - templates = defaultTemplates, |
63 | | - collapsible = false, |
64 | | - cssClasses: userCssClasses = {}, |
65 | | - step = 1, |
66 | | - pips = true, |
67 | | - autoHideContainer = true, |
68 | 57 | min: userMin, |
69 | 58 | max: userMax, |
70 | 59 | precision = 2, |
71 | | - } = {}) => { |
72 | | - if (!container || !attributeName) { |
73 | | - throw new Error(usage); |
74 | | - } |
| 60 | + }) => { |
| 61 | + if (!attributeName) { |
| 62 | + throw new Error(usage); |
| 63 | + } |
| 64 | + |
| 65 | + const formatToNumber = v => Number(Number(v).toFixed(precision)); |
| 66 | + |
| 67 | + const sliderFormatter = { |
| 68 | + from: v => v, |
| 69 | + to: v => formatToNumber(v).toLocaleString(), |
| 70 | + }; |
| 71 | + |
| 72 | + return { |
| 73 | + getConfiguration: originalConf => { |
| 74 | + const conf = { |
| 75 | + disjunctiveFacets: [attributeName], |
| 76 | + }; |
| 77 | + |
| 78 | + const hasUserBounds = userMin !== undefined || userMax !== undefined; |
| 79 | + const boundsNotAlreadyDefined = !originalConf || |
| 80 | + originalConf.numericRefinements && |
| 81 | + originalConf.numericRefinements[attributeName] === undefined; |
| 82 | + |
| 83 | + if (hasUserBounds && boundsNotAlreadyDefined) { |
| 84 | + conf.numericRefinements = {[attributeName]: {}}; |
| 85 | + if (userMin !== undefined) conf.numericRefinements[attributeName]['>='] = [userMin]; |
| 86 | + if (userMax !== undefined) conf.numericRefinements[attributeName]['<='] = [userMax]; |
| 87 | + } |
75 | 88 |
|
76 | | - const formatToNumber = v => Number(Number(v).toFixed(precision)); |
| 89 | + return conf; |
| 90 | + }, |
77 | 91 |
|
78 | | - const sliderFormatter = { |
79 | | - from: v => v, |
80 | | - to: v => formatToNumber(v).toLocaleString(), |
81 | | - }; |
| 92 | + _getCurrentRefinement(helper) { |
| 93 | + let min = helper.state.getNumericRefinement(attributeName, '>='); |
| 94 | + let max = helper.state.getNumericRefinement(attributeName, '<='); |
82 | 95 |
|
83 | | - const containerNode = getContainerNode(container); |
84 | | - |
85 | | - const cssClasses = { |
86 | | - root: cx(bem(null), userCssClasses.root), |
87 | | - header: cx(bem('header'), userCssClasses.header), |
88 | | - body: cx(bem('body'), userCssClasses.body), |
89 | | - footer: cx(bem('footer'), userCssClasses.footer), |
90 | | - }; |
91 | | - |
92 | | - return { |
93 | | - getConfiguration: originalConf => { |
94 | | - const conf = { |
95 | | - disjunctiveFacets: [attributeName], |
96 | | - }; |
97 | | - |
98 | | - const hasUserBounds = userMin !== undefined || userMax !== undefined; |
99 | | - const boundsNotAlreadyDefined = !originalConf || |
100 | | - originalConf.numericRefinements && |
101 | | - originalConf.numericRefinements[attributeName] === undefined; |
102 | | - |
103 | | - if (hasUserBounds && boundsNotAlreadyDefined) { |
104 | | - conf.numericRefinements = {[attributeName]: {}}; |
105 | | - if (userMin !== undefined) conf.numericRefinements[attributeName]['>='] = [userMin]; |
106 | | - if (userMax !== undefined) conf.numericRefinements[attributeName]['<='] = [userMax]; |
107 | | - } |
108 | | - |
109 | | - return conf; |
110 | | - }, |
111 | | - _getCurrentRefinement(helper) { |
112 | | - let min = helper.state.getNumericRefinement(attributeName, '>='); |
113 | | - let max = helper.state.getNumericRefinement(attributeName, '<='); |
114 | | - |
115 | | - if (min && min.length) { |
116 | | - min = min[0]; |
117 | | - } else { |
118 | | - min = -Infinity; |
119 | | - } |
120 | | - |
121 | | - if (max && max.length) { |
122 | | - max = max[0]; |
123 | | - } else { |
124 | | - max = Infinity; |
125 | | - } |
126 | | - |
127 | | - return { |
128 | | - min, |
129 | | - max, |
130 | | - }; |
131 | | - }, |
132 | | - init({helper, templatesConfig}) { |
133 | | - this._templateProps = prepareTemplateProps({ |
134 | | - defaultTemplates, |
135 | | - templatesConfig, |
136 | | - templates, |
137 | | - }); |
138 | | - this._refine = bounds => newValues => { |
139 | | - helper.clearRefinements(attributeName); |
140 | | - if (!bounds.min || newValues[0] > bounds.min) { |
141 | | - helper.addNumericRefinement(attributeName, '>=', formatToNumber(newValues[0])); |
| 96 | + if (min && min.length) { |
| 97 | + min = min[0]; |
| 98 | + } else { |
| 99 | + min = -Infinity; |
142 | 100 | } |
143 | | - if (!bounds.max || newValues[1] < bounds.max) { |
144 | | - helper.addNumericRefinement(attributeName, '<=', formatToNumber(newValues[1])); |
| 101 | + |
| 102 | + if (max && max.length) { |
| 103 | + max = max[0]; |
| 104 | + } else { |
| 105 | + max = Infinity; |
145 | 106 | } |
146 | | - helper.search(); |
147 | | - }; |
148 | | - |
149 | | - const stats = { |
150 | | - min: userMin || null, |
151 | | - max: userMax || null, |
152 | | - }; |
153 | | - const currentRefinement = this._getCurrentRefinement(helper); |
154 | | - |
155 | | - rangeSliderRendering({ |
156 | | - collapsible, |
157 | | - cssClasses, |
158 | | - refine: this._refine(stats), |
159 | | - pips, |
160 | | - range: {min: Math.floor(stats.min), max: Math.ceil(stats.max)}, |
161 | | - shouldAutoHideContainer: autoHideContainer && stats.min === stats.max, |
162 | | - start: [currentRefinement.min, currentRefinement.max], |
163 | | - step, |
164 | | - templateProps: this._templateProps, |
165 | | - tooltips, |
166 | | - format: sliderFormatter, |
167 | | - containerNode, |
168 | | - }, true); |
169 | | - }, |
170 | | - render({results, helper}) { |
171 | | - const facet = find(results.disjunctiveFacets, {name: attributeName}); |
172 | | - const stats = facet !== undefined && facet.stats !== undefined ? facet.stats : { |
173 | | - min: null, |
174 | | - max: null, |
175 | | - }; |
176 | | - |
177 | | - if (userMin !== undefined) stats.min = userMin; |
178 | | - if (userMax !== undefined) stats.max = userMax; |
179 | | - |
180 | | - const currentRefinement = this._getCurrentRefinement(helper); |
181 | | - |
182 | | - if (tooltips.format !== undefined) { |
183 | | - tooltips = [{to: tooltips.format}, {to: tooltips.format}]; |
184 | | - } |
185 | | - |
186 | | - rangeSliderRendering({ |
187 | | - collapsible, |
188 | | - cssClasses, |
189 | | - refine: this._refine(stats), |
190 | | - pips, |
191 | | - range: {min: Math.floor(stats.min), max: Math.ceil(stats.max)}, |
192 | | - shouldAutoHideContainer: autoHideContainer && stats.min === stats.max, |
193 | | - start: [currentRefinement.min, currentRefinement.max], |
194 | | - step, |
195 | | - templateProps: this._templateProps, |
196 | | - tooltips, |
197 | | - format: sliderFormatter, |
198 | | - containerNode, |
199 | | - }, false); |
200 | | - }, |
201 | | - }; |
202 | | -}; |
203 | 107 |
|
204 | | -export default connectRangeSlider; |
| 108 | + return { |
| 109 | + min, |
| 110 | + max, |
| 111 | + }; |
| 112 | + }, |
| 113 | + |
| 114 | + init({helper, instantSearchInstance}) { |
| 115 | + this._instantSearchInstance = instantSearchInstance; |
| 116 | + |
| 117 | + this._refine = bounds => newValues => { |
| 118 | + helper.clearRefinements(attributeName); |
| 119 | + if (!bounds.min || newValues[0] > bounds.min) { |
| 120 | + helper.addNumericRefinement(attributeName, '>=', formatToNumber(newValues[0])); |
| 121 | + } |
| 122 | + if (!bounds.max || newValues[1] < bounds.max) { |
| 123 | + helper.addNumericRefinement(attributeName, '<=', formatToNumber(newValues[1])); |
| 124 | + } |
| 125 | + helper.search(); |
| 126 | + }; |
| 127 | + |
| 128 | + const stats = { |
| 129 | + min: userMin || null, |
| 130 | + max: userMax || null, |
| 131 | + }; |
| 132 | + const currentRefinement = this._getCurrentRefinement(helper); |
| 133 | + |
| 134 | + renderFn({ |
| 135 | + refine: this._refine(stats), |
| 136 | + range: {min: Math.floor(stats.min), max: Math.ceil(stats.max)}, |
| 137 | + start: [currentRefinement.min, currentRefinement.max], |
| 138 | + format: sliderFormatter, |
| 139 | + instantSearchInstance: this._instantSearchInstance, |
| 140 | + }, true); |
| 141 | + }, |
| 142 | + |
| 143 | + render({results, helper}) { |
| 144 | + const facet = (results.disjunctiveFacets || []).find(({name}) => name === attributeName); |
| 145 | + const stats = facet !== undefined && facet.stats !== undefined ? facet.stats : { |
| 146 | + min: null, |
| 147 | + max: null, |
| 148 | + }; |
| 149 | + |
| 150 | + if (userMin !== undefined) stats.min = userMin; |
| 151 | + if (userMax !== undefined) stats.max = userMax; |
| 152 | + |
| 153 | + const currentRefinement = this._getCurrentRefinement(helper); |
| 154 | + |
| 155 | + renderFn({ |
| 156 | + refine: this._refine(stats), |
| 157 | + range: {min: Math.floor(stats.min), max: Math.ceil(stats.max)}, |
| 158 | + start: [currentRefinement.min, currentRefinement.max], |
| 159 | + format: sliderFormatter, |
| 160 | + instantSearchInstance: this._instantSearchInstance, |
| 161 | + }, false); |
| 162 | + }, |
| 163 | + }; |
| 164 | + }; |
| 165 | +} |
0 commit comments