2012/03/19

jQueryのload()とdocument.write()の共存

個人情報さらしてみる。
このページを管理している(現時点)のは俺なんだが、jQueryを使い始めた当時は何故か、真っ白なページに
Powered by FC2.com
とだけ表示されていて、大いに困った。いえでもちょろめでも火狐でもこうなる。
火狐に至っては「wyciwyg://103//http://~~」とかわけのわからんパスに飛ばされる始末。
で、最終的になんとかこのトラブルを(とりあえず)解決したのでここに記録しておく。

ずっと「読み込み中」だからFirebugが使えない、しかもwyciwyg://って…

ローカルの鯖(Apache)では正しく動作していたのに、リモートでは動かない。
プログラミングではよくあることだと自分をなだめつつ調査開始。

まず、一瞬あるべき姿のページが表示されたのち、ページがリセットされて「Powered by FC2」の一行のみになる。
アドレスバーを見るも、以上は無さそうだが、なぜかFirebugとかがページを移動したときと同じ挙動をする。
履歴を見てみると、なんと「wyciwyg://##/http://~~~」となっていて、##の部分は毎回数字が変わる。
そこで「"wyciwyg://"」をggr。すると「wyciwyg://」ドキュメントへの不正アクセスというのが引っかかった。
(ついでに、「WYCIWYG」は"What You Cache Is What You Get"らしい。(→Wikipedia))
でもこれMozillaってことは、Firefoxじゃん。しかも
「修正済みのバージョン Firefox 2.0.0.5」
ふ・ざ・け・る・な!

「Powered by FC2」ェ…

これは手がかりにならないので、ChromeとIEで見てみると、やっぱりFirefoxと同じ症状(ただしwicywigではないが)。
仕方ないのでfc2鯖との相違点を探す。てか一行広告しかないじゃん。
てことで一行広告を調べる。
どうやらbody要素の最後に次の内容が入るようだ。

<script type="text/javascript"><!-- var fhp_c_pc = navigator.userAgent.toLowerCase(); var fhp_ie = ((fhp_c_pc.indexOf("msie") != -1) && (fhp_c_pc.indexOf("opera") == -1)); var fhp_cs, fhp_wt, fhp_dm; if (fhp_ie) { fhp_cs = document.charset; }else{ fhp_cs = document.characterSet; } fhp_dm = encodeURI(document.location); fhp_wt = ""; fhp_wt = '<' + 'script src="http://web.fc2.com/header.php?cs=' + fhp_cs + '&dm=' + fhp_dm + '" charset="UTF-8"><' + '/script>'; fhp_wt += '<' + 'script src="http://web.fc2.com/footer/footer.php?cs=' + fhp_cs + '&dm=' + fhp_dm + '"><' + '/script>'; document.write(fhp_wt); //--></script> <!-- FC2, inc.--> <img src="http://media.fc2.com/counter_img.php?id=50" style="visibility:hidden" alt="inserted by FC2 system" width="0" height="0" /> <!-- FC2, inc.-->

なんで直接入れないんだよ… これがさらに展開されて、document.write()で追記される。

http://web.fc2.com/header.php
fhp_head='';
web.fc2.com/footer/footer.php
//http://kesc.web.fc2.com/ document.write('<div id=\"fc2_footer\">'+"\n"); document.write('<span style=\"font-size:12px;\">'+"\n"); document.write('<br>'+"\n"); document.write('Powered by <a target=\"_blank\" href=\"http://fc2.com/\">FC2.com</a>'+"\n"); document.write('</span>'+"\n"); document.write('</div>'+"\n"); document.write(''+"\n"); move_fc2_footer(); function move_fc2_footer(){ if(!document.getElementById("fc2_footer")){return;}; var ff=document.getElementById("fc2_footer"); ff.style.textAlign="center"; ff.style.width="100%"; ff.style.lineHeight="14px"; }

開始タグと終了タグが別々に…
こういうのは処理系を開発する側としては辛いんだけどな…
というか、DOMがどうとか言ってるこのご時勢に、document.write()とかアリなのか?

そもそもdocument.write()がだな

