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

19年9月21日(Sat) 8時36分
TOP » UsersWiki » nao-pon » blog » 2015-04-03

RSS of nao-pon/blog
Fri 3 Apr 2015
 

[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 での一括処理で送信エラーになっていました。


Comments list

Posts tree

Topic


nao-pon  Posted on 2015-4-4 0:35

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

nao-pon  Posted on 2015-5-11 20:48

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

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



Post a new comment

Subject
guestname
Body

Go to richer form

Front page   Freeze Diff Backup Copy Rename ReloadPrint View   New Page Page list Search Recent changes   Help   RSS of recent changes (RSS 1.0) RSS of recent changes (RSS 2.0) RSS of recent changes (RSS Atom) Powered by xpWiki
Counter: 2770, today: 1, yesterday: 0
Princeps date: 2015-04-03 (Fri) 21:03:10
Last-modified: 2015-05-18 (Mon) 20:31:08 (JST) (1586d) by nao-pon
このページのTopへ
ログイン
ユーザ名:

パスワード:

オートログイン

Basic 認証

Register now! | Lost Password?



メインメニュー
UsersWiki メニュー
付箋メニュー
Fusen(Tag) menu 
Tag Editor
Color: BG:
Name:  Connect line ID:
 
ブックマーク
Please log in to use it.
[Login]
サイト内 Wiki
☆ 検索 ☆



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

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

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

nao-pon
 

登録ユーザ数: 4614


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