Skip to content

Commit

Permalink
Merge pull request #993 from pkvach/fix/js-prevent-multiple-submit
Browse files Browse the repository at this point in the history
js: isso.js: Disable Postbox submit button on click, enable after response
  • Loading branch information
ix5 authored May 17, 2024
2 parents ca91601 + 27f55e1 commit 6f3874c
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 22 deletions.
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Bugfixes & Improvements
- Change logging to include datetime and loglevel (`#1023`_, ix5)
- Make 'text' field in 'comments' table NOT NULL and handling data migration (`#1019`_, pkvach)
- Python 3.12 support (`#1015`_, ix5)
- Disable Postbox submit button on click, enable after response (`#993`_, pkvach)

.. _#951: https://github.com/posativ/isso/pull/951
.. _#967: https://github.com/posativ/isso/pull/967
Expand All @@ -62,6 +63,7 @@ Bugfixes & Improvements
.. _#1023: https://github.com/isso-comments/isso/pull/1023
.. _#1019: https://github.com/isso-comments/isso/pull/1019
.. _#1015: https://github.com/isso-comments/isso/pull/1015
.. _#993: https://github.com/isso-comments/isso/pull/993

0.13.1.dev0 (2023-02-05)
------------------------
Expand Down
54 changes: 35 additions & 19 deletions isso/js/app/isso.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,34 +92,50 @@ var Postbox = function(parent) {

// submit form, initialize optional fields with `null` and reset form.
// If replied to a comment, remove form completely.
$("[type=submit]", el).on("click", function() {
$("[type=submit]", el).on("click", function(event) {
edit();
if (! el.validate()) {
return;
}

const submitButton = event.target;
submitButton.disabled = true; // Disable the submit button to prevent double posting

var author = $("[name=author]", el).value || null,
email = $("[name=email]", el).value || null,
website = $("[name=website]", el).value || null;

localStorage.setItem("isso-author", JSON.stringify(author));
localStorage.setItem("isso-email", JSON.stringify(email));
localStorage.setItem("isso-website", JSON.stringify(website));

api.create($("#isso-thread").getAttribute("data-isso-id"), {
author: author, email: email, website: website,
text: $(".isso-textarea", el).value,
parent: parent || null,
title: $("#isso-thread").getAttribute("data-title") || null,
notification: $("[name=notification]", el).checked() ? 1 : 0,
}).then(function(comment) {
$(".isso-textarea", el).value = "";
insert({ comment, scrollIntoView: true, offset: 0 });

if (parent !== null) {
el.onsuccess();
}
});
try {
localStorage.setItem("isso-author", JSON.stringify(author));
localStorage.setItem("isso-email", JSON.stringify(email));
localStorage.setItem("isso-website", JSON.stringify(website));

api.create($("#isso-thread").getAttribute("data-isso-id"), {
author: author, email: email, website: website,
text: $(".isso-textarea", el).value,
parent: parent || null,
title: $("#isso-thread").getAttribute("data-title") || null,
notification: $("[name=notification]", el).checked() ? 1 : 0,
}).then(
function(comment) {
$(".isso-textarea", el).value = "";
insert({ comment, scrollIntoView: true, offset: 0 });

if (parent !== null) {
el.onsuccess();
}

submitButton.disabled = false;
},
function(err) {
console.error(err);
submitButton.disabled = false;
}
);
} catch (err) {
console.error(err);
submitButton.disabled = false;
}
});

return el;
Expand Down
1 change: 1 addition & 0 deletions isso/js/tests/integration/highlight-comments.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ test('Linked should be highlighted', async () => {

// Cleanup
// Need to click once to surface "confirm" and then again to confirm
await page.waitForSelector('#isso-1 > .isso-text-wrapper > .isso-comment-footer > .isso-delete');
await expect(page).toClick('#isso-1 > .isso-text-wrapper > .isso-comment-footer > .isso-delete');
await expect(page).toClick('#isso-1 > .isso-text-wrapper > .isso-comment-footer > .isso-delete');
});
46 changes: 45 additions & 1 deletion isso/js/tests/integration/puppet.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ test("should fill Postbox with valid data and receive 201 reply", async () => {
await expect(elm.replace(/<time.*?>/, '<time>'))
.toMatchSnapshot();

await expect(page).not.toMatchElement('.isso-post-action > [type=submit]:disabled');

await page.waitForSelector('#isso-1 > .isso-text-wrapper > .isso-comment-footer > .isso-edit');

// Edit comment
Expand Down Expand Up @@ -243,7 +245,10 @@ test("should execute GET/PUT/POST/DELETE requests correctly", async () => {

await expect(page).toMatchElement(
'#isso-1 .isso-text',
{ text: 'New comment body' },
{
text: 'New comment body',
timeout: 1000,
},
);

// Delete comment via DELETE
Expand All @@ -268,3 +273,42 @@ test("should execute GET/PUT/POST/DELETE requests correctly", async () => {
{ text: 'New comment body' },
);
});

test("Postbox submit button should be disabled on submit click and enabled after response", async () => {
const delay = (duration) => new Promise(resolve => setTimeout(resolve, duration));

await page.setRequestInterception(true);
let createHandler = async (request) => {
if (request.url().startsWith(ISSO_ENDPOINT + '/new')) {
delay(800).then(() => request.abort());
} else {
request.continue();
}
};
await page.on('request', createHandler);

await page.goto(
ISSO_ENDPOINT + '/demo',
{waitUntil: 'load'}
);

// Fill the textarea with the comment
await expect(page).toFill(
'.isso-textarea',
'A comment with *italics* and [a link](http://link.com)'
);

// Click the submit button
const submitButtonSelector = '.isso-post-action > [type=submit]';
await expect(page).toClick(submitButtonSelector);

await page.waitForSelector(submitButtonSelector + ":disabled", {timeout: 1000});
await expect(page).toMatchElement(submitButtonSelector + ":disabled", {timeout: 1000});

await page.waitForSelector(submitButtonSelector + ":enabled", {timeout: 1000});
await expect(page).toMatchElement(submitButtonSelector + ":enabled", {timeout: 1000});

// Disable request interception and remove the request handler
await page.setRequestInterception(false);
await page.off('request', createHandler);
});
Binary file modified isso/js/tests/screenshots/reference/thread.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion isso/js/tests/screenshots/reference/thread.png.hash
Original file line number Diff line number Diff line change
@@ -1 +1 @@
78ea677962d3f80607995d9b88d81df2b7787832023cb7f1d64811829d0fc10a
a10040e07c4285acea4a36d41ee2ff9877b70fd399d908e6eaf7a4dfad100333
4 changes: 3 additions & 1 deletion isso/js/tests/screenshots/screenshots.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,14 @@ test('Screenshot with inserted comment', async () => {
page.waitForResponse(async (response) =>
// response.ok means code of 200-300
response.url().includes('/new') && response.ok(),
{ timout: 500 }
{ timeout: 500 }
),
// Then, click submit button
expect(page).toClick('.isso-post-action > input[type=submit]'),
]);

await page.waitForSelector('.isso-post-action > [type=submit]:enabled');
await page.waitForSelector('#isso-1');
const rendered_comment = await page.$('#isso-1');
await rendered_comment.screenshot({
path: SCREENSHOTS_PATH + '/comment.png'
Expand Down

0 comments on commit 6f3874c

Please sign in to comment.