iframe で Ajax

いろいろ調査中。

XHR で mod_plsql につなげると文字化けを起こす。
おそらくオラクルDBの文字コードが JA16EUC だからだと思われる。

と言うわけで、iframe で Ajax するライブラリを作成中。


all about のこちらの記事

http://allabout.co.jp/internet/javascript/closeup/CU20060115A/index.htm

に大変勉強になるコードがかかれてるが、get オンリー。

取りあえず欲しい機能は、

    • 1) html 上の form を指定したらそれに対応する iframe を非表示で生成。
    • 2) submit はユーザが submitボタンを押したとき
    • 3) iframe内に html がロード後、callback関数が実行される

というもの。

それほど難しくないかなと思ってたらはまった。

例えば jQuery でこう書くと

$j('<iframe></iframe>').appendTo('body').load(
function(){}//callback関数
}

FirefoxIE の場合のみこのタイミングで callback関数が実行されてしまう。(OperaSafariは平気)

で、

setTimeout(function(){上の処理},1)

とかすると、IEは回避できるが Firefoxがだめ。
待ち時間を 100ぐらいにすると平気。

ただ汎用ライブラリにすることを考えると、callback追加メソッドとsendメソッドを1ステートでかけるようにしたいので、sendメソッド内でcallbackのバインド待ち処理とかを入れる必要がでてきてしまう。

嫌なので、事前に iframeのsrcを src="javascript:false"とかにして、callbackをコールする関数内で、

var win=this.contentWindow;
if(!win.document)win.document=this.contentDocument;
if(win.location.href=='javascript:false')return;

こう書けば、IE, Firefox の初回ロード時のコールバックが回避できた


と思ったが、なぜかFirefoxの場合、更新ボタンを押した場合、iframeの作成ルーチンを通ってるのに、win.location.hrefの値が初期化されない。

そのためcallback関数がコールされてしまう。

う〜ん…

しょうがないんで、現時点ではsetTimeout( ,100)でつくるか。。

メモ

MyAjaxFrame

(function($j){

$j.MyAjaxFrame = $j.fn.MyAjaxFrame = $j.MyClass.create({
    opt : {
        cid : 0     
    },
    init: function(){
        if(!this.$j().isOwnNode())return this.$j();
        this.buildFrame();
        return this.$j();
    },
    buildFrame : function(){
        var my=this,frames=[];
        my.$j(my.idx()).idxEach(function(idx,node){
            frame$j = my.newFrame(idx);
            if(my.$j(idx)[0].tagName=='A'||my.$j(idx)[0].tagName=='FORM')
                my.$j(idx).attr('target',frame$j[0].name);
            frames[frames.length]=frame$j[0];
        })
        my.crossBind({
            getter : {
                frame$j : $j(frames)
            },
            method : my.method
        });
        return this;
    },
    newFrame : function(idx){
        var my=this;
        var n$j=my.$j(idx);
        var name='my-ajax-frame_'+MyClass.MyUtil.getUniquDateKey()+'_'+(my.opt.cid++);
        $j('<iframe src="javascript:false" class="my-ajax-frame" name="'+name+'"></iframe>').appendTo('body')
        var frame$j=$j('iframe[name="'+name+'"]');
        return frame$j;
    },
    callbackHandle : function(callback,a$j){
        return function(){
            var win=this.contentWindow;
            if(!win.document)win.document=this.contentDocument;
            if(win.location.href=='javascript:false')return;
            $j('html',win.document).css('border','none');
            (function(frame){
                return function(win){
                    callback.apply(frame,arguments);
                }
            })(a$j.frame$j(this))(win)
        };
    },
    method : {
        callback : function(callback){
            var my=this.my();
            var a$j=this.active$j()
            a$j.myData('callback',callback);
            var frame$j=a$j.frame$j(this.idx());
            frame$j.each(function(idx){
                this.callbackReady=0
                if(this.callbackHandle)frame$j(idx).unbind('load',this.callbackHandle)
            });
            setTimeout(function(){
                var callbackHandle = my.callbackHandle(callback,a$j);
                frame$j.bind('load',callbackHandle)
                .each(function(){this.callbackReady=1,this.callbackHandle=callbackHandle})
            },100)
            return this;
        },
        url : function(url){
            a$j=this.active$j();
            a$j.myData('url',url);
            a$j.idxEach(function(idx,node){
                var attr=node.tagName=='A'?'href':(node.tagName=='FORM'?'action':undefined)
                if(attr)node[attr]=url;
            });
            return this;
        },
        send : function(){
            a$j=this.active$j();
            var entry=function(frame,refNode){
                if(frame.callbackReady==0){
                    setTimeout(function(){entry(frame,refNode)},10)
                }   
                else{
                    if (refNode.tagName == 'FORM')refNode.submit();
                    else {frame.src=a$j.myData('url')};
                }   
            }
            a$j.active$j().idxEach(function(idx,node){
                entry(a$j.frame$j(idx)[0],a$j.$j(idx)[0]);
            })
            return this;
        }
    }
})

})(jQuery)

MyClass

