MSIEのパッチKB912945の対応案

たとえば・・・ですが、以下のような「やる気のない」対応でもいいかもしれません。

【条件】

  1. object,embed,appletの各オブジェクトに対し、動的にイベントメソッドなどを追加・削除していないこと
  2. object,embed,appletの各オブジェクトのonloadが2回呼ばれたり、(自動再生ならば)2回開始したりするかもしれないが、少しの時間差であれば許容できること

【特徴】

  1. 既存のHTMLのobject,embed,appletのタグ部分に手を加える必要がない
  2. window.onloadを含め、グローバル変数を使っていない(汚さない)
  3. HTMLファイルには1行加えるだけ

【外部ファイル】


(function() {
  var all = document.all;
  if(all) {
    var lst = [];
    var len = all.length;
    for(var i = 0; i < len; i++) {
      var obj = all[i];
      if(obj && obj.nodeName) {
        switch(obj.nodeName.toLowerCase()) {
          case "object":
          case "applet":
          case "embed":
            lst[lst.length] = obj;
            break;
          default:
        }
      }
    }
    for(var i = 0; i < lst.length; i++) {
      lst[i].outerHTML += "";
    }
    lst = null;
  }
})();

【HTMLファイル】
</body>の直前に、


<script language="JScript" src="★" charset="◆"></script>
★:上記JSファイル
◆:上記JSファイルの文字コード
を入れる。

【考え方】

  1. やる気ない(こんなことに労力を使いたくない)
  2. HTMLファイルはなるべく変更したくない
  3. MSIEだけ対象だからdocument.allで対象を探してouterHTMLをそのまま書き換えればいいでしょ*1
  4. 動的に実装されたイベントハンドラは却下*2

以下2006/01/13追記
【技術的観点】

  • 対象とするブラウザ
    JSが使用できないときは既存のタグでコンテンツが見られる。
    JSが使えるならばMSIEのみで動かし(language="JScript"とかdocument.allouterHTMLなど)、オブジェクトを置換する。
    removeChildしてinsertBeforeしてみたが、異なるオブジェクトでなければKB912945の問題は解決されないようです。
  • document.allのループについて
    1回目のループではリストアップのみを行い、変更はしません。変更すべきオブジェクトが確定するそばからオブジェクトを置き換えたくなかったので。
  • outerHTMLの置き換えについて
    2回目のループでオブジェクトを置き換えます。
    lst[i].outerHTML = lst[i].outerHTML;
    で動作(KB912945問題の解決を)確認しましたが、
    lst[i].outerHTML += ""
    でも(ソースの追記ではなく、ソースの入れ替えになるので)オブジェクトが置換されるはず*3なのでそれにしました。
  • <script>タグの記述場所
    scriptタグは</body>の直前に記述します。
    それは、全ての静的なobject,embed,appletタグが読み込まれた後に実行する必要があることと、onloadのタイミングが使用できないことによります。
    onloadのタイミングで何らかの処理が走るのを妨げることはできませんし、onloadよりも先に置換しておきたいので。
  • 問題点
    </body>の直前の段階で、すでにobject,embed,appletのオブジェクトに対する参照をJS側で保持していたり、JSでイベントなど(プリミティブ型ではないもの)を付加している場合は、参照が切れてしまいます。
    ドキュメントのonloadであれば間に合いますが、そうでなければ参照をコピーする必要があり、汎用的に作るのは結構めんどくさいです。
  • 拡張性
    もし拡張するならば、
    • この外部JSを読み込むscriptタグの属性として、(HTMLの仕様になくても)適当な属性を書く。

      <script language="JScript" src="★" charset="◆" ●="●属性の値"></script>
      ●:ありもしない属性
      これはdocument.scripts[document.scripts.length-1].getAttribute(●)とすれば取り出せるはずです。
    • この外部JSを読み込むscriptタグの開始タグと閉じタグの間に、JSのコメントとしてオプションを記述する。

      <script language="JScript" src="★" charset="◆"><!--
      //オプション1=値1
      //オプション2=値2
      //--></script>
      これは、document.scripts[documents.scripts.length-1].innerHTMLとでもすれば取り出せるはずです。
    などがあると思います。

*1:1回のループで変更するとallの参照先がなくなっちゃうのが嫌で、2回にしました。

*2:対応するとJSの容量が数倍にはなるはず

*3:私の環境の面からオブジェクトが置換されることは確認済みですが、KB912945が解決できるかどうかは未確認です。できるはずですが、できなかったら戻しますのでお知らせ頂けたら幸いです。私もsp2でアクティブ化できることを確認しました。