DOM Rangeを使って複数のノードを上の階層に上書きする

前回に引き続き http://upload0.dyndns.org/up/2/_/ を使い易いように改造する。

どのファイルでもいいので適当にクリックして、個別のページにいったら『ダウンロード』をクリックしてパスワードを求められるページに進む。


パスワード入力欄とボタンの部分だけ欲しい。


前回と同じように広告バナーを消すには、上の階層に移動するのが良さそう。複数のノードを扱うにはDOM Rangeが便利らしいのでそれを使ってみる。

ソースコード

  var d = document.evaluate('//label[@for="download_pass"]', document, null, 7, null);
  var range = document.createRange();
  range.setStart(d.snapshotItem(0), 0);
  range.setEnd(d.snapshotItem(0).nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling, 0);
  var df = range.extractContents();
  d.snapshotItem(0).parentNode.parentNode.replaceChild(df, d.snapshotItem(0).parentNode);

xpath一本釣り。まず基点となるlabelをxpathで補足する。次にRangeを組み立てていく。setStartとsetEndの第二引数のoffsetは今回必要がないので0。nextSiblingが並んでいるのはlabel→\n→input→\n→input→\n→inputという具合にDOMツリーを辿るため。formタグの外に置いたらpostできないので上げすぎに注意。
今回のミソはrange.extractContents()の部分。RengeはdocumentFragmentに変換しないとDOMツリー(?)に挿入することができないので、extractContents()かcloneContents()を使ってdocumentFragmentに変換する。


追記 こっちのほうがいいかな。xpathサビキ釣り。

//注意点は出力される順番を把握しておくこと。
//xpathはツリーの上から順に走査されるので今回の場合、
//divがsnapshotItem(0)、labelがsnapshotItem(1)、inputがsnapshotItem(2)となる。
var d = document.evaluate('//label[@for="download_pass"] | //input[@class="submit"] | //div[@class="input_download_pass"] ', document, null, 7, null);
var range = document.createRange();
range.setStart(d.snapshotItem(1), 0);
range.setEnd(d.snapshotItem(2), 0);
var df = range.extractContents();
d.snapshotItem(0).parentNode.replaceChild(df, d.snapshotItem(0));

結果

まとめ

// ==UserScript==
// @name           mod_index-uploader
// @namespace      http://d.hatena.ne.jp/Cherenkov/
// @include        http://upload0.dyndns.org/up/2/_/*
// ==/UserScript==

//キーワードにヒットしたらハイライト
var k = document.evaluate('//td[@class="name"]', document, null, 7, null);
for(i=0;i<k.snapshotLength;i++){
  //if(/hoge|fuga|kame|hige|cut/ig.test(k.snapshotItem(i).textContent)){ これ間違い
    if(/hoge|fuga|kame|hige|cut/i.test(k.snapshotItem(i).textContent)){
    k.snapshotItem(i).style.backgroundColor = 'yellow';
  }
}

//個別のファイルのページ
if(/jump/.test(location.href)) {
  var c = document.evaluate('//a[@class="download"]', document, null, 7, null);
  //if(c) location.href = c.snapshotItem(0).href; //コメントアウトをはずせば自動でパスワード入力のページへ
  c.snapshotItem(0).parentNode.offsetParent.replaceChild(c.snapshotItem(0), c.snapshotItem(0).parentNode.parentNode.parentNode);
  GM_addStyle('.download { font-size:30pt }');
}

//パスワード入力のページ
if(/download/.test(location.href)) {
  var d = document.evaluate('//label[@for="download_pass"]', document, null, 7, null);
  var range = document.createRange();
  range.setStart(d.snapshotItem(0), 0);
  range.setEnd(d.snapshotItem(0).nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling.nextSibling, 0);
  var df = range.extractContents();
  d.snapshotItem(0).parentNode.parentNode.replaceChild(df, d.snapshotItem(0).parentNode);

  document.getElementById('download_pass').focus();
  GM_addStyle('#download_pass { font-size:30pt }');
}