hypweb.net
XOOPSマニア  最新情報のRSS(サイト全体)
[ 自宅サーバーWebRing |ID=54 前後5表示乱移動サイト一覧 ]

19年2月23日(Sat) 2時40分
TOP » UsersWiki » nao-pon » blog » 2015-04-03

RSS of nao-pon/blog
2015 4月 3 (金)
 

[jQuery] Web ページのフォーム投稿時問題のあれこれを上手いことするやつ anchor.png

長文の投稿を書いている時に、間違ってブラウザ閉じてしまったり、ページ移動してしまったり、送信したらサーバーとの接続が切れてしまった!

OH MY GOD!

会心の出来だ!と喜んだのも束の間、奈落の底に突き落とされるような思いをすることが、たまにありますよね。

このような事態にみまわれると、投稿分の出来がよければよいほど、立ち直るのにしばらく時間が掛かってしまいます。

そんな、思いをしないため、させないために、ちょっとゴリゴリ jQuery で書いてみました。

Textarea復原ボタン.png

移動してもいい?.png
テキストエリアに入力中にページ移動しようとしたりしてページが閉じられる前にブラウザが閉じていいのかを聞いてくれます。
さらに、万が一閉じてしまったり送信時にサーバーと接続できなかったりした時でも、次に開いた時にテキストエリアの下に「復元」ボタンが表示されるので、それをクリックすれば、ほらっ元通り!

<script type="text/javascript" charset="utf-8" src="hyp_form_rescue.js"></script>

などと、UTF-8 指定で <head> 内の jQuery を読み込んだ後に置くだけで OK です。 :ok:

filehyp_form_rescue.js
Everything is expanded.Everything is shortened.
  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
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
-
|
|
|
|
|
!
-
|
-
-
|
|
!
!
-
-
-
-
|
!
!
!
|
|
|
!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
!
|
|
-
|
!
-
|
!
|
|
-
|
|
-
|
|
|
!
|
|
!
-
|
!
-
|
!
-
|
|
-
|
|
|
|
-
-
|
!
!
-
|
|
-
|
|
!
|
!
-
|
|
!
|
|
-
|
|
|
-
|
-
-
|
|
|
|
!
-
-
|
|
|
!
!
!
|
|
|
|
-
-
|
|
!
!
-
-
-
|
|
!
!
!
!
!
!
-
!
-
-
|
|
-
|
-
|
|
|
!
!
!
|
!
!
/*!
 * Web ページのフォーム投稿時問題のあれこれを上手いことするやつ
 * 
 * Copyright (c) 2015 Naoki Sawada hypweb.net
 * Released under the MIT license
 * http://opensource.org/licenses/mit-license.php
 */
