Skip to content

Commit

Permalink
Merge pull request #144 from istvan-ujjmeszaros/handle-disabled-input
Browse files Browse the repository at this point in the history
Handle disabled and readonly input
  • Loading branch information
istvan-ujjmeszaros authored Apr 3, 2023
2 parents 15fb083 + 1035f85 commit 5929e26
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 27 deletions.
47 changes: 46 additions & 1 deletion __tests__/basicOperations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});


});
2 changes: 1 addition & 1 deletion __tests__/events.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
30 changes: 18 additions & 12 deletions __tests__/helpers/touchspinHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
import { Page } from 'puppeteer';
import {Page, ElementHandle} from 'puppeteer';

async function waitForTimeout(ms: number): Promise<void> {
return new Promise(r => setTimeout(r, ms));
}

async function readValue(page: Page, selector: string): Promise<string|undefined> {
async function readInputValue(page: Page, selector: string): Promise<string|undefined> {
const input = await page.$(selector);
return await input?.evaluate((el) => (el as HTMLInputElement).value);
}

async function touchspinClick(page: Page, selector: string): Promise<void> {
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<void> {
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<boolean> {
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<void> {
Expand All @@ -43,4 +49,4 @@ async function changeEventCounter(page: Page): Promise<number> {
return (eventLogContent?.match(/change\[/g) ?? []).length;
}

export default { waitForTimeout, readValue, touchspinClick, touchspinClickUp, changeEventCounter };
export default { waitForTimeout, readInputValue, setInputAttr, checkTouchspinUpIsDisabled, touchspinClickUp, changeEventCounter };
2 changes: 1 addition & 1 deletion dist/jquery.bootstrap-touchspin.css
Original file line number Diff line number Diff line change
@@ -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/
*
Expand Down
32 changes: 27 additions & 5 deletions dist/jquery.bootstrap-touchspin.js
Original file line number Diff line number Diff line change
@@ -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/
*
Expand Down Expand Up @@ -135,6 +135,7 @@
_buildHtml();
_initElements();
_hideEmptyPrefixPostfix();
_setupMutationObservers();
_bindEvents();
_bindEventsInterface();
}
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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();

Expand Down
4 changes: 2 additions & 2 deletions dist/jquery.bootstrap-touchspin.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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": [
Expand Down
30 changes: 26 additions & 4 deletions src/jquery.bootstrap-touchspin.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
_buildHtml();
_initElements();
_hideEmptyPrefixPostfix();
_setupMutationObservers();
_bindEvents();
_bindEventsInterface();
}
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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();

Expand Down

0 comments on commit 5929e26

Please sign in to comment.