オーマイニュース用AutoPager

オーマイニュースのコメント欄を閲覧しやすくするための Greasemonkey スクリプト。かっとなって作った。別に反省はしていない。Opera 9.01 と Firefox 1.5 + Greasemonkey 0.6.5 で動作を確認。
しかし、ページングするために FORM つかって POST してるのな。なんか validation 用のパラメータとかもあってやたらと面倒だった。しかもやたらと id が長い。
まぁ、ここまでしてあのサイトのコメント読みたいかといえば全然そんなことはないんだけど。いや、コメントに限らず記事本文もアレだけど。

// ==UserScript==
// @name           OhMyNewsAutoPager
// @description    Auto Pager for comment at Oh My News
// @include        http://www.ohmynews.co.jp/*
// ==/UserScript==

(function() {
     if (location.href.match(/&paging=1$/)) {
         return;
     }

     var $ = function(id, doc) {
         if (!doc) { doc = document; }
         return doc.getElementById(id);
     };

     var parseHTML = function(text) {
         var createHTMLDocument = function() {
             var xsl = (new DOMParser()).parseFromString(
                 ['<?xml version="1.0"?>',
                  '<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform">',
                  '<output method="html"/>',
                  '</stylesheet>'].join("\n"), "text/xml");

             var xsltp = new XSLTProcessor();
             xsltp.importStylesheet(xsl);
             var doc = xsltp.transformToDocument(
                 document.implementation.createDocument("", "", null));
             return doc;
         };

         var doc = createHTMLDocument();
         var range = doc.createRange();
         doc.appendChild(doc.createElement("html"));
         range.selectNodeContents(doc.documentElement);
         doc.documentElement.appendChild(
             range.createContextualFragment(text));
         return doc;
     };

     var getNextPage = function(doc) {
         var target =  $('ctl00_ContentPlaceHolder1_NewsComment1_DDataGrid1', doc);
         if (!target) { return null; }

         var spans = target.getElementsByTagName("span");
         var current;
         for (var i = 0; i < spans.length; i++) {
             if (spans[i].className == "pager-current") {
                 current = spans[i];
                 break;
             }
         }
         if (!current) { return null; }

         var next = current.nextSibling;
         while (next != undefined && next.nodeType != 1 && next.tagName != 'A') {
             next = next.nextSibling;
         }

         if (next == undefined || next.getAttribute('href') == undefined) {
             return null;
         }

         if (next.getAttribute('href').match(/javascript:__doPostBack\('(.*)','(.*)'\)/)) {
             return {
                 '__EVENTTARGET': RegExp.$1,
                 '__EVENTARGUMENT': RegExp.$2,
                 '__VIEWSTATE': $('__VIEWSTATE', doc).value,
                 '__EVENTVALIDATION': $('__EVENTVALIDATION', doc).value
             };
         } else {
             return null;
         }
     }

     var scrollRemain;
     if (window.opera) {
         scrollRemain = function() {
             var sc = document.body.scrollTop;
             var total = document.body.scrollHeight - document.body.clientHeight;
             return total - sc;
         };
     } else {
         scrollRemain = function() {
             var sc = document.documentElement.scrollTop;
             var total = document.documentElement.scrollHeight - document.documentElement.clientHeight;
             return total - sc;
         };
     }

     var watchScroll = function() {
         var self = arguments.callee;
         var next = function() { setTimeout(self, 200); };
         var remain = scrollRemain();

         if (remain < 1500) {
             doRequest(next);
         } else if (!end_flag) {
             next();
         }
     };



     var doc = document;
     var doRequest = function(next) {
         var req = new XMLHttpRequest();
         var arg = getNextPage(doc);
         if (!arg) {
             end_flag = 1;
             return;
         }

         var data = [];
         for (var name in arg) { 
             data.push(name + '=' + encodeURIComponent(arg[name]));
         }

         req.onreadystatechange = function() {
             if (req.readyState != 4) { return; }
             doc = parseHTML(req.responseText);
             var target = $('ctl00_ContentPlaceHolder1_NewsComment1_PanelCommentList');
             var append = $('ctl00_ContentPlaceHolder1_NewsComment1_PanelCommentList', doc);
             var div = document.createElement('div');
             div.innerHTML = append.innerHTML;
             target.appendChild(div);

             next();
         };

         req.open('POST', $('aspnetForm').action + '&paging=1', true);
         req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
         req.setRequestHeader('Content-Length', data.join('&').length);
         req.setRequestHeader('Referer', location.href);
         req.send(data.join('&'));
     };

     var end_flag = 0;

     if (window.opera) {
         window.onload = function() {
             watchScroll();
         }
     } else {
         window.wrappedJSObject.onload = watchScroll;
     }
 })();