1angular.module('rainApp').directive('rangeSlider', function ($document) { 2 return { 3 restrict: 'E', 4 scope: { 5 min: '=', 6 max: '=', 7 minValue: '=', 8 maxValue: '=', 9 isPriceFilter: '@', 10 isFloat: '=', 11 useDynamicRanges: '=', 12 onUpdate: '&', 13 }, 14 templateUrl: function () { 15 return '/c/controls/range-slider/range-slider.template.html'; 16 }, 17 link: function (scope, element) { 18 var container = element[0].querySelector('.slider-container'); 19 var track = container.querySelector('.slider-track'); 20 var range = container.querySelector('.slider-range'); 21 var thumbMin = container.querySelector('.slider-thumb.min'); 22 var thumbMax = container.querySelector('.slider-thumb.max'); 23 24 scope.inputMinValue = formatWithCommasAndCurrency(scope.minValue); 25 scope.inputMaxValue = formatWithCommasAndCurrency(scope.maxValue); 26 27 var activeThumb = null; 28 29 function getAdjustedRanges(dynamicRanges) { 30 var adjustedRanges = []; 31 32 for (var i = 0; i < dynamicRanges.length; i++) { 33 var range = dynamicRanges[i]; 34 35 if (range.min >= scope.max) { 36 break; 37 } 38 39 adjustedRanges.push({ 40 min: range.min, 41 max: Math.min(range.max, scope.max), 42 increment: range.increment 43 }); 44 } 45 46 return adjustedRanges; 47 } 48 49 function getTotalWeight(ranges) { 50 return ranges.reduce((sum, range) => sum + (range.max - range.min) / range.increment, 0); 51 } 52 53 function getValueFromPercentageDynamic(percent, ranges) { 54 var targetWeight = (percent / 100) * getTotalWeight(ranges); 55 var accumulatedWeight = 0; 56 57 for (var i = 0; i < ranges.length; i++) { 58 var rangeWeight = (ranges[i].max - ranges[i].min) / ranges[i].increment; 59 60 if (targetWeight <= accumulatedWeight + rangeWeight) { 61 var stepsInRange = targetWeight - accumulatedWeight; 62 return ranges[i].min + stepsInRange * ranges[i].increment; 63 } 64 65 accumulatedWeight += rangeWeight; 66 } 67 68 return scope.max; 69 } 70 71 function getPercentageFromValueDynamic(value, ranges) { 72 var accumulatedWeight = 0; 73 74 for (var i = 0; i < ranges.length; i++) { 75 if (value <= ranges[i].max) { 76 var stepsInRange = (value - ranges[i].min) / ranges[i].increment; 77 return ((accumulatedWeight + stepsInRange) / getTotalWeight(ranges)) * 100; 78 } 79 80 accumulatedWeight += (ranges[i].max - ranges[i].min) / ranges[i].increment; 81 } 82 83 return 100; 84 } 85 86 function getValueFromPercentageLinear(percent) { 87 return scope.min + (percent / 100) * (scope.max - scope.min); 88 } 89 90 function getPercentageFromValueLinear(value) { 91 return ((value - scope.min) / (scope.max - scope.min)) * 100; 92 } 93 94 function getValueFromPercentage(percent) { 95 if (scope.useDynamicRanges) { 96 var ranges = getAdjustedRanges(scope.useDynamicRanges); 97 return getValueFromPercentageDynamic(percent, ranges); 98 } 99 100 return getValueFromPercentageLinear(percent); 101 } 102 103 function getPercentageFromValue(value) { 104 if (scope.useDynamicRanges) { 105 var ranges = getAdjustedRanges(scope.useDynamicRanges); 106 return getPercentageFromValueDynamic(value, ranges); 107 } 108 109 return getPercentageFromValueLinear(value); 110 } 111 112 function updatePositions() { 113 var percentMin = getPercentageFromValue(scope.minValue); 114 var percentMax = getPercentageFromValue(scope.maxValue); 115 116 thumbMin.style.left = `${percentMin}%`; 117 thumbMax.style.left = `${percentMax}%`; 118 119 range.style.left = `${percentMin}%`; 120 range.style.right = `${100 - percentMax}%`; 121 122 if (percentMin > 50) { 123 thumbMin.style.zIndex = 2; 124 thumbMax.style.zIndex = 1; 125 } else { 126 thumbMin.style.zIndex = 1; 127 thumbMax.style.zIndex = 2; 128 } 129 } 130 131 function setModelValue(percent) { 132 var isMin = activeThumb.classList.contains('min'); 133 var value = getValueFromPercentage(percent); 134 135 if (isMin) { 136 scope.minValue = Math.min(value, scope.maxValue); 137 scope.inputMinValue = formatWithCommasAndCurrency(Math.min(value, scope.maxValue)); 138 } else { 139 scope.maxValue = Math.max(value, scope.minValue);
140 scope.inputMaxValue = formatWithCommasAndCurrency(Math.max(value, scope.minValue)); 141 } 142 143 scope.$apply(); 144 } 145 146 function startDrag(event, thumb) { 147 event.preventDefault(); 148 activeThumb = thumb; 149 150 $document.on('mousemove', onDrag); 151 $document.on('mouseup', stopDrag); 152 } 153 154 function onDrag(event) { 155 if (!activeThumb) { 156 return; 157 } 158 159 var rect = track.getBoundingClientRect(); 160 var percent = Math.min(100, Math.max(0, ((event.clientX - rect.left) / rect.width) * 100)); 161 162 setModelValue(percent); 163 } 164 165 function stopDrag() { 166 activeThumb = null; 167 168 $document.off('mousemove', onDrag); 169 $document.off('mouseup', stopDrag); 170 } 171 172 scope.applyMinKeyUp = function (event) { 173 if (13 === event.keyCode) { 174 scope.triggerMinUpdate(); 175 } 176 } 177 178 scope.applyMaxKeyUp = function (event) { 179 if (13 === event.keyCode) { 180 scope.triggerMaxUpdate(); 181 } 182 } 183 184 scope.applyMinValue = function () { 185 validateMinValue(); 186 187 scope.minValue = scope.inputMinValue; 188 scope.inputMinValue = formatWithCommasAndCurrency(scope.inputMinValue); 189 190 updatePositions(); 191 } 192 193 scope.setMinValueWithoutCommas = function () { 194 if (scope.isFloat) { 195 scope.inputMinValue = parseFloat(scope.minValue).toFixed(2); 196 } else { 197 scope.inputMinValue = scope.minValue; 198 } 199 } 200 201 function validateMinValue() { 202 scope.inputMinValue = String(scope.inputMinValue).replace(/[^\d.]/g, ''); 203 204 var minRangeValue = scope.min; 205 var maxRangeValue = scope.maxValue; 206 207 if (scope.inputMinValue < minRangeValue) { 208 scope.inputMinValue = minRangeValue; 209 } 210 if (scope.inputMinValue > maxRangeValue) { 211 scope.inputMinValue = maxRangeValue; 212 } 213 } 214 215 function formatWithCommasAndCurrency(value) { 216 var options = scope.isFloat 217 ? { minimumFractionDigits: 2, maximumFractionDigits: 2, style: 'decimal' } 218 : { minimumFractionDigits: 0, maximumFractionDigits: 0, style: 'decimal' }; 219 220 var formatter = new Intl.NumberFormat(false, options); 221 return scope.isPriceFilter ? (window.currencySymbol || '$') + ' ' + formatter.format(value) : formatter.format(value); 222 } 223 224 scope.applyMaxValue = function () { 225 validateMaxValue(); 226 227 scope.maxValue = scope.inputMaxValue; 228 scope.inputMaxValue = formatWithCommasAndCurrency(scope.inputMaxValue); 229 230 updatePositions(); 231 } 232 233 scope.setMaxValueWithoutCommas = function () { 234 if (scope.isFloat) { 235 scope.inputMaxValue = parseFloat(scope.maxValue).toFixed(2); 236 } else { 237 scope.inputMaxValue = scope.maxValue; 238 } 239 } 240 241 function validateMaxValue() { 242 scope.inputMaxValue = parseFloat(String(scope.inputMaxValue).replace(/[^\d.]/g, '')); 243 244 var minRangeValue = scope.minValue; 245 var maxRangeValue = scope.max; 246 247 if (scope.inputMaxValue > maxRangeValue) { 248 scope.inputMaxValue = maxRangeValue; 249 } 250 251 if (scope.inputMaxValue < minRangeValue) { 252 scope.inputMaxValue = minRangeValue; 253 } 254 } 255 256 scope.triggerMinUpdate = function () { 257 scope.applyMinValue() 258 scope.onUpdate({ $event: { update: true } }); 259 }; 260 261 scope.triggerMaxUpdate = function () {
262 scope.applyMaxValue() 263 scope.onUpdate({ $event: { update: true } }); 264 }; 265 266 thumbMin.addEventListener('mousedown', function (event) { 267 startDrag(event, thumbMin) 268 }); 269 thumbMax.addEventListener('mousedown', function (event) { 270 startDrag(event, thumbMax) 271 }); 272 273 scope.$watchGroup(['minValue', 'maxValue'], updatePositions); 274 scope.$watchGroup(['min', 'max'], updatePositions); 275 276 updatePositions(); 277 }, 278 }; 279});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.