Blog-Archiv

Donnerstag, 1. Dezember 2022

Prevent Double Submit on Chrome via JavaScript

Here is the continuation of my article about the browser-specific double submit problem.

Add following JavaScript to the bottom of the web page, right before the closing </body> tag:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    <script>
    /**
     * Some browsers seem to launch two submit-requests on fast double click!
     * Calling this install-procedure will disable a clicked button after click,
     * this prevents any further click.
     * @param form optional, disable only submit-buttons of this form.
     *         When undefined or null, all submit-buttons of all forms in page will be disabled
     *         on submit of their form.
     * @param button optional, disable only this button. Requires a form.
     *         When undefined or null, all submit-buttons of all forms in page will be disabled
     *         on submit of their form.
     * @param installResetTimeout optional, when true,
     *         the button will be enabled again after 1 second.
     */
    function installDoubleSubmitPrevention(form, button, installResetTimeout) {
        function setButtonDisabled(btn) {
            btn.disabled = true;
            if (installResetTimeout) /* false for undefined and null */
                setTimeout(
                    () => btn.disabled = false,
                    1000
                );
        }
   
        function setFormButtonsDisabled(frm) {
            frm.querySelectorAll("input[type='submit']").forEach(
                (btn) => setButtonDisabled(btn)
            );
        }
   
        function installDoubleSubmitPreventionOnForm(frm) {
            frm.addEventListener("submit", () => setFormButtonsDisabled(frm));
        }
   
        if (form && button) {
            form.addEventListener("submit", () => setButtonDisabled(button));
        }
        else if (form) {
            installDoubleSubmitPreventionOnForm(form);
        }
        else {
            document.querySelectorAll("form").forEach(
                (frm) => installDoubleSubmitPreventionOnForm(frm)
            );
        }
    }
    
    installDoubleSubmitPrevention();
    
    </script>

On line 15, the definition of the install-function starts, which is then called on line 48. I call it without parameters, because that would manage all submit buttons in all forms by default. The documentation between line 2 and 14 tells you what you need to know about optional parameters.

Better would be to put the installDoubleSubmitPrevention function definition into a file js/preventDoubleSubmit.js and load it via a <script src="js/preventDoubleSubmit.js"></script> tag, so that you can reuse the function in many pages. In that case you would have to call installDoubleSubmitPrevention() explicitly in a second <script> tag. (For some reason you cannot put JS code into a tag that loads JS from a file!)

The install-function makes heavy use of the ES-6 lambda feature ("arrow-function"), to be seen on line 20, 27, 32, 36, 43, and thus may look short and simple, but is a little hard to read.

The setButtonDisabled function on line 16 sets the given button disabled, and optionally enables it after one second again, to be used in case the submit doesn't load a new page. (The timeout would be dismissed by the browser in case the submit loads a new page.)

The setFormButtonsDisabled function on line 25 calls the setButtonDisabled function for all submit-buttons of a given form.

The installDoubleSubmitPreventionOnForm function on line 31 installs the button-disabling on all submit-buttons of a given form.

All these nested functions exist to not duplicate code.

The install-logic starts on line 35, where the parameters are tested for existence, and according actions are taken. So you can call this function without arguments, or with a form, or with just a single button of a form. If you use the third parameter installResetTimeout and set it to true, a timeout that re-enables the button after 1 second would be installed. This can help when special treatments of the submit event were implemented on the page.
So, if you want to install the timeout on all buttons of all forms, call the function like this:

    installDoubleSubmitPrevention(undefined, undefined, true);



Ubuntu 22.04 LINUX Boots Very Slowly

Every two years Ubuntu releases a major ugrade. This year I got an incredibly slow Ubuntu 22.04 on my DELL laptop.

No one seems to be aware that MS-WINDOWS meanwhile boots incredibly fast and outperforms Ubuntu by far. See also my Blog about Ubuntu 20.04 ugrade.


First, I saw a line like this one on my boot console:

Dependency failed for SSSD SSH Service responder socket

You can view such messages after boot by entering

grep -i "Depend" /var/log/syslog

SSSD (System Security Service Daemon) seems to be not needed for isolated computer installations, and anyway, if it fails starting, I should disable it:

sudo systemctl stop sssd
sudo systemctl disable sssd


Displaying boot time consumptions is provided by systemd-analyze:

systemd-analyze blame

Output was:

41.472s plocate-updatedb.service
23.363s snapd.service
21.246s networkd-dispatcher.service
20.560s apport-autoreport.service
17.905s udisks2.service
14.792s ModemManager.service
14.678s systemd-journal-flush.service
13.575s NetworkManager-wait-online.service
13.446s accounts-daemon.service
 9.811s dev-sda8.device
 8.168s power-profiles-daemon.service
 7.840s polkit.service
 7.775s avahi-daemon.service
 7.772s NetworkManager.service
 6.895s switcheroo-control.service
 6.885s thermald.service
 6.883s systemd-logind.service
 6.750s dev-loop6.device
 .....
This command prints a list of all running units, ordered by the time they took to initialize. This information may be used to optimize boot-up times. Note that the output might be misleading as the initialization of one service might be slow simply because it waits for the initialization of another service to complete. ....
This command hence gives an impression of the performance of program code, but cannot accurately reflect latency introduced by waiting for hardware and similar events.

Unfortunately snapd.service is needed, Firefox is now a snap-application in Ubuntu 22.04. I could get rid of all snap-apps on Ubuntu 20.04, but now I have to consume it. Snap is a LINUX deployment system, similar to Docker, a snap-bundle contains all its library dependencies (trying to circumvent dependency hell in times of TeraByte disks). There is also a Snap Store on the internet.

I disabled some services that took a lot of time, or created error messages and seemed to be not needed:

sudo systemctl stop plocate-updatedb.service
sudo systemctl disable plocate-updatedb.service

sudo systemctl stop apport-autoreport.service
sudo systemctl disable apport-autoreport.service

sudo systemctl stop NetworkManager-wait-online.service
sudo systemctl mask NetworkManager-wait-online.service

sudo systemctl stop networkd-dispatcher.service
sudo systemctl disable networkd-dispatcher.service

# created errors
sudo systemctl disable ureadahead.service
sudo systemctl mask ureadahead.service

The plocate-updatedb.service took the most time. It indexes hard disk files and provides a very fast plocate command. I don't use that command and very rarely search my whole disk.

The apport-autoreport.service reports system failures to the outer world.

The NetworkManager-wait-online.service is important only when you are in a network with other computers.

The networkd-dispatcher.service is needed on computers that drive VPN or are network administrator machines.

These commands would enable a service again:

sudo systemctl enable networkd-dispatcher.service
sudo systemctl start networkd-dispatcher.service

sudo systemctl unmask NetworkManager-wait-online.service
sudo systemctl enable NetworkManager-wait-online.service


Back from booting I encountered it was not faster, but did not crash, and network is alright. In that case I will have to wait for an Ubuntu ugrade that hopefully will fix this slow boot. It is the graphical user-interface that takes a long time to build up. Lots of long and complex discussions of this issue on the web.