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関数 }
Firefox と IE の場合のみこのタイミングで callback関数が実行されてしまう。(OperaとSafariは平気)
で、
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);