dxpr / DXB-Slider

A customizable range slider with RTL support, synchronized number input, and accessibility features for modern web applications.
GNU General Public License v2.0
0 stars 0 forks source link

Lack of Integration API for DXPR Slider #1

Closed mohamedhyouns closed 1 month ago

mohamedhyouns commented 1 month ago

Summary

The DXPR slider currently lacks an integration-friendly API, making it difficult to incorporate into a real codebase despite functioning well in a technical demo.

Problem

Efforts to integrate the DXPR slider into the DXPR codebase have proven challenging due to its poor integration capabilities. Unlike the Bootstrap slider, which offers a straightforward API, the DXPR slider lacks a similar interface. For instance, the Bootstrap slider provides easy integration with both JQuery and vanilla JavaScript:

// With JQuery
$("#ex11").slider({step: 20000, min: 0, max: 200000});

// Without JQuery
var slider = new Slider("#ex11", {
    step: 20000,
    min: 0,
    max: 200000
});

Suggestion

To improve integration, I propose the following modifications to the DXPR slider:

The changes

// dxb-slider.js

(function ($) {
    $.fn.DXBSlider = function (options) {
        // Set default options if none are provided
        const settings = $.extend({
            min: 0,
            max: 100,
            step: 1,
            value: ''
        }, options);

        // Iterate over each selected element
        return this.each(function () {
            const slider = this;
            const min = parseFloat(settings.min);
            const max = parseFloat(settings.max);
            const step = parseFloat(settings.step);
            const value = settings.value === "" || isNaN(parseFloat(settings.value)) || settings.value === "NaN"
                ? min
                : parseFloat(settings.value);

            // Set initial attributes
            slider.setAttribute('min', min);
            slider.setAttribute('max', max);
            slider.setAttribute('step', step);
            slider.value = value;

            // Create number input programmatically
            const container = slider.closest('.dxb-slider-wrapper');
            const numberInput = document.createElement('input');
            numberInput.type = 'number';
            numberInput.className = 'dxb-slider-value';
            numberInput.setAttribute('aria-hidden', 'true');
            numberInput.setAttribute('tabindex', '-1');
            numberInput.value = value;
            numberInput.min = min;
            numberInput.max = max;
            container.appendChild(numberInput);

            function updateValue() {
                const val = slider.value;
                const percent = ((val - min) / (max - min)) * 100;
                slider.style.setProperty('--value-percent', `${percent}%`);
                numberInput.value = val;
                slider.setAttribute('aria-valuenow', val);
            }

            slider.addEventListener('input', updateValue);
            numberInput.addEventListener('input', () => {
                slider.value = numberInput.value;
                updateValue();
            });

            // Set initial ARIA attributes
            slider.setAttribute('aria-valuemin', min);
            slider.setAttribute('aria-valuemax', max);

            // Initial update
            updateValue();
        });
    };
}(jQuery));

Patch

diff --git a/dxb-slider.js b/dxb-slider.js
index d3d3947..67f6acd 100644
--- a/dxb-slider.js
+++ b/dxb-slider.js
@@ -1,43 +1,63 @@
 // dxb-slider.js

-(function() {
-  function initDXBSliders() {
-      document.querySelectorAll('[data-dxb-slider]').forEach(rangeInput => {
-          const container = rangeInput.closest('.dxb-slider-wrapper');
-          
-          // Create number input programmatically
-          const numberInput = document.createElement('input');
-          numberInput.type = 'number';
-          numberInput.className = 'dxb-slider-value';
-          numberInput.setAttribute('aria-hidden', 'true');
-          numberInput.setAttribute('tabindex', '-1');
-          container.appendChild(numberInput);
-
-          function updateValue() {
-              const val = rangeInput.value;
-              const min = rangeInput.min;
-              const max = rangeInput.max;
-              const percent = (val - min) / (max - min) * 100;
-              rangeInput.style.setProperty('--value-percent', `${percent}%`);
-              numberInput.value = val;
-              numberInput.min = min;
-              numberInput.max = max;
-              rangeInput.setAttribute('aria-valuenow', val);
-          }
-
-          rangeInput.addEventListener('input', updateValue);
-          numberInput.addEventListener('input', () => {
-              rangeInput.value = numberInput.value;
-              updateValue();
-          });
-
-          // Set initial ARIA attributes
-          rangeInput.setAttribute('aria-valuemin', rangeInput.min);
-          rangeInput.setAttribute('aria-valuemax', rangeInput.max);
-
-          updateValue();
-      });
-  }
-
-  initDXBSliders();
-})();
\ No newline at end of file
+(function ($) {
+    $.fn.DXBSlider = function (options) {
+        // Set default options if none are provided
+        const settings = $.extend({
+            min: 0,
+            max: 100,
+            step: 1,
+            value: ''
+        }, options);
+
+        // Iterate over each selected element
+        return this.each(function () {
+            const slider = this;
+            const min = parseFloat(settings.min);
+            const max = parseFloat(settings.max);
+            const step = parseFloat(settings.step);
+            const value = settings.value === "" || isNaN(parseFloat(settings.value)) || settings.value === "NaN"
+                ? min
+                : parseFloat(settings.value);
+
+            // Set initial attributes
+            slider.setAttribute('min', min);
+            slider.setAttribute('max', max);
+            slider.setAttribute('step', step);
+            slider.value = value;
+
+            // Create number input programmatically
+            const container = slider.closest('.dxb-slider-wrapper');
+            const numberInput = document.createElement('input');
+            numberInput.type = 'number';
+            numberInput.className = 'dxb-slider-value';
+            numberInput.setAttribute('aria-hidden', 'true');
+            numberInput.setAttribute('tabindex', '-1');
+            numberInput.value = value;
+            numberInput.min = min;
+            numberInput.max = max;
+            container.appendChild(numberInput);
+
+            function updateValue() {
+                const val = slider.value;
+                const percent = ((val - min) / (max - min)) * 100;
+                slider.style.setProperty('--value-percent', `${percent}%`);
+                numberInput.value = val;
+                slider.setAttribute('aria-valuenow', val);
+            }
+
+            slider.addEventListener('input', updateValue);
+            numberInput.addEventListener('input', () => {
+                slider.value = numberInput.value;
+                updateValue();
+            });
+
+            // Set initial ARIA attributes
+            slider.setAttribute('aria-valuemin', min);
+            slider.setAttribute('aria-valuemax', max);
+
+            // Initial update
+            updateValue();
+        });
+    };
+}(jQuery));
jjroelofs commented 1 month ago

Thank you for your suggestion, for integration I refer you to the README where you'll learn that integration is very simple, all that is required is a range input coupled with optional data attributes for min, max, and step parameters.

jQuery is very old and nobody should be creating new projects with it. The reason we created this new slider plugin is Drupal's adoption of jQuery 4 which deprecates many jQuery features, so we will not add a jQuery plugin wrapper.