jQuery と object タグの怪

Silverlightコンテンツを埋め込むjQueryプラグイン - Programmable Life で困ってたので一緒に悩んでみた。

でも何故かIEでは動かない。誰か動くようにしてけれ!

Silverlightコンテンツを埋め込むjQueryプラグイン - Architect Life

object を作れていない?

手元に環境を作って動かしてみると、<object> に <param> を追加するところで JavaScript エラーが出る。状況を切り分けるために、<param> を追加する部分をコメントアウトしてみた。

IE DOM Explorer で眺めてみると DIV タグが追加されている。

どうやら

var obj = $('<object>').attr({ ... });

のところで object タグが作られていないようだ。

jQuery でよく見る現象だ。こういうときは閉じ括弧を入れてあげると大抵うまくいく。

var obj = $('<object/>').attr({ ... });

IE DOM Explorer で確認したら <object> になってた。

でも、だめ

一歩前進したのでコメントアウトを外してみた。

が、やっぱり append のところでエラーがでる。

            obj.append( // ←ココ
                $('<param>').attr({
                    name: name,
                    value: value
                })
            );

同じ作戦で <param></param> のようにやってみたが変わらず。

仕方がないので、jQuery の $('<param>') から呼ばれる clean のソースを読んでみた。

IE で $('<param>') とすると、内部ではこんな処理をしてる。

var div = document.createElement("div");
div.innerHTML = "div<div>" + html + "</div>";
div = div.lastChild;
return jQuery.makeArray( div.childNodes );

空の div タグを作って、その中に innerHTML で HTML 文字列を流し込んで DOM ノードを作成しているようだ。

ここでピーンときた。仕様上は param タグは、本来は object タグの内部にしか入れることができない。なので、<div><param></div> のような HTML を innerHTML で設定すると、このときに生成される param タグは本来の param タグではなく、何か別のものになってるんじゃないだろうか。だから、object に appendChild すると不正なノードを追加したのでエラーになる。

あくまで想像。

同じような工夫は歯が立たない

同様の問題は既に jQuery で対応されている。例えば td タグなどを生成するときに単に innerHTML でノード生成するとエラーに出くわすので、一旦 table で囲ってから innerHTML する、といった泥臭いことをしている。

param タグに関しても、同じ仕組みを使えばうまくいくはず、と信じて前後を object タグで囲ってから innerHTML してみた。

が、うまく行かない…。

// IE7 で検証したよ
div.innerHTML = "<object><param></object>";
alert(div.innerHTML);  // <OBJECT></OBJECT>
div.innerHTML = "<object><param/></object>";
alert(div.innerHTML);  // <OBJECT></OBJECT>

なぜか param が消える。ナゼジャー!

仕方がないから諦めた

ということで、諦めて次のように置き換えたらうまく行った。

  $(document.createElement('param')).attr({

jQuery に任せず、自分で作っちゃえ!ということですな。

そして…

IE DOM Explorer で眺めてみたら、ちゃんと object の中に param が入って理想的な DOM ノードが構築されていた。

おお、完璧。

しかし…肝心の Silverlight コンテンツが表示されない。

ナゼダ…。

さらに、代替コンテンツの「Microsoft Silverlight を取得」のリンクもなぜか object ノードに入っていない。上と同じく document.createElement 作戦を試したが、それでもエラー。

不思議だ…。

まとめ

  • object は鬼門
  • 謎な挙動が多い
  • 同じようなことを Flash でやる超有名ライブラリの SWFObject は object 全体を innerHTML で作成してる。ソースを読んでてもバッドノウハウの塊っぽい

jQuery と object タグの怪 (その2) に続く。