ある意味ハーレムもの。
えろい回に限ってあからさまな力の入れようでどん引き(笑
まあ、結果的に面白いなら、それもアリか。
ドナルドはどう思う?
Enjoy everything.
ある意味ハーレムもの。
えろい回に限ってあからさまな力の入れようでどん引き(笑
まあ、結果的に面白いなら、それもアリか。
ドナルドはどう思う?
// 仮作成版。完成版は後述
var $n = function(nodeName, attrs){
var _parent = this, _callee = arguments.callee, _node = document.createElement(nodeName);
for (var i in attrs) {
if (i === "style") {
var ns = this.node.style, as = attrs.style;
for (var j in as) ns[j] = as[j];
} else {
this.node[i] = attrs[i];
}
}
return {
node: _node,
create: function(){
var self = this, parent;
while ((parent = self.parent()).node) self = parent;
return self.node;
},
text: function(text){
_node.appendChild(document.createTextNode(text));
return this;
},
child: function(){
var child = _callee.apply(this, arguments);
_node.appendChild(child.node);
return child;
},
parent: function(){
return _parent;
},
do: function(F, thisp){
F.call(thisp, this.node, this);
return this;
},
};
};
var iso8601 = function(d){
var ary = [d.getMonth()+1, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds()].map(function(v){ return ("0"+v).slice(-2); });
// Date#getTimezoneOffsetとかいうのもあるけどパス
return d.getFullYear() + "-" + ary.slice(0,2).join("-") + "T" + ary.slice(2).join(":") + "+09:00";
};
console.dirxml(
$n("div", {className: "hentry"})
.child("h2", {className: "entry-title"})
.child("a", {rel: "bookmark", href: location.href, textContent: "ENTRY-TITLE"}).parent()
.parent()
.child("div", {className: "entry-content"})
.child("p")
.text("ENTRY-CONTENT").parent()
.parent()
.child("abbr", {className: "updated", title: iso8601(new Date()), textContent: (new Date()).toString()}).parent()
.child("address", {className: "vcard author"})
.child("a", {className: "url fn", href: location.href, textContent: "AUTHOR"})
.create()
)
<div class="hentry">
<h2 class="entry-title">
<a rel="bookmark" href="http://mayokara.info/note/">ENTRY-TITLE</a>
</h2>
<div class="entry-content">
<p>ENTRY-CONTENT</p>
</div>
<abbr class="updated" title="2008-07-13T06:17:56+09:00">Sun Jul 13 2008 06:17:56 GMT+0900 (JST)</abbr>
<address class="vcard author">
<a class="url fn" href="http://mayokara.info/note/">AUTHOR</a>
</address>
</div>
どう見てもjQuery。
doを挟むことで、既にあるノードをappendChildしたりできる。
livedoor Readerのはどんなんだっけかな。
parent().child()の省略形でsibling()、はちょっとややこしいか。
実際のところ、Range#createContextualFragment使ったほうが楽だとは思う。
prototype仕様の完成版できた。
var $n = function(nodeName, attrs){
if (!(this instanceof $n)) return new $n(nodeName, attrs);
if (!nodeName) { this.node = document.createDocumentFragment(); return; }
this.node = document.createElement(nodeName);
for (var i in attrs) {
if (i === "style") {
var ns = this.node.style, as = attrs.style;
for (var j in as) ns[j] = as[j];
} else {
this.node[i] = attrs[i];
}
}
};
$n.prototype = {
_parent: null,
node: null,
create: function(){
var self = this;
while (self._parent) self = self._parent;
return self.node;
},
text: function(text){
this.node.appendChild(document.createTextNode(text));
return this;
},
child: function(nodeName, attrs){
var child = new $n(nodeName, attrs);
this.node.appendChild(child.node);
child._parent = this;
return child;
},
sibling: function(/* nodeName, attrs */){
var parent = this._parent;
return parent.child.apply(parent, arguments);
},
parent: function(){
return this._parent;
},
do: function(F, thisp){
F.call(thisp, this.node, this);
return this;
},
};
prototypeにオブジェクトを直接代入してるせいで、this.constructorが消えてしまうのが痛いなあ。
// ルートにdivを作る、引数なしでDocumentFragment
$n("div")
// プロパティを指定してdivをappendChild
.child("div", {className: "section", style: {margin: "1em 0"}})
// textNodeをappendChild
.text("何かのテキスト")
// さらにanchorをappendChild
.child("a", {href: location.href, textContent: "リンク"})
// aの中から出る
.parent()
// div.sectionの弟ノードを作る
.sibling("ul")
.child("li", {textContent: "list1"})
// 2つ目以降は.sibling()で追加する(.parent().child()と等価)
.sibling("li", {textContent: "list2"})
.sibling("li", {textContent: "list3"})
.sibling("li", {textContent: "list4"})
// li[4]の中から出る
.parent()
// さらに弟ノードを作って事前に用意したDocumentFragmentなどを入れる
.sibling("div").do(function(v){ v.appendChild(df); })
// 作成終了、ルートノードを返す
.create()
こんな感じ。
application/xhtml+xmlなページでcontinue_reading.user.jsが動かない問題が解決した。
既に更新済。以下覚書。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
この2行のせい。
つまり、<\?\w+とか<!\w+でこけている。
<--(HTMLにおけるコメント)は通る。
というわけで
var html = str.replace(/^[\s\S]*<html[^>]*>|<\/html>[\s\S]*$/ig, "");
解決。
innerHTML、読み取り専用っぽい。
というわけで、DOM関数で組み立ててappendChildして解決。
http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-102161490
var doc = document.implementation.createDocument("", "html", null);
でOK。
第2引数はdocumentElementを参照するために必要。
html/body要素が消える。
Firefox2ではhead要素も消え、事前にrange.setStartAfter(document.body)などとして何らかの選択をしないと評価されない。
Greasemonkey: continue_reading.user.js - mayokara note
iframe.style.width = document.documentElement.clientWidth + "px"で対処。
overflow: hidden; width: 1px; height: 1px;なdiv要素で隠す。
外部ドキュメントからのノードは、現在のドキュメントに挿入する前に importNode() を使ってクローンを作る (あるいは adoptNode() を使って取り込む) べきです。
DOM:document.adoptNode - MDC
エラーは出さないけど、使うべきだそうな。
iframe.style.display = "none"だと発生しない(Firefox2だけ?
iframe.style.visibility = "hidden"の場合は問題ない。
相変わらず、さっぱり意味がわからない。
GM_xmlhttpRequestでoverrideMimeTypeをtext/htmlにしてるのがまずいのかなあ。
Greasemonkey: continue_reading.user.js - mayokara note
position: absolute;のとき領域が被る
position: relative;に書き換えれば一応何とかなる
AutoPagerizeでtr要素の継ぎ足し時にレイアウトが崩れることがある件 - 0x廃棄階層 - 統治局
このパッチを参考に、pageElementの先頭がtr要素のときナビゲーションにdiv要素ではなくtr+td要素を使うようにした。
これにより、AutoPagerize – Userscripts.orgのコメント欄などの表示が崩れなくなる。
Twitterはdiv要素にもhentryをつけてるので効果なし。
たとえばGoogleの検索結果の6ページ目で以下を実行すると
$g('/descendant::a[self::node()+1=following::a[1]]', null, function(v){
return v.textContent;
})
// -> ["1", "2", "3", "4", "7", "8", "9", "10", "11", "12", "13", "14"]
こうなる。
すなわち、6だけテキストになっているため、元々a要素がない6とその前の5が落ちる。
これを踏まえて。
// location.href === "http://www.google.co.jp/search?q=hoge&start=50"
var nextLink = null, prev = 0;
$g('/descendant::a[self::node()+1=following::a[1]]', null).some(function(v){
if (!prev || prev+1 == v.textContent) {
prev = Number(v.textContent);
} else {
nextLink = v.href;
return true;
}
});
console.log(nextLink || "NOT FOUND");
// -> http://www.google.co.jp/search?hl=ja&q=hoge&start=60&sa=N
うむ、いけそう。
……なんだけど、このままだと1ページ目のときと最後の1ページ前のとき取れない。
1ページ目のときは「2」ちょうどのパターンで何とかなるけど、どうするかな。
$g('/descendant::a[self::node()-1=preceding::a[1] or self::node()+1=following::a[1]]', null, function(v){
return v.textContent;
})
// -> ["1", "2", "3", "4", "5", "7", "8", "9", "10", "11", "12", "13", "14", "15"]
前も見るようにするとこう。
この場合は、1ページ目と最後のページで結果を区別できないのが痛い。
あと、両者共通して「Comment(0) Trackback(1)」の数字にだけリンクが貼られているときなどに誤爆する。
配列の要素が3つ以上、とかの条件をつければ何とかならないこともないが、総ページ数が3ページ以下のときに検出できなくなる。
hashがあるかどうかを見る方法もあるけど、汎用性がない。
複数の画像を指して1、2、3とリンクを貼っているページもある。
総じて微妙。
var ELController = function(target, type, handler, useCapture){
return {
on: function(){
target.addEventListener(type, handler, useCapture);
},
off: function(){
target.removeEventListener(type, handler, useCapture);
},
};
};
var onclick = new ELController(window, "click", function(){
alert(1);
}, false);
(click) // -> none
onclick.on();
(click) // -> alert(1)
onclick.off();
(click) // -> none
クロージャを使って直接オブジェクトを返す形にすると、this._typeなどとして値を保持する必要がなくなる。
Firefox上では、EventListenerという名前はDOM2 EventsのEventListenerインタフェースとして、既に使われているみたい。
複数の同一の EventListener が、同じ EventTarget に同じ引数で登録された場合、重複するインスタンスは反映されません。EventListener が 2 度呼び出されることはなく、重複するインスタンスは反映されないので、removeEventListener で手動で削除する必要はありません。
DOM:element.addEventListener - MDC
イベントターゲット上にある現在のどのイベントリスナーも指定していない引数付きの removeEventListener は、何の効果もありません。
DOM:element.removeEventListener - MDC
イベントリスナは関数(というより、EventListenerインタフェース)単位で管理されているようで、連続でonしても1度しか実行されず、onしていない状態でoffしても特にエラーにはならない。
なので、状態を記憶して実行を制御しなくてもOK。
コンストラクタ関数は別のオブジェクトを返り値として返すことも可能で、その場合は返されたオブジェクトがnew式の値となる。thisの値であったオブジェクトは破棄される。
JavaScript 第5版 - 9章 クラスとコンストラクタとプロトタイプ(1) - (DxD)∞
newをハッタリに使える。結果は関数呼び出しのときと同じ。
var xp = null;
(xp = document.evaluate('//a/@href', document, null, XPathResult.STRING_TYPE, xp)).stringValue
// -> "http://mayokara.info/note/"
(xp = document.evaluate('//a/@href', document, null, XPathResult.STRING_TYPE, xp)).stringValue
// -> "http://mayokara.info/note/http://mayokara.info/note/"
Firefox2では増えないんだけど、Firefox3だと増える。
きちんと調べたわけではないけど、どうもXPathResult.STRING_TYPEのときだけっぽい。
不具合?
JavaScript: $g - mayokara note
使い回さないように戻した。
var box = document.getBoxObjectFor(elem); // 上端の絶対座標 box.y elem.getBoundingClientRect().top + window.scrollY // 下端の絶対座標 box.y + box.height elem.getBoundingClientRect().bottom + window.scrollY // 左端の絶対座標 box.x elem.getBoundingClientRect().left + window.scrollX // 右端の絶対座標 box.x + box.width elem.getBoundingClientRect().right + window.scrollX
document.getBoxObjectForの値が整数なのに対して、element.getBoundingClientRectの値は小数になる。
また、document.getBoxObjectForはborderを含むのに対し、element.getBoundingClientRectはborderを含まない(?)。
というわけで、draggable_textarea.user.js更新。
SITEINFOなしで動くAutoPagerize的な何か。
Greasemonkey: nisefastforward5.user.js - mayokara note
nisefastforward5.user.jsと同じく、以下の順で探索。
@rel="next"が存在せず、@rel="prev"のみが存在するときは進行方向を逆にする(Twitterなど)。
JavaScript: pageElementの推定 - mayokara note
これの「親要素も使う」版を手直ししたものを採用。
親・子ノードとの描画領域比を使う。
ちょっと重いかも。
microformatsが見つかったときは、それを利用する。
hAtom、xFolk、AutoPagerize独自形式に対応。
window.AutoPagerize.addDocumentFilter、window.AutoPagerize.addFilterを実装。