(function(){
    window.MyClass = {
        create : function(c,e){
            var f = function(){
                var ins;
                return (ins=MyClass.getMyInstance(f)).init.apply(ins,arguments);
            }
            f.__member__ = e||c;
            if(e)e.__c__=c;
            return f;
        },
        getMyInstance : function(f){
            var util = MyClass.MyUtil;
            if (f.__member__.__c__) {
                var ins = MyClass.getMyInstance(f.__member__.__c__)
                var $super = ins;
                ins = util.extend(
                        util.getInstance($super),util.getInstance(f.__member__,true)
                );
                ins.$super = $super;
                ins.MyUtil=util;
                return ins;
            }
            return util.getInstance(f.__member__||f,true);
        }
    }
    window.MyClass.MyUtil = {
        extend : function(obj,ext){
            for(var i in ext)obj[i]=ext[i];
            return obj;
        },
        getDeepInstance : function(obj){
            if (obj.constructor === Object) {
                var f = function(){};      
                for(var i in obj)f.prototype[i]=MyClass.MyUtil.getDeepInstance(obj[i]);
                return new f();
            }
            else return obj;
        },
        getInstance : function(obj,deep){
            var f;
            (f = function(){}).prototype = obj;      
            obj = new f;
            if(deep)for(var i in obj)obj[i]=MyClass.MyUtil.getDeepInstance(obj[i]);
            return obj;
        },
        getUniquDateKey : function(){
            var d = new Date();
            return d.getFullYear()+'_'+d.getMonth()+'_'+d.getDate()+'_'+d.getHours()+'_'+d.getMinutes()+'_'+d.getSeconds()+'_'+d.getMilliseconds();
        }
    }
})();

MyClass4jquery

(function($j){
    $j.MyClass = {
        create : MyClass.create({
            init : function(c,e){
                var o=this;
                var f = MyClass.create(c,e);
                var r = function(){
                    if(this===$j)return r.apply($j('body'),arguments);
                    var ins=$j.MyClass.getMyInstance(f,this);
                    return ins.init.apply(ins,arguments);
                };
                r.__member__ = f.__member__;
                return r;
            }
        }),
        getMyInstance : function(f,n$j){
            var o=this;
            var _init = f.__member__.init;
            f.__member__.init=function(){return this};
            var ins=f.apply(n$j,arguments);
            if(_init)ins.init = f.__member__.init=_init;
            o.nestedBind(ins,n$j);
            return ins;
        },
        nestedBind : function(ins,n$j){
            var o=this;
            if (ins.$super) {
                o.nestedBind(ins.$super,n$j);
                ins.__getter__=MyClass.MyUtil.getInstance(ins.$super.__getter__);
            }
            ins.my=function(){return ins}
            ins.crossBind = function(opt){return o.crossBind(ins,opt)}
            o.crossBind(ins,{getter:{$j:n$j},method:o.comnMethod})
            return ins;
        },
        crossBind : function(ins,opt){
            var o=this;
            var g = ins.__getter__=ins.__getter__||{}
            var m = ins.__method__=ins.__method__||{}
            if(opt.getter)$j.extend(g, opt.getter);
            if(opt.method)$j.extend(m, opt.method);
            o.initMyData(ins,g);
            for(var i in g)ins[i]=o.getReGetter(i,g[i],ins);
            $j.extend(ins,m);
            return ins;
        },
        initMyData : function(ins,obj){
            if(ins.__mydata__)return ins.__mydata__;
            ins.__mydata__=[];
            (obj.$j.__allObj__||obj.$j).each(function(idx){
                ins.__mydata__[idx]={};
            })
            return ins.__mydata__;
        },
        getReGetter : function(name,obj,ins){
            var o=this;
            var g=ins.__getter__;
            var m=ins.__method__;
            return function(idx){
                var newObj = o.reget(obj,idx);
                newObj.my=ins.my;
                for(var j in g)newObj[j]=o.getReGetter(j,g[j],ins);
                $j.extend(newObj,m);
                return newObj;
            }
        },
        reget : function(obj,idx){
            if(!(obj instanceof $j))return obj;
            if(!obj.__allObj__)obj.__allObj__=obj;
            if(typeof idx == 'object')idx = obj.__allObj__.index(idx);
            if(idx >= obj.__allObj__.size())idx=obj.__allObj__._idx;
            obj.__allObj__._idx=idx;
            if(idx==undefined)return obj.__allObj__;
            var newObj=obj.__allObj__.filter(':eq('+idx+')')
            newObj.__allObj__=obj.__allObj__;
            return newObj;
        },
        comnMethod : {
            idx : function(){
                return this.__allObj__?this.__allObj__._idx:undefined;
            },
            idxEach : function(f){
                var o=this,cIdx=o.idx();
                return o.each(function(idx,node){
                    f(cIdx==undefined?idx:cIdx,node);
                })
            },
            isOwnNode : function(){
                return this.parents('html')[0]===$j('html')[0]?true:this[0]===$j('html')[0];
            },
            active$j : function(){
                return this.$j(this.idx());
            },
            myData : function(key,val){
                var idx=this.idx();
                var mydata = this.my().__mydata__;
                if(arguments.length==2)
                    if(idx==undefined)
                        this.each(function(idx){
                            mydata[idx][key]=val;
                        })
                    else mydata[idx][key]=val;
                else return (idx==undefined)? mydata[0][key] : mydata[idx][key];
                return this;
            }
        }
    }
})(jQuery);