はてな匿名ダイアリーでその場で返信/投稿できるようにする

  • Permalink」の横に「Reply」をつける
  • 「Reply」を押すと下にフォームを出す
    • タイトルを返信元エントリのURLにする
    • テキスト選択中の場合はそれを引用文とする
  • 右上の「日記を書く」を押してもフォームを出す
// ==UserScript==
// @name anond quick post
// @include http://anond.hatelabo.jp/*
// @exclude http://anond.hatelabo.jp/*/edit
// @exclude http://anond.hatelabo.jp/search?*
// ==/UserScript==

(function(){
  var xeb = xe(document.body);
  var username = xeb("descendant::td["+className("username")+"]/a", 0);
  if (!username) return;
  var editpath = "/"+username.textContent+"/edit";

  xeb("descendant::a[@href='"+editpath+"']", function(a){
    a.addEventListener("click", function(e){
      e.preventDefault();
      getEditForm(function(form){
        xe(form)("descendant::h2", 0).style.display = "block";
        var day0 = xeb("id('body')/div["+className("day")+"]", 0);
        var body = day0.parentNode;
        if (day0.previousSibling == form) {
          body.removeChild(form);
        } else {
          body.insertBefore(form, day0);
          setControlValue(form, {title: "", body: ""});
        }
      });
    }, false);
  });
  if (window.AutoPagerize) window.AutoPagerize.addFilter(filter);
  filter([document.getElementById("body")]);

  function filter(pages){
    for (var i = 0, len = pages.length, page; i < len; i++) {
      page = pages[i];
      xe(page)("descendant::p["+className("sectionfooter")+"]", function(p){
        var eb = document.createElement("a");
        eb.href = editpath;
        eb.textContent = "Reply";
        eb.addEventListener("click", function(e){
          e.preventDefault();
          var title = xe(p)("preceding-sibling::h3/a", 0).href;
          var body = document.getSelection();
          getEditForm(function(form){
            xe(form)("descendant::h2", 0).style.display = "none";
            var sect = eb.parentNode.parentNode;
            if (sect.lastChild == form) {
              sect.removeChild(form);
            } else {
              sect.appendChild(form);
              setControlValue(form, {title: title, body: ""});
              if (body) setControlValue(form, {body: ">>\n"+body+"\n<<"});
            }
          }, function(){
            var href = editpath + "?title=" + encodeURIComponent(title);
            if (body) href += "&body="+ encodeURIComponent(">>\n"+body+"\n<<");
            location.href = href;
          });
        }, false);
        p.insertBefore(eb, p.childNodes[1]);
        p.insertBefore(document.createTextNode(" | "), eb);
      });
    }
  }
  function getEditForm(fn, errfn){
    var c = arguments.callee;
    if (!c.form) {
      var r = new XMLHttpRequest();
      r.open("GET", editpath, true);
      r.onreadystatechange = function(){
        if (r.readyState == 4) {
          if (r.status == 200) {
            var dummy = document.createElement("div");
            var m = r.responseText.match(/<form method="post"[\s\S]+?<\/form>/i);
            dummy.innerHTML = m[0];
            fn(c.form = dummy.removeChild(dummy.firstChild));
          } else if (errfn) errfn();
        }
      }
      r.send(null);
    } else fn(c.form);
  }
  function setControlValue(form, hash){
    for (k in hash) {
      if (hash.hasOwnProperty(k)) form.elements.namedItem(k).value = hash[k];
    }
  }
  function className(name){
    return "contains("+
      "concat(' ',normalize-space(@class),' '), concat(' ','"+name+"',' ')"+
    ")";
  }
  function xe(c, r){
    c = c || document;
    var d = (c.nodeType == 9) ? c : c.ownerDocument;
    return function(expr, fn){
      var result = d.createExpression(expr, r).evaluate(c, 7, null);
      if (typeof fn == "number") {
        return result.snapshotItem(fn < 0 ? fn+result.snapshotLength : fn);
      } else {
        for (var i = 0, len = result.snapshotLength; i < len; i++) {
          if (fn(result.snapshotItem(i), i) === false) break;
        }
      }
    }
  }
})();
  • AutoPagerizeと併用したときに2ページ目以降有効に機能していなかったのを修正 (2008-03-27)