uupaa.jsの不具合報告
Twitterの@uupaaさんのメールアドレスが分からないので、
日記で不具合報告を書くことにします。
まぁ、ずっと更新されてない日記なので、こんな使い方でも良いでしょう。
<table> <tr id='xx'><td>C</td><td>D</td></tr> </table>
以上のようなHTMLがあって、スクリプト内にて、以下の様な処理を行います。
uu('#xx').add('<tr><td>A</td><td>B</td></tr>', 'prev');
すると、OperaとSafari以外のブラウザ(IE, firefox, Chrome)にて、
予想と異なる結果になりました。
(各ブラウザでどうなるかは、各自やってみてください)
それで、少しソースコードを変えて、以下の様にしてやると、
失敗していたブラウザでも、予想と同じ結果になりました。
uu('#xx').add(uu.node.bulk('<tr><td>A</td><td>B</td></tr>'), 'prev');
で、uupaa.js初心者な私としては、
これはこういうものだと最初のうちは思ったのですが、
どうやら違うことに気が付きます。
これはバグだ――そんな予感がして、ちょいと調べてみました。
バグな気がしたのは、addのみの処理の場合でも、その中では
uu.node.bulkを呼び出していたからです。
addの第二引数は、内部関数のuunodeaddの中では
positionという変数に収納されます。
そして以下の様な処理で、指定した場所に追加する処理が書かれています。
switch (uunodeadd.pos[position] || 8) { case 1: reference = context[_parentNode][_firstChild]; case 2: reference || (reference = context); case 3: reference || (reference = context[_nextSibling]); case 4: context[_parentNode].insertBefore(node, reference); break; case 5: reference = context[_firstChild]; case 8: context.insertBefore(node, reference); }
uunodeadd.pos = { first: 1, prev: 2, next: 3, last: 4, "./first": 5, "./last": 8 };
uu.node.bulkが内部的に呼ばれているのは、その少し前……
下記の場所のuunodebulkが、それにあたります。
var nodes = !source ? [newNode()] // [1] uu.node.add() : isArray(source) ? source // [4] uu.node.add([<div>, <div>]) : source[_nodeType] ? [source] // [3][6] uu.node.add(Node or DocumentFragment) : !source[_indexOf]("<") ? [uunodebulk(source, context)] // [5] uu.node.add(HTMLFragmentString) : [newNode(source)], // [2] uu.node.add("p") reference = null, i = 0, iz = nodes.length, node, rv;
uu.node.bulkを予め呼び出しておいた場合と、
ほとんど同じ扱いをされていることになるのですが、
唯一違うのはcontext、こいつの中身が、結果を変えていると言えます。
で……contextが何者なのか、調べました。
uu.node.bulkを直接呼び出した場合、
contextは'div'と同じものとして動作します。
そしてadd経由で呼び出されていた時は、'TR'になっていました。
uunodebulk内の大まかな流れとしては、以下の様な感じです。
1. contextをdoc.createElementする。
2. 1で作ったノードのinnerHTMLに、作りたいhtmlテキストを流し込んでやる。
3. ノードから、子要素を全て抜き出す。
つまり、具体例で言うと'<tr><td>A</td><td>B</td></tr>'の親ノードとして、
contextを使ってノードを作っている、ということです。
divの時にうまく行って、TRのときにうまくいかないのは、
trタグの中にtrタグを生成するのがDOM的に不正だからでしょう。
そう、本当にあるべきcontextは、TRではなく、TABLEなわけです。
もうお分かりでしょうか。
positionによって処理分岐が発生するのは、要素を収納する時だけでなく、
context(文脈)を特定する時にも、positionによる分岐が必要なのです。
ここまで書けば、あとはこれだけ立派なjsライブラリを作った@uupaa氏が、
良い感じに修正してくれることだと思います。
それにしても、Javascriptド素人の私が、
ちょっと読んだだけで原因を特定できるぐらい読みやすいコードを書くuupaa氏、
流石ですね。
ということで、原因だけ特定しておいて、この日記を終えます。
アデュー。