diff --git a/__tests__/basicOperations.test.ts b/__tests__/basicOperations.test.ts index 06dd9cf..165420e 100644 --- a/__tests__/basicOperations.test.ts +++ b/__tests__/basicOperations.test.ts @@ -17,7 +17,52 @@ describe('Core functionality', () => { // We have to use the mousedown and mouseup events because the plugin is not handling the click event. await touchspinHelpers.touchspinClickUp(page, selector); - expect(await touchspinHelpers.readValue(page, selector)).toBe('51'); + expect(await touchspinHelpers.readInputValue(page, selector)).toBe('51'); }); + it('should not increase value when clicking the + button with a disabled input', async () => { + const selector: string = '#testinput1'; + + await touchspinHelpers.setInputAttr(page, selector, 'disabled', true); + + // We have to use the mousedown and mouseup events because the plugin is not handling the click event. + await touchspinHelpers.touchspinClickUp(page, selector); + + expect(await touchspinHelpers.readInputValue(page, selector)).toBe('50'); + }); + + it('should not increase value when clicking the + button with a readonly input', async () => { + const selector: string = '#testinput1'; + + await touchspinHelpers.setInputAttr(page, selector, 'readonly', true); + + // We have to use the mousedown and mouseup events because the plugin is not handling the click event. + await touchspinHelpers.touchspinClickUp(page, selector); + + expect(await touchspinHelpers.readInputValue(page, selector)).toBe('50'); + }); + + it('setting the input disabled should disable the touchspin buttons', async () => { + const selector: string = '#testinput1'; + + await touchspinHelpers.setInputAttr(page, selector, 'disabled', true); + + // We have to use the mousedown and mouseup events because the plugin is not handling the click event. + await touchspinHelpers.touchspinClickUp(page, selector); + + expect(await touchspinHelpers.checkTouchspinUpIsDisabled(page, selector)).toBe(true); + }); + + it('setting the input readonly should disable the touchspin buttons', async () => { + const selector: string = '#testinput1'; + + await touchspinHelpers.setInputAttr(page, selector, 'readonly', true); + + // We have to use the mousedown and mouseup events because the plugin is not handling the click event. + await touchspinHelpers.touchspinClickUp(page, selector); + + expect(await touchspinHelpers.checkTouchspinUpIsDisabled(page, selector)).toBe(true); + }); + + }); diff --git a/__tests__/events.test.ts b/__tests__/events.test.ts index 25d3dab..404433d 100644 --- a/__tests__/events.test.ts +++ b/__tests__/events.test.ts @@ -9,7 +9,7 @@ describe('Events', () => { // We have to use the mousedown and mouseup events because the plugin is not handling the click event. await touchspinHelpers.touchspinClickUp(page, selector); - expect(await touchspinHelpers.readValue(page, selector)).toBe('51'); + expect(await touchspinHelpers.readInputValue(page, selector)).toBe('51'); }); it('should fire the change event only once when updating the value', async () => { diff --git a/__tests__/helpers/touchspinHelpers.ts b/__tests__/helpers/touchspinHelpers.ts index 3866c4f..9b2ba0c 100644 --- a/__tests__/helpers/touchspinHelpers.ts +++ b/__tests__/helpers/touchspinHelpers.ts @@ -1,25 +1,31 @@ -import { Page } from 'puppeteer'; +import {Page, ElementHandle} from 'puppeteer'; async function waitForTimeout(ms: number): Promise { return new Promise(r => setTimeout(r, ms)); } -async function readValue(page: Page, selector: string): Promise { +async function readInputValue(page: Page, selector: string): Promise { const input = await page.$(selector); return await input?.evaluate((el) => (el as HTMLInputElement).value); } -async function touchspinClick(page: Page, selector: string): Promise { - await page.evaluate((selector) => { - document.querySelector(selector)!.dispatchEvent(new Event('mousedown')); - }, selector); +async function setInputAttr(page: Page, selector: string, attributeName: 'disabled' | 'readonly', attributeValue: boolean): Promise { + const input = await page.$(selector); + await input?.evaluate((el, attributeName, attributeValue) => { + if (attributeValue) { + (el as HTMLInputElement).setAttribute(attributeName, ''); + } else { + (el as HTMLInputElement).removeAttribute(attributeName); + } + }, attributeName, attributeValue); +} - // Delay to allow the value to change. - await new Promise(r => setTimeout(r, 200)); +async function checkTouchspinUpIsDisabled(page: Page, selector: string): Promise { + const input = await page.$(selector + ' + .input-group-btn > .bootstrap-touchspin-up'); - await page.evaluate((selector) => { - document.querySelector(selector)!.dispatchEvent(new Event('mouseup')); - }, selector); + return await input!.evaluate((el) => { + return (el as HTMLInputElement).hasAttribute('disabled'); + }); } async function touchspinClickUp(page: Page, input_selector: string): Promise { @@ -43,4 +49,4 @@ async function changeEventCounter(page: Page): Promise { return (eventLogContent?.match(/change\[/g) ?? []).length; } -export default { waitForTimeout, readValue, touchspinClick, touchspinClickUp, changeEventCounter }; +export default { waitForTimeout, readInputValue, setInputAttr, checkTouchspinUpIsDisabled, touchspinClickUp, changeEventCounter }; diff --git a/dist/jquery.bootstrap-touchspin.css b/dist/jquery.bootstrap-touchspin.css index 6849d68..d446b13 100644 --- a/dist/jquery.bootstrap-touchspin.css +++ b/dist/jquery.bootstrap-touchspin.css @@ -1,5 +1,5 @@ /* - * Bootstrap Touchspin - v4.4.0 + * Bootstrap Touchspin - v4.5.1 * A mobile and touch friendly input spinner component for Bootstrap 3 & 4. * https://www.virtuosoft.eu/code/bootstrap-touchspin/ * diff --git a/dist/jquery.bootstrap-touchspin.js b/dist/jquery.bootstrap-touchspin.js index f4d7ad3..1fa1987 100644 --- a/dist/jquery.bootstrap-touchspin.js +++ b/dist/jquery.bootstrap-touchspin.js @@ -1,5 +1,5 @@ /* - * Bootstrap Touchspin - v4.4.0 + * Bootstrap Touchspin - v4.5.1 * A mobile and touch friendly input spinner component for Bootstrap 3 & 4. * https://www.virtuosoft.eu/code/bootstrap-touchspin/ * @@ -135,6 +135,7 @@ _buildHtml(); _initElements(); _hideEmptyPrefixPostfix(); + _setupMutationObservers(); _bindEvents(); _bindEventsInterface(); } @@ -405,7 +406,7 @@ elements.down.on('mousedown.touchspin', function(ev) { elements.down.off('touchstart.touchspin'); // android 4 workaround - if (originalinput.is(':disabled')) { + if (originalinput.is(':disabled,[readonly]')) { return; } @@ -419,7 +420,7 @@ elements.down.on('touchstart.touchspin', function(ev) { elements.down.off('mousedown.touchspin'); // android 4 workaround - if (originalinput.is(':disabled')) { + if (originalinput.is(':disabled,[readonly]')) { return; } @@ -433,7 +434,7 @@ elements.up.on('mousedown.touchspin', function(ev) { elements.up.off('touchstart.touchspin'); // android 4 workaround - if (originalinput.is(':disabled')) { + if (originalinput.is(':disabled,[readonly]')) { return; } @@ -447,7 +448,7 @@ elements.up.on('touchstart.touchspin', function(ev) { elements.up.off('mousedown.touchspin'); // android 4 workaround - if (originalinput.is(':disabled')) { + if (originalinput.is(':disabled,[readonly]')) { return; } @@ -545,6 +546,21 @@ }); } + function _setupMutationObservers() { + if (typeof MutationObserver !== 'undefined') { + // MutationObserver is available + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.type === 'attributes' && (mutation.attributeName === 'disabled' || mutation.attributeName === 'readonly')) { + updateButtonDisabledState(); + } + }); + }); + + observer.observe(originalinput[0], { attributes: true }); + } + } + function _forcestepdivisibility(value) { switch (settings.forcestepdivisibility) { case 'round': @@ -632,6 +648,12 @@ } } + function updateButtonDisabledState() { + const isDisabled = originalinput.is(':disabled,[readonly]'); + elements.up.prop('disabled', isDisabled); + elements.down.prop('disabled', isDisabled); + } + function upOnce() { _checkValue(); diff --git a/dist/jquery.bootstrap-touchspin.min.js b/dist/jquery.bootstrap-touchspin.min.js index a6bf195..636ba1a 100644 --- a/dist/jquery.bootstrap-touchspin.min.js +++ b/dist/jquery.bootstrap-touchspin.min.js @@ -1,9 +1,9 @@ /* - * Bootstrap Touchspin - v4.4.0 + * Bootstrap Touchspin - v4.5.1 * A mobile and touch friendly input spinner component for Bootstrap 3 & 4. * https://www.virtuosoft.eu/code/bootstrap-touchspin/ * * Made by István Ujj-Mészáros * Under Apache License v2.0 License */ -!function(o){"function"==typeof define&&define.amd?define(["jquery"],o):"object"==typeof module&&module.exports?module.exports=function(t,n){return void 0===n&&(n="undefined"!=typeof window?require("jquery"):require("jquery")(t)),o(n),n}:o(jQuery)}(function(q){"use strict";var S=0;q.fn.TouchSpin=function(M){var P={min:0,max:100,initval:"",replacementval:"",firstclickvalueifempty:null,step:1,decimals:0,stepinterval:100,forcestepdivisibility:"round",stepintervaldelay:500,verticalbuttons:!1,verticalup:"+",verticaldown:"-",verticalupclass:"",verticaldownclass:"",prefix:"",postfix:"",prefix_extraclass:"",postfix_extraclass:"",booster:!0,boostat:10,maxboostedstep:!1,mousewheel:!0,buttondown_class:"btn btn-primary",buttonup_class:"btn btn-primary",buttondown_txt:"-",buttonup_txt:"+",callback_before_calculation:function(t){return t},callback_after_calculation:function(t){return t}},N={min:"min",max:"max",initval:"init-val",replacementval:"replacement-val",firstclickvalueifempty:"first-click-value-if-empty",step:"step",decimals:"decimals",stepinterval:"step-interval",verticalbuttons:"vertical-buttons",verticalupclass:"vertical-up-class",verticaldownclass:"vertical-down-class",forcestepdivisibility:"force-step-divisibility",stepintervaldelay:"step-interval-delay",prefix:"prefix",postfix:"postfix",prefix_extraclass:"prefix-extra-class",postfix_extraclass:"postfix-extra-class",booster:"booster",boostat:"boostat",maxboostedstep:"max-boosted-step",mousewheel:"mouse-wheel",buttondown_class:"button-down-class",buttonup_class:"button-up-class",buttondown_txt:"button-down-txt",buttonup_txt:"button-up-txt"};return this.each(function(){var s,p,a,e,o,t,n,i,u,r,c,l,d,f,b,h=q(this),v=h.data(),x=0,g=!1;function m(){""===s.prefix&&(p=e.prefix.detach()),""===s.postfix&&(a=e.postfix.detach())}function w(){var t,n,o=s.callback_before_calculation(h.val());""===o?""!==s.replacementval&&(h.val(s.replacementval),h.trigger("change")):0s.max&&(n=s.max),parseFloat(o).toString()!==n.toString()&&(h.val(n),h.trigger("change")))}function _(){var t;return s.booster?(t=Math.pow(2,Math.floor(x/s.boostat))*s.step,s.maxboostedstep&&t>s.maxboostedstep&&(t=s.maxboostedstep,o=Math.round(o/t)*t),Math.max(s.step,t)):s.step}function y(){return"number"==typeof s.firstclickvalueifempty?s.firstclickvalueifempty:(s.min+s.max)/2}function k(){w();var t,n=o=parseFloat(s.callback_before_calculation(e.input.val()));isNaN(o)?o=y():(t=_(),o+=t),null!==s.max&&o>s.max&&(o=s.max,h.trigger("touchspin.on.max"),D()),e.input.val(s.callback_after_calculation(parseFloat(o).toFixed(s.decimals))),n!==o&&h.trigger("change")}function C(){w();var t,n=o=parseFloat(s.callback_before_calculation(e.input.val()));isNaN(o)?o=y():(t=_(),o-=t),null!==s.min&&o'+s.prefix+"",f=''+s.postfix+"",b.hasClass("input-group-btn")||b.hasClass("input-group-prepend")?(r='",b.append(r)):(r='",q(r).insertBefore(h)),l.hasClass("input-group-btn")||l.hasClass("input-group-append")?(c='",l.prepend(c)):(c='",q(c).insertAfter(h)),q(d).insertBefore(h),q(f).insertAfter(h),r=v):(b="",h.hasClass("input-sm")&&(b="input-group-sm"),h.hasClass("input-lg")&&(b="input-group-lg"),b=s.verticalbuttons?'
'+s.prefix+''+s.postfix+'
":'
'+s.prefix+''+s.postfix+'
",r=q(b).insertBefore(h),q(".bootstrap-touchspin-prefix",r).after(h),h.hasClass("input-sm")?r.addClass("input-group-sm"):h.hasClass("input-lg")&&r.addClass("input-group-lg")),e={down:q(".bootstrap-touchspin-down",r),up:q(".bootstrap-touchspin-up",r),input:q("input",r),prefix:q(".bootstrap-touchspin-prefix",r).addClass(s.prefix_extraclass),postfix:q(".bootstrap-touchspin-postfix",r).addClass(s.postfix_extraclass)},m(),h.on("keydown.touchspin",function(t){var n=t.keyCode||t.which;38===n?("up"!==g&&(k(),j()),t.preventDefault()):40===n?("down"!==g&&(C(),F()),t.preventDefault()):9!==n&&13!==n||h.val(function(t){switch(s.forcestepdivisibility){case"round":return(Math.round(t/s.step)*s.step).toFixed(s.decimals);case"floor":return(Math.floor(t/s.step)*s.step).toFixed(s.decimals);case"ceil":return(Math.ceil(t/s.step)*s.step).toFixed(s.decimals);default:return t.toFixed(s.decimals)}}(h.val()))}),h.on("keyup.touchspin",function(t){t=t.keyCode||t.which;38!==t&&40!==t||D()}),h.on("blur.touchspin",function(){w(),h.val(s.callback_after_calculation(h.val()))}),e.down.on("keydown",function(t){var n=t.keyCode||t.which;32!==n&&13!==n||("down"!==g&&(C(),F()),t.preventDefault())}),e.down.on("keyup.touchspin",function(t){t=t.keyCode||t.which;32!==t&&13!==t||D()}),e.up.on("keydown.touchspin",function(t){var n=t.keyCode||t.which;32!==n&&13!==n||("up"!==g&&(k(),j()),t.preventDefault())}),e.up.on("keyup.touchspin",function(t){t=t.keyCode||t.which;32!==t&&13!==t||D()}),e.down.on("mousedown.touchspin",function(t){e.down.off("touchstart.touchspin"),h.is(":disabled")||(C(),F(),t.preventDefault(),t.stopPropagation())}),e.down.on("touchstart.touchspin",function(t){e.down.off("mousedown.touchspin"),h.is(":disabled")||(C(),F(),t.preventDefault(),t.stopPropagation())}),e.up.on("mousedown.touchspin",function(t){e.up.off("touchstart.touchspin"),h.is(":disabled")||(k(),j(),t.preventDefault(),t.stopPropagation())}),e.up.on("touchstart.touchspin",function(t){e.up.off("mousedown.touchspin"),h.is(":disabled")||(k(),j(),t.preventDefault(),t.stopPropagation())}),e.up.on("mouseup.touchspin mouseout.touchspin touchleave.touchspin touchend.touchspin touchcancel.touchspin",function(t){g&&(t.stopPropagation(),D())}),e.down.on("mouseup.touchspin mouseout.touchspin touchleave.touchspin touchend.touchspin touchcancel.touchspin",function(t){g&&(t.stopPropagation(),D())}),e.down.on("mousemove.touchspin touchmove.touchspin",function(t){g&&(t.stopPropagation(),t.preventDefault())}),e.up.on("mousemove.touchspin touchmove.touchspin",function(t){g&&(t.stopPropagation(),t.preventDefault())}),h.on("mousewheel.touchspin DOMMouseScroll.touchspin",function(t){var n;s.mousewheel&&h.is(":focus")&&(n=t.originalEvent.wheelDelta||-t.originalEvent.deltaY||-t.originalEvent.detail,t.stopPropagation(),t.preventDefault(),(n<0?C:k)())}),h.on("touchspin.destroy",function(){var t=h.parent();D(),h.off(".touchspin"),t.hasClass("bootstrap-touchspin-injected")?(h.siblings().remove(),h.unwrap()):(q(".bootstrap-touchspin-injected",t).remove(),t.removeClass("bootstrap-touchspin")),h.data("alreadyinitialized",!1)}),h.on("touchspin.uponce",function(){D(),k()}),h.on("touchspin.downonce",function(){D(),C()}),h.on("touchspin.startupspin",function(){j()}),h.on("touchspin.startdownspin",function(){F()}),h.on("touchspin.stopspin",function(){D()}),h.on("touchspin.updatesettings",function(t,n){var o=n;s=q.extend({},s,o),o.postfix&&(0===h.parent().find(".bootstrap-touchspin-postfix").length&&a.insertAfter(h),h.parent().find(".bootstrap-touchspin-postfix .input-group-text").text(o.postfix)),o.prefix&&(0===h.parent().find(".bootstrap-touchspin-prefix").length&&p.insertBefore(h),h.parent().find(".bootstrap-touchspin-prefix .input-group-text").text(o.prefix)),m(),w(),""!==(n=e.input.val())&&(n=parseFloat(s.callback_before_calculation(e.input.val())),e.input.val(s.callback_after_calculation(parseFloat(n).toFixed(s.decimals))))})):console.log("Must be an input."))})}}); \ No newline at end of file +!function(o){"function"==typeof define&&define.amd?define(["jquery"],o):"object"==typeof module&&module.exports?module.exports=function(t,n){return void 0===n&&(n="undefined"!=typeof window?require("jquery"):require("jquery")(t)),o(n),n}:o(jQuery)}(function(q){"use strict";var S=0;q.fn.TouchSpin=function(M){var P={min:0,max:100,initval:"",replacementval:"",firstclickvalueifempty:null,step:1,decimals:0,stepinterval:100,forcestepdivisibility:"round",stepintervaldelay:500,verticalbuttons:!1,verticalup:"+",verticaldown:"-",verticalupclass:"",verticaldownclass:"",prefix:"",postfix:"",prefix_extraclass:"",postfix_extraclass:"",booster:!0,boostat:10,maxboostedstep:!1,mousewheel:!0,buttondown_class:"btn btn-primary",buttonup_class:"btn btn-primary",buttondown_txt:"-",buttonup_txt:"+",callback_before_calculation:function(t){return t},callback_after_calculation:function(t){return t}},N={min:"min",max:"max",initval:"init-val",replacementval:"replacement-val",firstclickvalueifempty:"first-click-value-if-empty",step:"step",decimals:"decimals",stepinterval:"step-interval",verticalbuttons:"vertical-buttons",verticalupclass:"vertical-up-class",verticaldownclass:"vertical-down-class",forcestepdivisibility:"force-step-divisibility",stepintervaldelay:"step-interval-delay",prefix:"prefix",postfix:"postfix",prefix_extraclass:"prefix-extra-class",postfix_extraclass:"postfix-extra-class",booster:"booster",boostat:"boostat",maxboostedstep:"max-boosted-step",mousewheel:"mouse-wheel",buttondown_class:"button-down-class",buttonup_class:"button-up-class",buttondown_txt:"button-down-txt",buttonup_txt:"button-up-txt"};return this.each(function(){var s,a,e,p,o,t,n,i,u,r,c,l,d,f,b,h=q(this),v=h.data(),x=0,g=!1;function m(){""===s.prefix&&(a=p.prefix.detach()),""===s.postfix&&(e=p.postfix.detach())}function w(){var t,n,o=s.callback_before_calculation(h.val());""===o?""!==s.replacementval&&(h.val(s.replacementval),h.trigger("change")):0s.max&&(n=s.max),parseFloat(o).toString()!==n.toString()&&(h.val(n),h.trigger("change")))}function y(){var t;return s.booster?(t=Math.pow(2,Math.floor(x/s.boostat))*s.step,s.maxboostedstep&&t>s.maxboostedstep&&(t=s.maxboostedstep,o=Math.round(o/t)*t),Math.max(s.step,t)):s.step}function _(){return"number"==typeof s.firstclickvalueifempty?s.firstclickvalueifempty:(s.min+s.max)/2}function k(){w();var t,n=o=parseFloat(s.callback_before_calculation(p.input.val()));isNaN(o)?o=_():(t=y(),o+=t),null!==s.max&&o>s.max&&(o=s.max,h.trigger("touchspin.on.max"),D()),p.input.val(s.callback_after_calculation(parseFloat(o).toFixed(s.decimals))),n!==o&&h.trigger("change")}function C(){w();var t,n=o=parseFloat(s.callback_before_calculation(p.input.val()));isNaN(o)?o=_():(t=y(),o-=t),null!==s.min&&o'+s.prefix+"",f=''+s.postfix+"",b.hasClass("input-group-btn")||b.hasClass("input-group-prepend")?(r='",b.append(r)):(r='",q(r).insertBefore(h)),l.hasClass("input-group-btn")||l.hasClass("input-group-append")?(c='",l.prepend(c)):(c='",q(c).insertAfter(h)),q(d).insertBefore(h),q(f).insertAfter(h),r=v):(b="",h.hasClass("input-sm")&&(b="input-group-sm"),h.hasClass("input-lg")&&(b="input-group-lg"),b=s.verticalbuttons?'
'+s.prefix+''+s.postfix+'
":'
'+s.prefix+''+s.postfix+'
",r=q(b).insertBefore(h),q(".bootstrap-touchspin-prefix",r).after(h),h.hasClass("input-sm")?r.addClass("input-group-sm"):h.hasClass("input-lg")&&r.addClass("input-group-lg")),p={down:q(".bootstrap-touchspin-down",r),up:q(".bootstrap-touchspin-up",r),input:q("input",r),prefix:q(".bootstrap-touchspin-prefix",r).addClass(s.prefix_extraclass),postfix:q(".bootstrap-touchspin-postfix",r).addClass(s.postfix_extraclass)},m(),"undefined"!=typeof MutationObserver&&new MutationObserver(t=>{t.forEach(t=>{"attributes"!==t.type||"disabled"!==t.attributeName&&"readonly"!==t.attributeName||(t=h.is(":disabled,[readonly]"),p.up.prop("disabled",t),p.down.prop("disabled",t))})}).observe(h[0],{attributes:!0}),h.on("keydown.touchspin",function(t){var n=t.keyCode||t.which;38===n?("up"!==g&&(k(),j()),t.preventDefault()):40===n?("down"!==g&&(C(),F()),t.preventDefault()):9!==n&&13!==n||h.val(function(t){switch(s.forcestepdivisibility){case"round":return(Math.round(t/s.step)*s.step).toFixed(s.decimals);case"floor":return(Math.floor(t/s.step)*s.step).toFixed(s.decimals);case"ceil":return(Math.ceil(t/s.step)*s.step).toFixed(s.decimals);default:return t.toFixed(s.decimals)}}(h.val()))}),h.on("keyup.touchspin",function(t){t=t.keyCode||t.which;38!==t&&40!==t||D()}),h.on("blur.touchspin",function(){w(),h.val(s.callback_after_calculation(h.val()))}),p.down.on("keydown",function(t){var n=t.keyCode||t.which;32!==n&&13!==n||("down"!==g&&(C(),F()),t.preventDefault())}),p.down.on("keyup.touchspin",function(t){t=t.keyCode||t.which;32!==t&&13!==t||D()}),p.up.on("keydown.touchspin",function(t){var n=t.keyCode||t.which;32!==n&&13!==n||("up"!==g&&(k(),j()),t.preventDefault())}),p.up.on("keyup.touchspin",function(t){t=t.keyCode||t.which;32!==t&&13!==t||D()}),p.down.on("mousedown.touchspin",function(t){p.down.off("touchstart.touchspin"),h.is(":disabled,[readonly]")||(C(),F(),t.preventDefault(),t.stopPropagation())}),p.down.on("touchstart.touchspin",function(t){p.down.off("mousedown.touchspin"),h.is(":disabled,[readonly]")||(C(),F(),t.preventDefault(),t.stopPropagation())}),p.up.on("mousedown.touchspin",function(t){p.up.off("touchstart.touchspin"),h.is(":disabled,[readonly]")||(k(),j(),t.preventDefault(),t.stopPropagation())}),p.up.on("touchstart.touchspin",function(t){p.up.off("mousedown.touchspin"),h.is(":disabled,[readonly]")||(k(),j(),t.preventDefault(),t.stopPropagation())}),p.up.on("mouseup.touchspin mouseout.touchspin touchleave.touchspin touchend.touchspin touchcancel.touchspin",function(t){g&&(t.stopPropagation(),D())}),p.down.on("mouseup.touchspin mouseout.touchspin touchleave.touchspin touchend.touchspin touchcancel.touchspin",function(t){g&&(t.stopPropagation(),D())}),p.down.on("mousemove.touchspin touchmove.touchspin",function(t){g&&(t.stopPropagation(),t.preventDefault())}),p.up.on("mousemove.touchspin touchmove.touchspin",function(t){g&&(t.stopPropagation(),t.preventDefault())}),h.on("mousewheel.touchspin DOMMouseScroll.touchspin",function(t){var n;s.mousewheel&&h.is(":focus")&&(n=t.originalEvent.wheelDelta||-t.originalEvent.deltaY||-t.originalEvent.detail,t.stopPropagation(),t.preventDefault(),(n<0?C:k)())}),h.on("touchspin.destroy",function(){var t=h.parent();D(),h.off(".touchspin"),t.hasClass("bootstrap-touchspin-injected")?(h.siblings().remove(),h.unwrap()):(q(".bootstrap-touchspin-injected",t).remove(),t.removeClass("bootstrap-touchspin")),h.data("alreadyinitialized",!1)}),h.on("touchspin.uponce",function(){D(),k()}),h.on("touchspin.downonce",function(){D(),C()}),h.on("touchspin.startupspin",function(){j()}),h.on("touchspin.startdownspin",function(){F()}),h.on("touchspin.stopspin",function(){D()}),h.on("touchspin.updatesettings",function(t,n){var o=n;s=q.extend({},s,o),o.postfix&&(0===h.parent().find(".bootstrap-touchspin-postfix").length&&e.insertAfter(h),h.parent().find(".bootstrap-touchspin-postfix .input-group-text").text(o.postfix)),o.prefix&&(0===h.parent().find(".bootstrap-touchspin-prefix").length&&a.insertBefore(h),h.parent().find(".bootstrap-touchspin-prefix .input-group-text").text(o.prefix)),m(),w(),""!==(n=p.input.val())&&(n=parseFloat(s.callback_before_calculation(p.input.val())),p.input.val(s.callback_after_calculation(parseFloat(n).toFixed(s.decimals))))})):console.log("Must be an input."))})}}); \ No newline at end of file diff --git a/package.json b/package.json index 6fb6b25..fcecba4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bootstrap-touchspin", - "version": "4.4.0", + "version": "4.5.1", "title": "Bootstrap Touchspin", "description": "A mobile and touch friendly input spinner component for Bootstrap 3 & 4.", "keywords": [ diff --git a/src/jquery.bootstrap-touchspin.js b/src/jquery.bootstrap-touchspin.js index e982f3e..1331ba6 100644 --- a/src/jquery.bootstrap-touchspin.js +++ b/src/jquery.bootstrap-touchspin.js @@ -127,6 +127,7 @@ _buildHtml(); _initElements(); _hideEmptyPrefixPostfix(); + _setupMutationObservers(); _bindEvents(); _bindEventsInterface(); } @@ -397,7 +398,7 @@ elements.down.on('mousedown.touchspin', function(ev) { elements.down.off('touchstart.touchspin'); // android 4 workaround - if (originalinput.is(':disabled')) { + if (originalinput.is(':disabled,[readonly]')) { return; } @@ -411,7 +412,7 @@ elements.down.on('touchstart.touchspin', function(ev) { elements.down.off('mousedown.touchspin'); // android 4 workaround - if (originalinput.is(':disabled')) { + if (originalinput.is(':disabled,[readonly]')) { return; } @@ -425,7 +426,7 @@ elements.up.on('mousedown.touchspin', function(ev) { elements.up.off('touchstart.touchspin'); // android 4 workaround - if (originalinput.is(':disabled')) { + if (originalinput.is(':disabled,[readonly]')) { return; } @@ -439,7 +440,7 @@ elements.up.on('touchstart.touchspin', function(ev) { elements.up.off('mousedown.touchspin'); // android 4 workaround - if (originalinput.is(':disabled')) { + if (originalinput.is(':disabled,[readonly]')) { return; } @@ -537,6 +538,21 @@ }); } + function _setupMutationObservers() { + if (typeof MutationObserver !== 'undefined') { + // MutationObserver is available + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.type === 'attributes' && (mutation.attributeName === 'disabled' || mutation.attributeName === 'readonly')) { + updateButtonDisabledState(); + } + }); + }); + + observer.observe(originalinput[0], { attributes: true }); + } + } + function _forcestepdivisibility(value) { switch (settings.forcestepdivisibility) { case 'round': @@ -624,6 +640,12 @@ } } + function updateButtonDisabledState() { + const isDisabled = originalinput.is(':disabled,[readonly]'); + elements.up.prop('disabled', isDisabled); + elements.down.prop('disabled', isDisabled); + } + function upOnce() { _checkValue();