再びggったところ、どうやらdocument.write()自体は問題ないらしい。
仕方ないので、htmlに仕込んだスクリプトをコメントアウトしながら原因調査。すると…
$(~).load()を入れるとdocument.write()のタイミングでおかしくなることが発覚。
やっぱAjaxとは相性悪いんだな…

しかし大人の社会とやらは

しかし、「相性が悪い」という理由で広告を消してしまうと契約違反なので、がんばってdocument.write()を動かさなければならない。
どうするか。
document.writeをオーバーライドするしかない。
普通に考えれば、

  1. document.write()の引数の文字列をためていく
  2. すべて読み終わったらタグ生成&表示
となりそうだが、ここで問題が。
document.write()で出力したscriptタグの内容って、もう一度document.write()を呼ぶんじゃね?
こりゃ参った。正攻法でなんとかしようと思ったら、かなり面倒になる。

というわけで、手抜きしました。

document.write()で開始と終了タグを別々に出力するとはいっても、たかが何ミリ秒のレベルだろ?
というわけで、

  1. はじめの書き込みから1000ms間は溜める
  2. 出力。以降は、2000msごとに出力
というかんじのスクリプトを組んだ。
iframeとかで読んだ別のページでもdocument.write()されても親の方に表示されてしまったりするが、現状では困ってないので無視。

jquery_use.js
var __tl_internal_document_write={cntnow:5,str:[],ready:false, add:function(str){ __tl_internal_document_write.str[__tl_internal_document_write.cntnow]+=str; }, show:function(){ if(__tl_internal_document_write.cntnow>0){ $(__tl_internal_document_write.str[__tl_internal_document_write.cntnow]).appendTo($(document.body)); __tl_internal_document_write.str[__tl_internal_document_write.cntnow--]=""; setTimeout(__tl_internal_document_write.show,2000); }else{ __tl_internal_document_write.cntnow=4; } }, fn:function(str){ __tl_internal_document_write.add(str); if(__tl_internal_document_write.ready){ setTimeout(__tl_internal_document_write.show,1000); } } }; // __tl_internal_document_write document.write=__tl_internal_document_write.fn; $(function(){ __tl_internal_document_write.ready=true; __tl_internal_document_write.show(""); });

2 件のコメント:

  1. はじめまして。
    まったく同じ状況に出くわしており調べてたらこのページに辿りつきました。

    自身のHPもFC2上に載せてるんですが、2ペインの左メニュー部を一括で共有しようと考え、各htmlのheadに…

    <script type="text/javascript" src="js/jquery-1.11.0.min.js"></script>
    <script>
    $(function(){
    $("#Menu").load("menu.html");
    })
    </script>

    の様に指定してます。その際に管理者様と同じ状況になりました。

    もしよろしければ、管理者様が作った jquery_use.js を使用しても構わないでしょうか?

    また使用しても良い場合、どのように組み込めば使用できるのかご教授出来ませんでしょうか?
    ※最近 jQuery を勉強したばかりで組み込み方が「?」になっております。

    <script type="text/javascript" src="js/jquery-1.11.0.min.js"></script>
    <script type="text/javascript" src="js/jquery_use.js"></script>
    <script>
    $(function(){
    $("#Menu").load("menu.html");
    })
    </script>

    として発火させる記述があればいける感じでしょうか?

    長文ですみませんでした。
    もしお手数でなければご教授下さい。

    よろしくお願いいたします。

    返信削除
    返信
    1. おつかれさまです。

      jquery_use.jsの使いかた(というほどのものでもないですが)は、それで合ってます。
      このスクリプト内でjqueryの機能が使われているので、jquery_use.jsはjquery.jsの後でさえあれば、headタグ内のどのタイミングで読んでも構いません。
      また、このスクリプトは読まれた時点で必要な処理は行ってくれるので、他の部分で何か特別なことをする必要はありません。

      このコードの著作権とかは一切気にしないので、コピペするなり改造するなり、それを使うなり配布するなり、好きにしてもらって構いません。
      というより間に合わせのコードなのでタイミングによっては問題が起きるかもしれませんが、そこら辺の責任も持てないので、いつか余力のあるときに、御自身でもっとマシな対策をされるのが良いかと思います。

      削除