From 0e2948779bece16ac09f349e44cea55580aa05bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=20Pl=C3=B6tze?= <7642349+andrepxx@users.noreply.github.com> Date: Sun, 25 Mar 2018 14:06:49 +0200 Subject: [PATCH] Fixed several issues with the knob control. 1. Control now gracefully handles empty input, falling back to zero instead of NaN. 2. The control now also handles 'wheel' events instead of only 'mousewheel' and 'DOMMouseScroll' events. Modern browsers use the W3C standard 'wheel' event when reporting scroll wheel events. This also prevents the site from scrolling when the cursor is over a knob and the mouse wheel or track pad scrolling is actuated. Previously, the web site would scroll away under the cursor as the user tried to actuate a knob with the scroll wheel or track pad, since the event was not properly captured. 3. Increased the timeout for detecting mouse wheel stops from 100 ms to a more graceful 250 ms, which often works better. 4. Removed the second timer (mwTimerRelease), since it messes things up. 5. Added more key codes allowed for input, since the original set turned out too restrictive. 6. Removed the speedup on long key presses, since this does not actually cause the increment to speed up, but instantly skips to the end of the range (min/max value) on a long press. --- js/jquery.knob.js | 117 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 35 deletions(-) diff --git a/js/jquery.knob.js b/js/jquery.knob.js index 792313c..e0cfe81 100644 --- a/js/jquery.knob.js +++ b/js/jquery.knob.js @@ -6,6 +6,7 @@ * Requires: jQuery v1.7+ * * Copyright (c) 2012 Anthony Terrien + * Modified 2017 by Andre Plötze * Under MIT License (http://www.opensource.org/licenses/mit-license.php) * * Thanks to vor, eskimoblood, spiffistan, FabrizioC @@ -132,7 +133,15 @@ return v; }, parse: function (v) { - return parseFloat(v); + // --- + // This doesn't work nicely with empty input. + // --- + // + // return parseFloat(v); + + // Handle empty input more gracefully. + var val = parseFloat(v); + return isFinite(val) ? val : 0; } }, this.o ); @@ -315,6 +324,9 @@ this._touch = function (e) { var touchMove = function (e) { + // Prevent page from scrolling on touchpad/-screen input. + e.preventDefault(); + var v = s.xy2val( e.originalEvent.touches[s.t].pageX, e.originalEvent.touches[s.t].pageY @@ -455,8 +467,20 @@ }; this._validate = function (v) { - var val = (~~ (((v < 0) ? -0.5 : 0.5) + (v/this.o.step))) * this.o.step; - return Math.round(val * 100) / 100; + + // --- + // With this, the input cannot be empty, not even temporarily. + // --- + // + // var val = (~~ (((v < 0) ? -0.5 : 0.5) + (v/this.o.step))) * this.o.step; + // return Math.round(val * 100) / 100; + + // Alternate validation method allowing for empty input. + if (isFinite(v)) + return Math.round(v); + else + return v; + }; // Abstract methods @@ -502,7 +526,7 @@ this.lineWidth = null; this.cursorExt = null; this.w2 = null; - this.PI2 = 2*Math.PI; + this.PI2 = 2 * Math.PI; this.extend = function () { this.o = $.extend({ @@ -569,8 +593,11 @@ e.preventDefault(); var ori = e.originalEvent, - deltaX = ori.detail || ori.wheelDeltaX, - deltaY = ori.detail || ori.wheelDeltaY, + // --- + // Handle "wheel" events as well. + // --- + deltaX = ori.deltaX || ori.detail || ori.wheelDeltaX, + deltaY = ori.deltaY || ori.detail || ori.wheelDeltaY, v = s._validate(s.o.parse(s.$.val())) + ( deltaX > 0 || deltaY > 0 @@ -588,17 +615,24 @@ mwTimerStop = setTimeout(function () { s.rH(v); mwTimerStop = null; - }, 100); - - // Handle mousewheel releases - if (!mwTimerRelease) { - mwTimerRelease = setTimeout(function () { - if (mwTimerStop) - s.rH(v); - mwTimerRelease = null; - }, 200); - } + }, 250); // Increased the timeout from 100 to 250 ms. + + // --- + // The second timeout messes things up. + // Don't know why it's here. + // Works better without, so don't do this. + // --- + // + // // Handle mousewheel releases + // if (!mwTimerRelease) { + // mwTimerRelease = setTimeout(function () { + // if (mwTimerStop) + // s.rH(v); + // mwTimerRelease = null; + // }, 200); + // } } + }, kval, to, @@ -624,13 +658,10 @@ kval = parseInt(String.fromCharCode(kc)); if (isNaN(kval)) { - (kc !== 13) // enter - && kc !== 8 // bs - && kc !== 9 // tab - && kc !== 189 // - - && (kc !== 190 - || s.$.val().match(/\./)) // . allowed once - && e.preventDefault(); + + // Enter - Backspace - Tab - Minus Numblock FF - Minus FireFox - Minus - Dot + if ((kc !== 13) && (kc !== 8) && (kc !== 9) && (kc !== 109) && (kc !== 173) && (kc !== 189) && (kc !== 190)) + e.preventDefault(); // arrows if ($.inArray(kc,[37,38,39,40]) > -1) { @@ -642,10 +673,16 @@ s.change(s._validate(v)); s._draw(); - // long time keydown speed-up - to = window.setTimeout(function () { - m *= 2; - }, 30); + // --- + // This causes the value to almost instantly skip to the min/max on a long key press. + // It doesn't speed up, it just skips to the end. + // Works better without, so don't do this. + // --- + // + // // long time keydown speed-up + // to = window.setTimeout(function () { + // m *= 2; + // }, 30); } } } @@ -654,12 +691,18 @@ "keyup", function (e) { if (isNaN(kval)) { - if (to) { - window.clearTimeout(to); - to = null; - m = 1; - s.val(s.$.val()); - } + // --- + // No longer needed, since we removed the corresponding code from the 'keydown' event. + // --- + // + // if (to) { + // window.clearTimeout(to); + // to = null; + // m = 1; + // s.val(s.$.val()); + // } + + s.val(s.$.val()); // Better just validate. } else { // kval postcond (s.$.val() > s.o.max && s.$.val(s.o.max)) @@ -668,8 +711,12 @@ } ); - this.$c.bind("mousewheel DOMMouseScroll", mw); - this.$.bind("mousewheel DOMMouseScroll", mw); + // --- + // Handle "wheel" events as well. + // This prevents the site from scrolling when knob is actuated using mouse wheel in Firefox. + // --- + this.$c.bind("wheel mousewheel DOMMouseScroll", mw); + this.$.bind("wheel mousewheel DOMMouseScroll", mw); }; this.init = function () {