フォームの二重投稿防止

以下のようなものを書いてみた*1。ボタンのdisabledはなくてもいいかな。

{
  (function(){
    var observeForms = function(){
      var forms = document.forms;
      for(var i=0; i<forms.length; i++){
        var form = forms[i];
        var disable = function(){
          form.onsubmit = function(){
            return false;
          }
          return true;
        }
        form.onsubmit = disable;
      }
    }
    Event.observe(window, "load", observeForms, false);
  })();
}

数秒後には送信可能にする

通信が切断されたときなどにformが送信できないままだと問題があるという意見を見かけた*2。setTimeoutで5秒後に再送信可能にしてみた。

{
  (function(){
    var observeForms = function(){
      var forms = document.forms;
      for(var i=0; i<forms.length; i++){
        var form = forms[i];
        var enable = function(){
          form.onsubmit = function(){
            return true;
          }
        }
        var disable = function(){
          form.onsubmit = function(){
            return false;
          }
          setTimeout(enable, 5000);
          return true;
        }
        form.onsubmit = disable;
      }
    }
    Event.observe(window, "load", observeForms, false);
  })();
}

一緒にボタンの無効化を行う

こんな感じかな。

{
  (function(){
    var observeForms = function(){
      var forms = document.forms;
      for(var i=0; i<forms.length; i++){
        var form = forms[i];
        var enableButtons = function(){
          for(j=0; j<form.elements.length; j++){
            if(
              ( form.elements[j].tagName.toUpperCase() == "INPUT" || form.elements[j].tagName.toUpperCase() == "BUTTON" )
              && form.elements[j].type.toUpperCase() == "SUBMIT"
            ){
              form.elements[j].removeAttribute("disabled");
            }
          }
        }
        var disableButtons = function(){//修正 2008-04-03. Thanks to suezo!
          for(j=0; j<form.elements.length; j++){
            if(
              ( form.elements[j].tagName.toUpperCase() == "INPUT" || form.elements[j].tagName.toUpperCase() == "BUTTON" )
              && form.elements[j].type.toUpperCase() == "SUBMIT"
            ){
              form.elements[j].setAttribute("disabled", "disabled");
            }
          }
        }
        var enable = function(){
          form.onsubmit = disable;//修正(追記2) 2008-04-14
          enableButtons();
        }
        var disable = function(){
          form.onsubmit = function(){
            return false;
          }
          setTimeout(disableButtons, 10);//修正(追記1) 2008-04-14
          setTimeout(enable, 5000);
          return true;
        }
        form.onsubmit = disable;
      }
    }
    Event.observe(window, "load", observeForms, false);
  })();
}

form.onsubmitにすでに何か処理を行っている場合はこれだとまずい…。

(追記1)Submitのボタンの値が来ることを期待している場合

上記の書き方だと

        var disable = function(){
          form.onsubmit = function(){
            return false;
          }
          disableButtons(form);
          setTimeout(enable, 5000);
          return true;
        }
        form.onsubmit = disable;

というように、フォームがsubmitされる前にdisableButtons()を呼んでいるので、フォームがsubmitされるときにはすでにsubmitのボタンが無効になっていてその値はサーバに渡されない。
下記のように変更すれば、フォームがsubmitされてからボタンを無効化するのでボタンの値もサーバに渡される。

        var disable = function(){
          form.onsubmit = function(){
            return false;
          }
          setTimeout(disableButtons, 10);
          setTimeout(enable, 5000);
          return true;
        }
        form.onsubmit = disable;

と書いて気が付いたけどdisableButtons()にformという引数を渡す必要ないじゃん!元の記事のソースは修正しておいた。
変更内容も元のソースに反映させた。

(追記2)再び押せるようになったボタンも二度押しできないようにする

これだと5秒経過するなどして再び押せるようになったボタンは二度押しできてしまうので、これも二度押しできないようにした方が自然だと思う。

        var enable = function(){
          form.onsubmit = function(){
            return true;
          }
          enableButtons();
        }

ではなくて、

        var enable = function(){
          form.onsubmit = disable;
          enableButtons();
        }

とする。
上のソースには反映させてある。