jQuery(function($){
    /** 二重投稿防止用 **/
    $('form:not([target])').each(function(){
        if (this.onsubmit) {
            $(this).data('hyp_onsubmit', this.onsubmit.bind(this));
            this.onsubmit = null;
        }
    });
    $(window).on('submit', 'form:not([target])', function(e){
        if ($(this).data('hyp_onsubmit')) {
            try {
                if (!$(this).data('hyp_onsubmit')()) {
                    return false;
                }
            } catch(e){}
        }
        var btn = $(this).find('input[type="submit"]');
        setTimeout(function(){btn.prop('disabled', true)},100);
        setTimeout(function(){btn.prop('disabled', false);},20000);
    });
 
    /** 入力途中のページ移動防止とテキストエリアに「復元」ボタン追加 **/
    var
    /* ページを閉じるときのアラートメッセージ(Firefox は指定メッセージは表示されない) */
    msg   = 'テキストエリアに入力中のデータがあります。\n\n※ 次回、同様のページを開いた時にテキストエリアの内容は[復元]ボタンで復元できます。',
    /* ボタンテキスト */
    btnTx = '復元',
    /* ボタンの title 属性値 */
    btnTi = '最後に入力したデータを復元します。\nテキストエリアが未入力の場合に利用できます。'
    /* ボタン CSS クラス */
    btnCl = 'hypRescueBtn',
    /* 自動保存(秒): 初回2分後、その後30秒毎 (及びページ移動時) */
    autoS = [120000, 30000],
    /* textarea 入力中フラグ */
    flgC  = 'hyp-changed',
    /* localStorage の保存キー */
    dataK = 'hyp-textarea-rescue',
    /* CSS */
    css   = (function () {/*
form div.hypRescueBtn {
	float: right;
	width: auto;
	font-size: 11px;
	margin-top: 2px;
	margin-right: 1px;
	padding: 1px 5px;
	border: 1px solid gray;
	-moz-border-radius: 4px;
	-webkit-border-radius: 4px;
	border-radius: 4px;
	cursor: pointer;
	background: #fcfff4;
	background: -moz-linear-gradient(top,  #fcfff4 27%, #dfe5d7 93%, #b3bead 100%);
	background: -webkit-gradient(linear, left top, left bottom, color-stop(27%,#fcfff4), color-stop(93%,#dfe5d7), color-stop(100%,#b3bead));
	background: -webkit-linear-gradient(top,  #fcfff4 27%,#dfe5d7 93%,#b3bead 100%);
	background: -o-linear-gradient(top,  #fcfff4 27%,#dfe5d7 93%,#b3bead 100%);
	background: -ms-linear-gradient(top,  #fcfff4 27%,#dfe5d7 93%,#b3bead 100%);
	background: linear-gradient(to bottom,  #fcfff4 27%,#dfe5d7 93%,#b3bead 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fcfff4', endColorstr='#b3bead',GradientType=0 );
}
form div.hypRescueBtn:hover {
	padding: 0px 4px;
	border: 2px solid orange;
	border-top-color: gold;
	border-left-color: gold;
}
form div.hypRescueBtn.disabled {
	color: #aaa;
	cursor: default;
}
form div.hypRescueBtn.disabled:hover {
	border: 1px solid #808080;
	padding: 1px 5px;
}
*/}).toString().match(/\/\*([^]*)\*\//)[1];
 
    var htr = {},
    isEmpty = function(val) {
        return val.match(/^\s*$/);
    }
    try{
        htr = JSON.parse(localStorage.getItem(dataK));
    }catch(e){}
    if (!htr || typeof htr != 'object') htr = {};
    $('<style>').append(css).appendTo($('head')[0]);
    $(window).on('beforeunload', function(){
        if (typeof localStorage == 'undefined') return;
        var ret;
        $('form textarea').each(function(){
            var tArea = $(this);
            if (tArea.data(flgC) && !isEmpty(tArea.val())) ret = true;
            if (!isEmpty(tArea.val())) htr[this.name] = tArea.val();
        });
        localStorage.setItem(dataK, JSON.stringify(htr));
        if (ret) return msg;
    });
    $('body').on('change', 'form textarea', function(){
        $(this).val() && $(this).data(flgC, true);
    });
    $('body').on('submit', 'form', function(){
        $(this).find('textarea').data(flgC, false);
    });
    $('body').one('focus', 'textarea', function(){
        var tArea = $(this),
            flg   = 'hyp_rescue';
        if (!tArea.data(flg)) {
            var res,cur,ck,
            ckArea = $('#cke_' + tArea.attr('id'))[0],
            name = this.name,
            bef  = null,
            tgl  = function(on){
                if (res) {
                    on? res.removeClass('disabled') : res.addClass('disabled');
                }
            },
            save = function(){
                ck = ckArea? CKEDITOR.instances[tArea.attr('id')] : null;
                ck && tArea.val(ck.getData());
                if (!isEmpty(tArea.val())) {
                    htr[name] = tArea.val();
                    localStorage.setItem(dataK, JSON.stringify(htr));
                }
                setTimeout(save, autoS[1]);
            };
            if (ckArea || typeof CKEDITOR == 'object') {
                ckArea = $(ckArea);
                ck = CKEDITOR.instances[tArea.attr('id')];
            }
            tArea.data(flg, true).change();
            setTimeout(save, autoS[1]);
            if (htr[name]) {
                res = $('<div>')
                .addClass(btnCl)
                .attr('title', btnTi)
                .on('click', function(){
                    ck = ckArea? CKEDITOR.instances[tArea.attr('id')] : null;
                    if (ck) {
                        if (isEmpty(ck.getData())) {
                            (tArea.data('editor') == 'html')? ck.insertHtml(htr[name]) : ck.insertText(htr[name]);
                            tArea.data(flgC, true);
                            ck.focus();
                            tgl(false);
                        }
                    } else {
                        if (isEmpty(tArea.val())) {
                            tArea.val(htr[name]).data(flgC, true);
                            tArea.focus();
                            tgl(false);
                        }
                    }
                })
                .append(btnTx)
                .insertAfter(ckArea|| tArea);
                if (!(bef = isEmpty(tArea.val()))) res.addClass('disabled');
                res.fadeIn(750).fadeOut(250).fadeIn(750);
                tArea.on('keyup change', function(){
                    if (bef !== (cur = isEmpty(tArea.val()))) {
                        bef = cur;
                        tgl(bef);
                    }
                });
                if (ck) {
                    (tArea.data('ckon') || ck.on)('change', function(){
                        if (bef !== (cur = isEmpty(ck.getData()))) {
                            bef = cur;
                            tgl(bef);
                        }
                    });
                }
            }
        }
    });
    // for Ajax post
    var oldSend = XMLHttpRequest.prototype.send;
    XMLHttpRequest.prototype.send = function(){
        if (arguments[0] && arguments[0].split) {
            var q = arguments[0].split('&'),
            i = 0, t;
            for(i; i < q.length; i ++) {
                t = q[i].split('=');
                $('form textarea[name=\''+t[0]+'\']').each(function(){
                    var tArea = $(this);
                    tArea.data(flgC, false);
                    if (!isEmpty(tArea.val())) htr[t[0]] = tArea.val();
                });
            }
        }
        oldSend.apply(this, arguments);
    };
});
Page Top

更新履歴 anchor.png

  • 2015-04-03 初版
  • 2015-04-04 Ajax 送信に対応
  • 2015-05-11 ckeditor4 モジュール 0.61 以上との組み合わせで CKEditor での投稿フォームに対応
  • 2015-05-11 onsubmit 属性が指定された <FORM> で submit がキャンセルされた場合にフォームボタンが一定時間押せなくなって困ってしまう :hammer: 問題を修正
  • 2015-05-12 CKEditor で編集中でも定期的な自動保存に対応
  • 2015-05-18 Ajax 通信時に不具合がでることがある問題を修正
    • 具体的には、name 属性に英数文字以外の文字が含まれる場合に正常に送信できていませんでした。XOOPS X だと、X-update での一括処理で送信エラーになっていました。


コメント一覧

投稿ツリー

トピック


nao-pon  投稿日時 2015-4-4 0:35

Ajax でのフォーム送信に対応していなかったので、対応して hyp_form_rescue.js を差し替えました。 :-)

