AutoPagerize#SITEINFOのinsertBeforeを省略する際の精度をあげる
siteinfoにinsertBeforeがなくてもいいようにしました。
とあって、実装は下記のようになっている。
if (info.insertBefore) { this.insertPoint = getFirstElementByXPath(info.insertBefore) } else { var lastPageElement = getElementsByXPath(info.pageElement).pop() if (lastPageElement) { this.insertPoint = getFirstElementByXPath('following-sibling::node()', lastPageElement) } }
.insertBeforeが空だったら、{{pageElementの最後の要素}の次に来る兄弟要素}をinsertPointにしている。
改行なりスペースのひとつでもあれば、見た目にはわからなくてもテキストノードが存在することになるので、
汎用的に動きそうに思える。
が、Googleなどhtmlをコンパクトにしている場合、改行もスペースもないのでinsertPointも空になってしまう。
こういった場合は普通ならinsertBeforeの代わりにappendChildすればよいが、今回はそれをすると変更箇所が多くなるので避けたいところ。
そこで、スペースだけのテキストノードをappendChildしておいて、その要素をinsertPointにする案を考えた。
ので、oAutoPagerizeで次のように実装してみた。
var lastPageElement = getElementsByXPath(info.pageElement).pop(); this.insertPoint = lastPageElement.nextSibling || lastPageElement.parentNode.appendChild(document.createTextNode(' '));
nextSiblingが空だったらparentNodeにTextNodeをappendChildしていて、ちょうどappendChildがTextNodeを返してくれているので、insertPointにはそのTextNodeが入ってくれる。
ちなみに、
getFirstElementByXPath('following-sibling::node()', lastPageElement)
は、「following-sibling 基準点はコンテキストノードの後ろにあるすべての兄弟ノードを選択」し、「::node() はノード型に関係なく、コンテキストノードのすべての子ノードを選択する」したものから最初の要素を取得している*1。
これは自分の兄弟であり、直後に当たる要素なので、
lastPageElement.nextSibling
つまりはnextSiblingになる。(調べた限り間違いないと思うんだけど、やっぱり言い切るのは不安だなぁ。。)
なので、DOMで一発で取れる場合はXPathのほうが効率悪いので、nextSiblingを使っている。