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 }');
}

element.replaceChildを使って上の階層に上書きする

今回は http://upload0.dyndns.org/up/2/_/ を使い易いように改造していく。

どのファイルでもいいので、適当にクリックして個別のファイルのダウンロードページに進む。

広告バナーがたくさん

ダウンロードページにいくとバナーがたくさんある。目的のファイルをダウンロードするには『ダウンロード』と書かれたリンクをクリックしないといけない。(自動的に『ダウンロード』のリンク先に飛ぶ方法もあるけど。)


firebugでソースをみるとこうなっている。

バナーにid、class、nameが付いていれば、広告不可視化関数を使って簡単にdisplay:none出来るけど今回は使えない。DOM element - MDCを眺めていたらreplaceNodeというのが便利そうなので使ってみることにした。
アイディアとしては、ダウンロードのaタグの部分を上の階層に上げる。上位と下位を入れ替える。そうすれば上書きされて広告バナーの部分が消滅するはず。

ソースコード

var d = document.evaluate('//a[@class="download"]', document, null, 7, null);
d.snapshotItem(0).parentNode.parentNode.parentNode.parentNode.replaceChild(d.snapshotItem(0), d.snapshotItem(0).parentNode.parentNode.parentNode);

まずxpathでaタグを補足する。入れ替え先の親ノードをreplaceChildの前に書いて、第一引数に入れ替えたいノード、第二引数に入れ替え先ノードを書く。


ちょっとだけダイエット。

var d = document.evaluate('//a[@class="download"]', document, null, 7, null);
d.snapshotItem(0).parentNode.offsetParent.replaceChild(d.snapshotItem(0), d.snapshotItem(0).parentNode.parentNode.parentNode);

tdにいくとoffsetParentにtableタグが指定されているのでそれを利用した。(firebugでのDOMツリーツアーは楽しい。)


追記 xpathでor検索して二匹釣る。
snapshotはツリー順に作られるのでsnapshotItem(0)はtable。snapshotItem(1)はa。

var d = document.evaluate('//a[@class="download"]|//table[descendant::a/@class="download"]', document, null, 7, null);
d.snapshotItem(0).parentNode.replaceChild(d.snapshotItem(1), d.snapshotItem(0));

結果

余計なものは消えた。ソースにGM_addStyle('.download { font-size:30pt }');を追加して『ダウンロード』の文字を大きくした。これが一番やりたかったこと。


tableの中身がすっきりした。

次回は、『ダウンロード』のリンク先に舞台を移して「ここから〜ここまで」のようにDOM Rangeを使って複数のノードを上の階層に上書きする方法を模索します。

関連