nao-pon  投稿日時 2015-5-11 20:48

復元ボタン on ckeditor.pngckeditor4 version 0.61 以上との組み合わせで、 CKEditor でも「復元」ボタンを利用できるようにバージョンアップしました。

元記事のファイルを差し替えてあります。 ;-)



新しくコメントをつける

題名
ゲスト名
投稿本文

より詳細なコメント入力フォームへ

トップ   凍結 差分 バックアップ 複製 名前変更 リロード印刷に適した表示   ページ新規作成 全ページ一覧 単語検索 最新ページの一覧   ヘルプ   最新ページのRSS 1.0 最新ページのRSS 2.0 最新ページのRSS Atom Powered by xpWiki
Counter: 2465, today: 1, yesterday: 0
初版日時: 2015-04-03 (金) 21:03:10
最終更新: 2015-05-18 (月) 20:31:08 (JST) (1376d) by nao-pon
このページのTopへ
ログイン
ユーザ名:

パスワード:

オートログイン

Basic 認証

新規登録 | パスワード紛失



メインメニュー
UsersWiki メニュー
付箋メニュー
付箋メニュー 
付箋の編集
文字色: 背景色:
お名前:  線接続id:
 
ブックマーク
オンサイトブックマークは
ログインするとご利用になれます
[ログインする]
サイト内 Wiki
☆ 検索 ☆



高度な検索(サイト内)
FireFox検索プラグイン
オンライン状況
合計 58 人がオンライン中 :-)
(UsersWiki : 9 人)

登録ユーザ: 0 & ゲスト: 58

もっと...
サイト情報
管理人

nao-pon
 

登録ユーザ数: 4598


Web Services by Yahoo! JAPAN
楽天ウェブサービスセンター
Amazon.co.jpアソシエイト
現在ページのQRコード
現在ページのQRコード
[携帯対応]
参照元情報