add multirange input range scripts - jscancer - Javascript crap (relatively small)
HTML git clone git://git.codemadness.org/jscancer
DIR Log
DIR Files
DIR Refs
DIR README
DIR LICENSE
---
DIR commit 7f471d96bbdab4f5ce0605076805f378f730ebe7
DIR parent 2eb5ad4110cabfa6ebd65a0e631a7c1c49901d48
HTML Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date: Thu, 23 Jul 2026 19:26:52 +0200
add multirange input range scripts
Diffstat:
A multirange/README | 42 +++++++++++++++++++++++++++++++
A multirange/example.html | 130 +++++++++++++++++++++++++++++++
A multirange/filter.js | 100 +++++++++++++++++++++++++++++++
3 files changed, 272 insertions(+), 0 deletions(-)
---
DIR diff --git a/multirange/README b/multirange/README
@@ -0,0 +1,41 @@
+multi range filter
+==================
+
+Multiple input range filter.
+Intended for use-case where you need to select a minimum and maximum value
+within a certain range.
+
+Where each input range restricts min, max to eachother.
+
+Requires a modern browser that supports the list attribute (for ticks and
+snapping to a nearest value).
+
+
+FEATURES
+--------
+
+- Small:
+ - Filesize: +- 3KB (+- 1KB GZIP).
+ - Lines: +- 99, not much code, so hopefully easy to understand.
+ - No dependencies on other libraries like jQuery.
+- (Graceful) fallback to input range.
+- Support manual keyboard input for ranges.
+- Ticks and snapping to a value (requires browser support).
+- Custom label function to show depending on the value.
+- Detect decimal values, formatting them nicely (maximum digits required).
+- Permissive ISC license, see LICENSE file.
+- Supported browsers are:
+ - Firefox and Firefox ESR.
+ - Chrome and most recent webkit-based browsers.
+
+
+EXAMPLES
+--------
+
+See example.html for an example.
+
+
+Author
+------
+
+Hiltjo Posthuma <hiltjo@codemadness.org>
+\ No newline at end of file
DIR diff --git a/multirange/example.html b/multirange/example.html
@@ -0,0 +1,129 @@
+<html>
+<head>
+<title>Example</title>
+</head>
+<body>
+
+<style type="text/css">
+label {
+ font-weight: bold;
+}
+input:invalid {
+ border-color: #ff0000 !important;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(255, 0, 0, 0.3) !important;
+}
+</style>
+
+<form autocomplete="off">
+
+<h2>Example: basic example</h2>
+
+<table class="filterslider" data-from="filter_number_from[0]" data-to="filter_number_to[0]" data-label-from="filter_number_from_value[0]" data-label-to="filter_number_to_value[0]">
+ <tr>
+ <td class="label"><label for="filter_number_from[0]">From:</label></td>
+ <td class="input"><input class="slider" type="range" step="1" value="0" name="filter_number_from[0]" id="filter_number_from[0]" min="0" max="1000" /></td>
+ <td class="value"><span id="filter_number_from_value[0]">0</span></td>
+ <td class="measure">meter</td>
+ </tr>
+ <tr>
+ <td class="label"><label for="filter_number_to[0]">Through:</label></td>
+ <td class="input"><input class="slider" type="range" step="1" value="1000" name="filter_number_to[0]" id="filter_number_to[0]" min="0" max="1000" /></td>
+ <td class="value" id="filter_number_to_value[0]">1000</td>
+ <td class="measure">meter</td>
+ </tr>
+</table>
+
+<hr/>
+
+<h2>Example: basic example with ticks</h2>
+
+<p>
+<i>A datalist is used for ticks and snapping to values.</i>
+</p>
+
+<table class="filterslider" data-from="filter_number_from[1]" data-to="filter_number_to[1]" data-label-from="filter_number_from_value[1]" data-label-to="filter_number_to_value[1]">
+ <tr>
+ <td class="label"><label for="filter_number_from[1]">From:</label></td>
+ <td class="input"><input class="slider" type="range" step="1" value="0" name="filter_number_from[1]" id="filter_number_from[1]" min="0" max="1000" list="filter_values_1" /></td>
+ <td class="value"><span id="filter_number_from_value[1]">0</span></td>
+ <td class="measure">meter</td>
+ </tr>
+ <tr>
+ <td class="label"><label for="filter_number_to[1]">Through:</label></td>
+ <td class="input"><input class="slider" type="range" step="1" value="1000" name="filter_number_to[1]" id="filter_number_to[1]" min="0" max="1000" list="filter_values_1" /></td>
+ <td class="value" id="filter_number_to_value[1]">1000</td>
+ <td class="measure">meter</td>
+ </tr>
+</table>
+<datalist id="filter_values_1">
+ <option value="0" label="0"></option>
+ <option value="250" label="250"></option>
+ <option value="500" label="500"></option>
+ <option value="650" label="650"></option>
+ <option value="1000" label="1000"></option>
+</datalist>
+
+<hr/>
+
+<h2>Example: with decimals</h2>
+
+<p>
+<i>The step attribute must be set to "any" for some browsers for decimal values.</i>
+</p>
+
+<table class="filterslider" data-decimals="datalist" data-from="filter_number_from[2]" data-to="filter_number_to[2]" data-label-from="filter_number_from_value[2]" data-label-to="filter_number_to_value[2]">
+ <tr>
+ <td class="label"><label for="filter_number_from[2]">From:</label></td>
+ <td class="input"><input class="slider" type="range" step="any" value="0" name="filter_number_from[2]" id="filter_number_from[2]" min="0" max="1" list="filter_values_2" /></td>
+ <td class="value"><span id="filter_number_from_value[2]">0</span></td>
+ <td class="measure">meter</td>
+ </tr>
+ <tr>
+ <td class="label"><label for="filter_number_to[2]">Through:</label></td>
+ <td class="input"><input class="slider" type="range" step="any" value="1" name="filter_number_to[2]" id="filter_number_to[2]" min="0" max="1" list="filter_values_2" /></td>
+ <td class="value" id="filter_number_to_value[2]">1</td>
+ <td class="measure">meter</td>
+ </tr>
+</table>
+<datalist id="filter_values_2">
+ <option value="0.0" label="0"></option>
+ <option value="0.25" label="0.25"></option>
+ <option value="0.50" label="0.50"></option>
+ <option value="0.65" label="0.65"></option>
+ <option value="0.90" label="0.9"></option>
+ <option value="1.00" label="1.0"></option>
+</datalist>
+
+<hr/>
+
+<h2>Example: example allowing also manual input</h2>
+
+<table class="filterslider" data-from="filter_number_from[3]" data-to="filter_number_to[3]" data-label-from="filter_number_from_value[3]" data-label-to="filter_number_to_value[3]">
+ <tr>
+ <td class="label"><label for="filter_number_from[3]">From:</label></td>
+ <td class="input"><input class="slider" type="range" step="1" value="0" name="filter_number_from[3]" id="filter_number_from[3]" min="0" max="1000" list="filter_values_3" /></td>
+ <td class="value"><input id="filter_number_from_value[3]" type="number" value="0" step="1" min="0" max="1000" /></td>
+ <td class="measure">meter</td>
+ </tr>
+ <tr>
+ <td class="label"><label for="filter_number_to[3]">Through:</label></td>
+ <td class="input"><input class="slider" type="range" step="1" value="1000" name="filter_number_to[3]" id="filter_number_to[3]" min="0" max="1000" list="filter_values_3" /></td>
+ <td class="value"><input id="filter_number_to_value[3]" type="number" value="1000" step="1" min="0" max="1000" /></td>
+ <td class="measure">meter</td>
+ </tr>
+</table>
+<datalist id="filter_values_3">
+ <option value="0" label="0"></option>
+ <option value="250" label="250"></option>
+ <option value="500" label="500"></option>
+ <option value="650" label="650"></option>
+ <option value="1000" label="1000"></option>
+</datalist>
+
+</form>
+
+<script type="text/javascript" src="filter.js"></script>
+
+</body>
+
+</html>
+\ No newline at end of file
DIR diff --git a/multirange/filter.js b/multirange/filter.js
@@ -0,0 +1,99 @@
+var sliders = document.getElementsByClassName("filterslider");
+for (var i = 0; i < sliders.length; i++) {
+ var slider = sliders[i];
+ var fromel = document.getElementById(slider.getAttribute("data-from") || "");
+ var toel = document.getElementById(slider.getAttribute("data-to") || "");
+ if (fromel === null || toel === null)
+ continue;
+
+ // datalist: ticks and for snapping to value.
+ var datalistel = null;
+ var datalist = fromel.getAttribute("list") || "";
+ if (datalist !== "") {
+ datalistel = document.getElementById(datalist);
+ if (datalistel === null)
+ continue;
+ }
+
+ // decimals format based on datalist values.
+ var decimals = slider.getAttribute("data-decimals") || "0";
+ if (decimals === "datalist" && datalistel !== null) {
+ var maxdecimals = 0;
+ var countdecimals = function(v) {
+ if (Math.floor(v) !== v) {
+ var vs = v.toString().split(".");
+ return vs.length > 1 ? (vs[1].length || 0) : 0;
+ }
+ return 0;
+ };
+ var options = datalistel.options || [];
+ for (var j = 0; j < options.length; j++) {
+ var d = countdecimals(options[j].value);
+ if (d > maxdecimals)
+ maxdecimals = d;
+ }
+ decimals = maxdecimals;
+ } else {
+ decimals = parseInt(decimals) || 0;
+ }
+
+ var cfg = {
+ from: fromel,
+ to: toel,
+ labelfrom: document.getElementById(slider.getAttribute("data-label-from") || ""),
+ labelto: document.getElementById(slider.getAttribute("data-label-to") || ""),
+ decimals: decimals < 0 ? 0 : decimals
+ };
+
+ cfg.labelfn = (function(dec) {
+ return function(v) {
+ return Number(v).toFixed(dec);
+ };
+ })(cfg.decimals);
+
+ // from
+ cfg.inputrangefrom = (function(c) {
+ return function(e) {
+ if (parseFloat(c.from.value) > parseFloat(c.to.value))
+ c.from.value = c.to.value;
+ if (c.labelfrom !== null)
+ c.labelfrom[c.labelfrom.tagName === "INPUT" ? "value" : "innerText"] = c.labelfn(c.from.value);
+ };
+ })(cfg);
+ fromel.addEventListener("input", cfg.inputrangefrom);
+
+ // to
+ cfg.inputrangeto = (function(c) {
+ return function(e) {
+ if (parseFloat(c.to.value) < parseFloat(c.from.value))
+ c.to.value = c.from.value;
+ if (c.labelto !== null)
+ c.labelto[c.labelto.tagName === "INPUT" ? "value" : "innerText"] = c.labelfn(c.to.value);
+ };
+ })(cfg);
+ toel.addEventListener("input", cfg.inputrangeto);
+
+ // allow manual input if label is input element.
+ if (cfg.labelfrom != null && cfg.labelfrom.tagName === "INPUT") {
+ cfg.inputnumberfrom = (function(c) {
+ return function() {
+ this.max = c.to.value;
+ c.from.value = this.value;
+ };
+ })(cfg);
+ cfg.labelfrom.addEventListener("input", cfg.inputnumberfrom);
+ }
+ if (cfg.labelto != null && cfg.labelto.tagName === "INPUT") {
+ cfg.inputnumberto = (function(c) {
+ return function() {
+ this.min = c.from.value;
+ c.to.value = this.value;
+ };
+ })(cfg);
+ cfg.labelto.addEventListener("input", cfg.inputnumberto);
+ }
+
+ // call on init.
+ cfg.inputrangefrom();
+ cfg.inputrangeto();
+}
+\ No newline at end of file