はてなキーワード: Prototypeとは
JavaScript って生き物っぽいって思ったのがきっかけだった。
なんか菌?に遺伝子いれてたんぱく質を生産させるやつ? Function は菌の細胞膜で prototype は遺伝子で、だから prototype に全然関係ない違う生物の遺伝子を生きてる菌に入れちゃったり。そうすると全然ちがうたんぱく質が生産されたり。prototype にべべーっとコピーして追加するのなんてまさしくそれっぽい。
だってプロトタイプベースって、生き物しかいない世界じゃない?基本的に。インスタンスってのは生き物じゃない設計図があってそれにしたがって出来た生き物がインスタンスってイメージあんだけど。プロトタイプベースの世界にはそんな設計図も生き物じゃないものもないよね?なのにわざわざインスタンスっていうのに何か違和感?ご都合主義的なもの感じる。クラスは型で、インスタンスを実体だとかなんとかって氾濫してるせいかな。多分この辺の用語が JavaScript をわかりにくくさせてる気がする。
僕の感覚では、オブジェクトってのは生き物で、クラスベースってのは神が設計図に基づいて生き物を生産してる世界で、インスタンスベースってのは生き物が生き物を複製してる世界のイメージだ。多分、原始の生物はインスタンスベースみたいな世界で、海の中にうようよしてたんだろうな、とか。
オブジェクトじゃないものは、生き物じゃない死んでるたんぱく質や RNA の破片みたいな。それだけじゃなにもできないみたいな。それだけじゃ命がないから、生き物の殻に詰めるってのが JavaScript のコンストラクタのイメージ。
Perl の bless したらこれはもう命入ったよ生き物だからねっあとは勝手にしてねってのも、Python の名前空間さえあればなんとかなるよねってのも、JavaScript のハッシュさえあれば世界作れるよねってのも、みんなどこか似ている。ちゃんと OOP を理解できてるかは別としてもこの三つはわりとすぐやりたいことができた。昔 Java の本を買ってきて挫折したのにくらべたら、なぜかずっとわかりやすかった。(bless という命名はすごく洒落てる)
全然関係ないけど、Django の日本語リファレンスは何か萌える。ラクダ本の日本語訳はむかつくのに。
プログラミングを始めたばっかりの時は、なんだか難しい用語の意味を理解しないと OOP がわからないと思ってた。それは僕らの住んでる世界とは全然関係のないプログラミングの技術ってやつだと思ってた。
でも多分違う。
世界が動く仕組みさえあれば、あとは作り手に世界の成り立ちを抽象化する表現力さえあれば、世界は勝手に表現されていくし、動き出してく。たまたま僕らの世界はオブジェクトなもので溢れていて、プログラミング言語が進化すれば世界に似るのも当然だろう。いや逆か。プログラミング言語が世界に似てきたから、オブジェクトなんていう世界に似た概念が出てきたってことか。なんだか難しい用語ってのは、その表現の一部分の技術に名前をつけてるだけなんだな、と。例えば何とか歌唱法や何々画法とか何とかレトリックとかパースの取り方みたいなのと同じ。それは表現を理解する手助けにはなるけど、その意味を知る事がイコール表現力をあげることにはならないんだよね。これに気づくのに遠回りしすぎたなあ。
(知識を得るだけで、100% 還元される人もいるかもしれないけど、そんなのは一部の天才だけだと思う。殆どの凡人はそうはいかない。とはいえ、元の錬度が低ければ、コツをいくつか教わるだけでいきなりうまくいくこともある。ただ、それをまるまんま実力だと思うのは、どんな分野でも危険だ。恋愛テクニックやらを必死に読んでる連中が男女間の深い人間関係を上手くやれてるとはちょっと想像できない!)
プログラミングで表現力を上げるにはどうすればいいんだろう。きっと他と同じだろうな。いい表現を沢山味わって、世界をよく観察して、どう成り立ってるかどう動いてるか、私達はそれをどう認知しているのか、考えることかもしれない。漫画家を志す人が美術解剖学を学んだり、優れた画家が絵筆で世界を生々しく描写するように、優れたプログラマは世界のなりたちをプログラムに写し取ったり、世界の仕組みを作る事が出来るのだと思う。
http://anond.hatelabo.jp/20110316202255
亀仙流やつ鶴仙流など、世の中にはいくつかの流派があり、それぞれ カメハメ波やドドン波、舞空術などの技(メソッド)がある。 実際に技を使う場合、技を覚えているZ戦士(インスタンス)が必要。
クラス = 流派
メソッド = 技
インスタンス = Z 戦士
というのはおもしろいと思うし, 例えばゲームを作るなら実際にそういう実装になると思う.
例)セルを作りましょう。 class Cell extends Goku,Veget,Picoro,Tenshinhan,Kuririn{ .... } cell_inst = new Cell(); cell_inst.shotKienzan(); //Kuririnをextendsしているので気円斬が使えます。
しかし, ここではクラス = Z 戦士になってしまっているので, 混乱を招くだろう.
むしろ, 「JavaScript における prototype」 に絞って説明するのはどうだろう.
(ついでに「撃つ」の現在形は shot でなく shoot ですね)
var Goku = function () {};
Goku.prototype.shootKamehameha = function () {
console.log("波!!!");
};
var goku = new Goku;
goku.shootKamehameha(); // 波!!!
var Gohan = function () {};
Gohan.prototype = new Goku;
var gohan = new Gohan;
gohan.shootKamehameha(); // 波!!!
そしてセルによる吸収は, 動的な継承として考えるのがより自然だろう.
var Goku = function () {};
Goku.prototype.shootKamehameha = function () {
console.log("波!!!");
};
var Vegeta = function () {};
Vegeta.prototype.shootBigBangAttack = function () {
console.log("ビッグバンアタック!!!");
};
var Cell = function () {};
// 吸収メソッド
Cell.prototype.absorb = function (target) {
for (var method in target) {
this[method] = target[method];
}
};
var goku = new Goku;
var vegeta = new Vegeta;
var cell = new Cell;
cell.absorb(goku); // 悟空を吸収
cell.absorb(vegeta); // ベジータを吸収
cell.shootKamehameha(); // 波!!!
cell.shootBigBangAttack(); // ビッッグバンアタック!!!
そして次にクロージャの使用例として挙げられた次の例.
例)連続エネルギー波 var shotRenzokuEnergy = function( count ){ var shotEnergy = function(){ //エネルギー波を放ちます }; for(var i=0;i<count;i++){ shotEnergy(); } };
この実装では, shotRenzokuEnergy を実行するたびに shotEnergy が毎回定義されてしまい, 非効率である.
以下のように書き換えることで, shootEnergy の定義は, shootRenzokuEnergy の定義時の 1 回のみとなる.
var shootRenzokuEnergy = (function () {
var shootEnergy = function () {
console.log("エネルギー波!!!");
};
return function (count) {
for (var i = 0; i < count; i++) {
shootEnergy();
}
};
})();
shootRenzokuEnergy(10); // エネルギー波!!! x 10
メンバメソッドとは違うもの。JavaScript では
Public なメンバメソッド → prototype チェインなどで付加した関数
となっている。
わざわざ外に出して関数化するほどのことでもないよな、とか
この関数からしか呼ばないのに、並列に関数を置きたくないな、とか思うことがあるでしょう。
JavaScript ならこんな思いに見事に答えてくれます。
たとえば個人情報が云々なので文字列のマスク処理を作ろうとしましょう。
String.prototype.mask = function() { var maskedText = ""; for(var ix = 0; ix < this.length; ix++){ maskedText += mask1(this.substring(ix, 1)); } return maskedText; function mask1(character) { var maskedCharacter = ""; swith(chr) { case 数字: 処理A, 個別処理 case 英字: 処理B, 個別処理 case 全数字: 処理A, 個別処理 case 全英字: 処理B, 個別処理 case ひらがな: 処理C, 個別処理 case カタカナ: 処理C, 個別処理 case 漢字: 処理D, 個別処理 default: 未処理 } return maskedCharacter; } };
こういうメソッドを作った時、処理A、処理B、処理Cは冗長な処理になっているわけです。
個別処理があるのでbreakしなければいいや、というわけでもありません。
しかしこの処理A,B,Cはこの関数外に置くような処理でもないわけです。
この関数内でしか使いませんし、むしろ使って欲しくないわけです。
function mask1(character) {
var maskedCharacter = "";
swith(chr) {
case 数字:
shoriA(), 個別処理
case 英字:
shoriB(), 個別処理
case 全数字:
shoriA(), 個別処理
case 全英字:
shoriB(), 個別処理
case ひらがな:
shoriC(), 個別処理
case カタカナ:
shoriC(), 個別処理
case 漢字:
処理D, 個別処理
default:
未処理
}
return maskedCharacter;
function shoriA() { 処理A }
function shoriB() { 処理B }
function shoriC() { 処理C }
}
こう書けるのです。
JavaScript で一番好きなのはこの内部関数です。
少し遅れた感があるけど、解いてみた。
出力がテキストでないけど・・・。
仕事の合間を使ってやったものの、昼前に始めたのが5時頃にようやくできる程度。
これを25分とは尋常じゃないな、大口叩くだけあってよっぽど優秀なんだろう。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis"> <meta http-equiv="Content-Language" content="ja"> <meta http-equiv="Content-Script-Type" content="text/javascript"> <meta http-equiv="Content-Style-Type" content="text/css"> <style type="text/css"> <!-- pre { font-family: monospace; } --> </style> <script type="text/javascript"> <!-- window.onload = function() { var q = new Map(); q.load("maptest.txt"); q.search(); var answer = document.getElementsByTagName("pre").item(0); var answerText = "\r\n"; for(var ix = 0; ix < q.route.length; ix++) { answerText += q.route[ix].join("") + "\r\n"; } answer.firstChild.data = answerText; alert("終了しました。"); }; /** マップオブジェクト */ function Map() { this.ymap = []; this.route = []; } //マップの読み込み Map.prototype.load = function(filePath) { //ファイルシステム var fileSystem = new ActiveXObject("Scripting.FileSystemObject"); //ファイル読み込み var file = fileSystem.OpenTextFile(filePath); while(!file.AtEndOfLine) { var fileBuffer = file.ReadLine(); this.ymap.push(fileBuffer.split("")); } file.Close(); fileSystem = null; }; //マップの探索 Map.prototype.search = function() { var that = this; //マップコピー var ymap = this.ymap.concat(); for(var y = 0; y < ymap.length; y++) { ymap[y] = ymap[y].concat(); for(var x = 0; x < ymap[y].length; x++) { if(ymap[y][x] == "S") var start = new MapNode(y, x); if(ymap[y][x] == "G") var goal = new MapNode(y, x); } } var openList = []; var closeList = []; start.costf = start.distance(goal); openList.push(start); //経路探索 while(openList.length > 0) { var node = openList.shift(); //探索終了 if(goal.equal(node)) { createRoute(node); break; } closeList.push(node); //隣接ノードの作成 var tonari = []; if( ymap[node.positionY][node.positionX - 1] == " " || ymap[node.positionY][node.positionX - 1] == "G" ) tonari.push(new MapNode(node.positionY, node.positionX - 1, node)); if( ymap[node.positionY - 1][node.positionX] == " " || ymap[node.positionY - 1][node.positionX] == "G" ) tonari.push(new MapNode(node.positionY - 1, node.positionX, node)); if( ymap[node.positionY][node.positionX + 1] == " " || ymap[node.positionY][node.positionX + 1] == "G" ) tonari.push(new MapNode(node.positionY, node.positionX + 1, node)); if( ymap[node.positionY + 1][node.positionX] == " " || ymap[node.positionY + 1][node.positionX] == "G" ) tonari.push(new MapNode(node.positionY + 1, node.positionX, node)); //隣接ノードの検索 for(var tx = 0; tx < tonari.length; tx++) { var openIn = false; var closeIn = false; tonari[tx].cost = node.cost + 1; var costf = tonari[tx].cost + tonari[tx].distance(goal); tonari[tx].costf = costf; //オープンリストから検索し入れ替える。 for(var ox = 0; ox < openList.length; ox++) { if(tonari[tx].equal(openList[ox])) { openIn = true; if(costf < openList[ox].costf) { openList.splice(ox, 1); push(openList, tonari[tx]); } break; } } //クローズリストから検索し、オープンリストへ移す。 for(var cx = 0; cx < closeList.length; cx++) { if(tonari[tx].equal(closeList[cx])) { closeIn = true; if(costf < closeList[cx].costf) { closeList.splice(cx, 1); push(openList, tonari[tx]); } break; } } //どちらにもない場合、オープンリストへ追加する。 if(!openIn &amp;&amp; !closeIn) push(openList, tonari[tx]); } } //適切な位置に追加する。 function push(array, item) { for(var ix = 0; ix < array.length; ix++) { if(item.costf < array[ix].costf) { array.splice(ix, 0, item); return; } } array.push(item); } //ルートマップの作成 function createRoute(lastNode) { var node = lastNode.parent; while(node.parent) { ymap[node.positionY][node.positionX] = "$"; node = node.parent; } that.route = ymap; } }; /** マップノード */ function MapNode(y, x, parentNode) { this.positionY = y; this.positionX = x; this.parent = parentNode; this.cost = 0; this.costf = 0; } //同一ノードかチェックする。 MapNode.prototype.equal = function(targetNode) { if( this.positionY == targetNode.positionY &amp;&amp; this.positionX == targetNode.positionX ) return true; return false; }; //直線距離を求める。 MapNode.prototype.distance = function(targetNode) { sabunY = this.positionY - targetNode.positionY; sabunX = this.positionX - targetNode.positionX; return sabunY ^ 2 + sabunX ^ 2; }; // --> </script> <title>経路探索:A*</title> </head> <body> <pre>&nbsp;</pre> </body> </html>
なんかPerlのblessっぽい。
JavaScriptのnewって本当にいらない子?(http://d.hatena.ne.jp/jdg/20090706/1246840565)
というよりperlのnewっぽい。なぜか。
classでクラスを定義してnewでインスタンスを生成する言語を「一般的オブジェクト指向言語」とすると、
つまり、javascriptでnewを(直接)使わず、class(のようなもの)を作ればperlっぽくなる。
オブジェクトを作る。オブジェクトを作るには3つの動作が必要である。
通常は言語仕様でこれらを行う"new"という命令が用意されている。しかし、必ずしも必要な物ではない。perlでは言語仕様としてはnewが用意されていない。new関数が存在するのはコーディング規約に従っているからに過ぎない。代わりにblessが用意されている。なぜこのようになっているのか。理由はいたって簡単だ。perlのオブジェクトの実態はリファレンスだ。初期化を行うコンストラクタはどの道定義せねばならない。だから必要なのはリファレンスとパッケージを結びつけるおまじないblessだけだ。コンストラクタで好きなリファレンスを用意し、好きなように初期化してblessすればよい。コンストラクタの名前はコーディング規約でnewと決めた。一方javascriptはnewを用意した。{}でオブジェクトは作れるし、どの道コンストラクタは作る必要があるのに。
オブジェクトとクラスを結びつける。しかし、javascriptはクラスを持たないので必要はない。代わりに必要なのは、継承元との結びつき、プロトタイプチェーンの構築だ。
既存のクラスの性質や振る舞いを流用する。default状態を与える。一般的オブジェクト指向言語ではクラス定義時に継承元となるクラスを指定する。javascriptではクラスの代わりにオブジェクトを指定する。
クラスとはオブジェクトの性質・振る舞いの定義だ。しかし、ダック・タイピングではオブジェクトの性質や振る舞いはオブジェクトの持つメンバにより決まるため、そのような環境ではオブジェクトに初期値と継承関係を与えるのが主な仕事となる。
コンストラクタはオブジェクトの初期化を行う。javascriptではクラスがないため継承とコンストラクタによりオブジェクトが初期化される。
var object = function(o) { var F = function() {}; F.prototype = o.prototype; return new F; };JavaScriptのnewって本当にいらない子?(http://d.hatena.ne.jp/jdg/20090706/1246840565)
個人的には
var object = function(o) { var F = function() {}; F.prototype = o; return new F; };
で良いんじゃね?って思う。
更に、コレでは初期化しないから
var object = function(o, n) { var F = function() {}; F.prototype = o; f = new F; if (n) for (var i in n) f[i] = n[i]; return f; };
みたいな。
さらにせっかくだからメソッドにして
var object = function(o, n) { var F = function() {}; F.prototype = o; f = new F; if (not f.inherit) f.inherit = function(n) {object(this, n)}; if (n) for (var i in n) f[i] = n[i]; return f; };
とか。
ところでサー
javascriptってラッパー作りやすくていいよね。
名前を変えずにラップ出来るから好き。
クラスもインスタンスもメソッドも関数もオーバーライドしてラップして、好き勝手出来るから好き。
(function(){ var origin = hoge.prototype.foo; hoge.prototype.foo = function(){ ... }; hoge.prototype.foo.origin = origin; })();
perlはオーバーライドできるけど、元のメソッド呼べなくなる。すべてのインスタンスに影響する(たしか)。チョイめんどい。
use hoge; package hoge; sub foo { ... } package main; ...
他の言語では、どんな技がありますか?
[追記]
\&hoge::foo で元のコードのリファレンス取れたっけ?
すっかり忘れてる。
yutori.2ch.net.hp.infoseek.co.jp/w/r/e/wrestleangel/post2ch.swf#host=yutori.2ch.net
ここ↑にあるやつ。
解説よろしく。
movie 'post2ch.swf' { // flash 8, total frames: 17, frame rate: 12 fps, 320x320 px frame 1 { System.useCodepage = true; nret = function (k, v) { return (flash.external.ExternalInterface.call('d', k, v)).toString(); }; host2ch = 'tmp6.2ch.net'; i = _url.indexOf('://'); if (-1 < i) { host2ch = _url.substring(i + 3); } i = host2ch.indexOf('.2ch.net'); if (-1 < i) { host2ch = host2ch.substring(0, i + 8); } path2ch = '/test/bbs.cgi?guid=ON'; l = new LoadVars(); i = _url.indexOf('#'); u = ''; if (0 < i) { u = _url.substring(i + 1); } LoadVars.prototype.sendNoEnc = function (url, target, method) { LoadVars.prototype._toString = LoadVars.prototype.toString; LoadVars.prototype.toString = function () { return unescape(this._toString()); }; ASSetPropFlags(LoadVars.prototype, '_toString', 3); this.send(url, target, method); LoadVars.prototype.toString = LoadVars.prototype._toString; }; ASSetPropFlags(LoadVars.prototype, 'sendNoEnc', 3); } frame 2 { _root.nowtime = null; _root.secondpost = null; _root.FROM = null; _root.mail = null; _root.MESSAGE = null; _root.subject = null; _root.ng = null; } frame 3 { (flash.external.ExternalInterface.call('c')).toString(); } frame 9 { if (_root.nowtime == null) { if (!_root.ng) { gotoAndPlay(3); } else { this.stop(); } } } frame 10 { if (_root.nowtime == null) { gotoAndPlay(3); } nowtime = _root.nowtime; l.addRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); l.hana = 'mogera'; l.time = '1180000000'; if (l.time < nowtime) { l.time = nowtime; } l.key = ''; l.bbs = 'kitchen'; l.MESSAGE = '%82%D3%82%F1%82%C7%82%B5'; l.subject = '%82%D3%82%F1%82%C7%82%B5'; l.mail = ''; l.FROM = '%82%D3%82%F1%82%C7%82%B5'; l.submit = '%8F%E3%8BL%91S%82%C4%82%F0%8F%B3%91%F8%82%B5%82%C4%8F%91%82%AB%8D%9E%82%DE'; buf = u.split('&'); i = 0; goto 623; for (;;) { ++i; label 623: if (i >= buf.length) break; a = buf[i].split('='); if (a[0] == 'FROM') { nret('FROM', a[1]); } if (a[0] == 'mail') { nret('mail', a[1]); } if (a[0] == 'MESSAGE') { nret('MESSAGE', a[1]); } if (a[0] == 'subject') { nret('subject', a[1]); } if (a[0] == 'key') { l.key = a[1]; } if (a[0] == 'time') { l.time = a[1]; } if (a[0] == 'bbs') { l.bbs = a[1]; } if (a[0] == 'host') { host2ch = a[1]; } if (a[0] == 'path') { path2ch = a[1]; } } } frame 16 { if (_root.nowtime == null) { gotoAndPlay(3); } if (_root.FROM != null) { l.FROM = _root.FROM; } if (_root.mail != null) { l.mail = _root.mail; } if (_root.MESSAGE != null) { l.MESSAGE = _root.MESSAGE; } if (_root.subject != null) { l.subject = _root.subject; } if (l.key != '') { l.subject = ''; } if (l.subject != '') { l.key = ''; } l.sendNoEnc('http://' + host2ch + path2ch, '_2ch', 'POST'); } frame 17 { if (_root.secondpost != null) { _root.secondpost = null; gotoAndPlay(4); } _root.nowtime = null; gotoAndPlay(2); } } ||>
地味になって残念
結局概要表示機能追加した。unsafeWindow使いまくり。大丈夫かいな。
// ==UserScript== // @name Hatena Bookmark Tree Expander // @namespace http://anond.hatelabo.jp/ // @include http://b.hatena.ne.jp/entry/* // ==/UserScript== // <div class="info"> // <ul id="similar_entries" class="bookmarklist"> // <li></li> // </ul> // </div> // <div class="info"> // <ul id="referred_entries" class="bookmarklist"> // <li id="referred-entry-\d+"></li> // </ul> // </div> // <div class="info"> // <ul id="relation_diary" class="bookmarklist"> // <li id="diary-{id}-\d+"></li> // </ul> // </div> (function() { function main() { loadBookmarkCommentViewer(); similar.prototype.rootAppend(); referred.prototype.rootAppend(); } function HBTM(target) { this.target = target; this.targetXPath = "//ul[@id='"+target+"']/li"; this.targetRegExp = new RegExp('<ul id="'+target+'"(.|\\s)*?</ul>'); } HBTM.prototype = { openIcon: '<img width="15" height="15" class="icon" style="opacity: 0.6" src="http://anond.hatelabo.jp/images/common/open.gif"/>', closeIcon: '<img width="15" height="15" class="icon" style="opacity: 0.6" src="http://anond.hatelabo.jp/images/common/close.gif"/>', loadingIcon: '<img width="13" height="13" class="icon" src="http://anond.hatelabo.jp/images/common/loading.gif"/>', commentIcon: function(url) { return '<img class="hatena-bcomment-view-icon" src="http://r.hatena.ne.jp/images/popup.gif" onclick="iconImageClickHandler(this, \''+url+'\', event);">' }, create: function() { this.comment = document.createElement("span"); this.comment.innerHTML = this.commentIcon($X("string(descendant::a/@href)", this.node).value()); this.open = document.createElement("a"); this.open.href = "javascript:void(0)"; this.open.innerHTML = this.openIcon; this.close = document.createElement("a"); this.close.href = "javascript:void(0)"; this.close.innerHTML = this.closeIcon; this.close.style.display = "none"; this.loading = document.createElement("span"); this.loading.innerHTML = this.loadingIcon; this.loading.style.display = "none"; this.node.appendChild(this.comment); this.node.appendChild(document.createTextNode(" ")); this.node.appendChild(this.open); this.node.appendChild(this.close); this.node.appendChild(this.loading); this.open.addEventListener("click", bind(this.openAct, this), false); this.close.addEventListener("click", bind(this.closeAct, this), false); }, openAct: function() { this.open.style.display = "none"; if (this.tree) { this.tree.style.display = "block"; this.close.style.display = "inline"; } else { this.loading.style.display = "inline"; this.load(); } }, closeAct: function() { if (this.tree) { this.tree.style.display = "none"; this.close.style.display = "none"; this.open.style.display = "inline"; } }, load: function() { var url = $X("string(descendant::a[starts-with(@href, '/entry/')]/@href)", this.node).value(); GM_xmlhttpRequest({ method: "GET", url: "http://b.hatena.ne.jp"+url, onload: bind(this.loadCallback, this) }); }, loadCallback: function(result) { var match = result.responseText.match(this.targetRegExp); if (match) { var sandbox = document.createElement("div"); sandbox.innerHTML = match[0].replace(this.target,""); this.tree = sandbox.firstChild; } else { this.tree = document.createElement("ul"); } this.append(); this.loading.style.display = "none"; this.close.style.display = "inline"; }, append: function() { this.tree.style.backgroundColor = "transparent"; this.tree.style.listStyleType = "circle"; this.node.appendChild(this.tree); $X("li", this.tree).each(function(n) { var a = $X("a",n).node(); var c = $X("count(//li/a[@href='"+a.href+"'])").value(); if (c > 1) n.parentNode.removeChild(n); }); $X("li", this.tree).each(bind(function(node){new this.constructor(node)}, this)); }, rootAppend: function() { $X(this.targetXPath).each(bind(function(node){new this.constructor(node)}, this)); } }; function similar(node) { this.node = node; this.create(); } similar.prototype = new HBTM("similar_entries"); similar.prototype.constructor = similar; function referred(node) { this.node = node; this.create(); } referred.prototype = new HBTM("referred_entries"); referred.prototype.constructor = referred; function loadBookmarkCommentViewer() { var head = document.getElementsByTagName("head")[0]; var script = document.createElement("script"); script.type = "text/javascript"; script.src = "http://b.hatena.ne.jp/js/BookmarkCommentViewerAllInOne.1.2.js"; head.appendChild(script); var css = document.createElement("link"); css.rel="stylesheet"; css.href="http://d.hatena.ne.jp/css/base.css"; css.type="text/css"; css.media="all"; head.insertBefore(css, head.firstChild); window.addEventListener("load",function(){ var BCV = unsafeWindow.BookmarkCommentViewer; BCV.options['screenshot'] = true; var asyncCommnetView = BCV.asyncCommnetView; BCV.asyncCommnetView = function(url, onCompleteCallback) { var div = asyncCommnetView(url, function(){ onCompleteCallback.apply(this, arguments); new unsafeWindow.Ten.XHR("http://b.hatena.ne.jp/entry/rss/"+url, {}, function(result) { if (! result.responseText.match(/<description>(.*?)<\/description>/)) return; if (! RegExp.$1) return; // var desc = document.createTextNode("desc: "+RegExp.$1); var desc = document.createElement("li"); desc.appendChild(document.createTextNode("desc: "+RegExp.$1)); div.lastChild.insertBefore(desc,div.lastChild.getElementsByTagName("li")[0]); }); }); return div; }; BCV.asyncCommnetView.origin = asyncCommnetView; }, false); } function bind(f,o) {return function() {return f.apply(o, arguments)}} function $X(xpath, context) { if (!(this instanceof $X)) return new $X(xpath, context); this.xpath = xpath; this.context = context || document; } $X.prototype = { evaluate: function() { var result = document.evaluate(this.xpath, this.context, null, this.type, null); switch (result.resultType) { case XPathResult.STRING_TYPE : return result.stringValue; case XPathResult.NUMBER_TYPE : return result.numberValue; case XPathResult.BOOLEAN_TYPE: return result.booleanValue; case XPathResult.FIRST_ORDERED_NODE_TYPE: return result.singleNodeValue; } return result; }, node: function() { this.type = XPathResult.FIRST_ORDERED_NODE_TYPE; return this.evaluate(); }, value: function() { this.type = XPathResult.ANY_TYPE; return this.evaluate(); }, each: function(func) { this.type = XPathResult.ORDERED_NODE_SNAPSHOT_TYPE; var result = this.evaluate(); for (var i=0; i<result.snapshotLength; i++) func(result.snapshotItem(i)); } }; main(); })();
javascriptでスーパークラスのメソッドを簡単に呼び出したかった。それだけだった。
var Class = inherit(SuperClass, {hoge: ...});
作ったクラスはprototypeに、第二引数のオブジェクトがコピーされたスーパークラスのインスタンスを持つ。
第一引数がnullだと、スーパークラスにObjectを用いる。つまり、
var Class = inherit(null, {hoge: ...});
は
var Class = inherit(Object, {hoge: ...});
と同等となる。
また、第一引数が"prototype"をメンバに持たない普通のオブジェクト、つまり、
var Class = inherit({hoge: ...});
だと
var Class = inherit(Object, {hoge: ...});
と同等となる。
var obj = new Class({hoge: ...});
でインスタンスを作ると、引数のオブジェクトのコピーを持つオブジェクトとなる。
また、メソッド"initialize"が自動的に実行される。
ただし、コンストラクタに引数を渡さなかった場合は、initializeは実行されない。
this.superapply(arguments);
としてスーパークラスのメソッドを呼べる。第一引数は呼び出すメソッドの引数の配列とする。
このとき、呼び出し側のメソッドはコンストラクタやinheritでオーバーライドしたメソッドでなくてはならない。これは呼び出し側のメソッド名を記録する必要があるためである。
そうでない場合は第二引数にメソッド名を渡す必要がある。
var obj = new Class({}); obj.foo = function(){ this.superapply(arguments); // X this.superapply(arguments, "foo"); // O };
<html><head> <script type="text/javascript"> function inherit(superclass, override) { if (!superclass) superclass = Object; if (! "prototype" in superclass) { override = superclass; superclass = Object; } var that; var func; function superapply(arg, name) { var prev = {that: that, func: func}; try { var my = this.superapply; if (!arg) arg = []; if (!name) name = arguments.callee.caller.caller.methodName; if (that && func && (!name || name == func.methodName)) { that = that.superapply.obj; name = func.methodName; } else if (name) { that = my.obj; func = arguments.callee.caller.caller; func.methodName = name; } else { throw new Error("methodName is null"); } var result; if (func === that[name]) { result = this.superapply(arg, name); } else { func = that[name]; func.methodName = name; result = func.apply(this, arg); } } finally { that = prev.that; func = prev.func; } return result; }; var prototype = new superclass(); prototype.superapply = function(){superapply.apply(this, arguments)}; prototype.superapply.obj = superclass.prototype; if (override) for (var i in override) { prototype[i] = override[i]; if (typeof override[i] == "function") prototype[i].methodName = i; } var subclass = function(obj) { this.superapply = function(){superapply.apply(this, arguments)}; this.superapply.obj = prototype; if (obj) { for (var i in obj) { this[i] = obj[i]; if (typeof obj[i] == "function") this[i].methodName = i; } this.initialize(); } }; subclass.prototype = prototype; subclass.prototype.constructor = subclass; return subclass; } var C1 = inherit(Object, { fn: "C1", initialize: function(){ alert("C1.initialize"); this.second(this.fn); }, second: function(a){ alert("C1.second: "+a); } }); var C2 = inherit(C1, { fn: "C2", initialize: function(){ alert("C2.initialize"); this.superapply(); // }, //second: // function(a){ // alert("C2.second: "+a); // this.superapply([a]); } }); var C3 = new C2({ fn: "C3", //initialize: // function(){ // alert("C3.initialize"); // this.superapply(); // }, second: function(a){ alert("C3.second: "+a); this.superapply([a]); } }); </script> </head><body> </body><html>
methodNameなんとかならんもんか。
<html><head><title>Hello JavaScript World!</title><style type="text/css"> <!-- .select { margin-left: 30px; padding: 0 2px; width: 6em; border: dotted 1px; } .select p { margin: 2px; } --> </style></head><body><script type="text/javascript"> <!-- // step 1 : output text document.write("Hello world!"); // step 2 : output html document.write("<br/><b>Hello javascript world!</b>"); // step 3 : manipulate DOM var p1 = document.createElement("p"); p1.appendChild(document.createTextNode("Hello DOM world!")); document.body.appendChild(p1); // step 3 : interactive, using function, event handler function solid() { this.style.borderStyle="solid"; } var p2 = document.createElement("p"); p2.appendChild(document.createTextNode("Hello interactive world!")); document.body.appendChild(p2); p2.addEventListener("click", solid, false); // not solid() // step 4 : using object, prototype, closure function P(str) { this.str = str; } P.prototype.regist = function(parent){ this.elem = document.createElement("p"); this.elem.appendChild(document.createTextNode(this.str)); parent.appendChild(this.elem); var self = this; this.elem.addEventListener("click", function(){self.act()}, false); // otherwise // this.elem.helloworld = this; // this.elem.addEventListener("click", function(){this.helloworld.act()}, false); // bad way // this.elem.addEventListener("click", this.act, false); // this.elem.addEventListener("click", function(){this.act()}, false); }; P.prototype.act = function(){}; var p3 = new P("Hello prototype world!"); p3.act = function(){ if (this.elem.style.borderStyle == ""){ this.elem.style.borderStyle = "solid"; } else { this.elem.style.borderStyle = ""; } }; p3.regist(document.body); // step 5 : inheritance function SELECT(parent, str) { this.str = str; this.regist(parent); } SELECT.prototype = new P(); SELECT.prototype.act = function(){ p4.elem.style.borderStyle = this.str; p4.div.style.display = "none"; } var p4 = new P("Hello world!"); p4.div = document.createElement("div"); p4.div.className = "select"; p4.div.style.display = "none"; p4.select = [ new SELECT(p4.div, "none"), new SELECT(p4.div, "dotted"), new SELECT(p4.div, "solid") ]; p4.act = function(){ p4.div.style.display = "block"; }; p4.regist(document.body); document.body.appendChild(p4.div); //--> </script></body></html>
/* Ten */
if (typeof(Ten) == 'undefined') {
Ten = {};
}
Ten.NAME = 'Ten';
Ten.VERSION = 0.06;
/* Ten.Class */
Ten.Class = function(klass, prototype) {
if (klass && klass.initialize) {
var c = klass.initialize;
} else if(klass && klass.base) {
var c = function() { return klass.base[0].apply(this, arguments) };
} else {
var c = function() {};
}
c.prototype = prototype || {};
c.prototype.constructor = c;
Ten.Class.inherit(c, klass);
if (klass && klass.base) {
for (var i = 0; i < klass.base.length; i++) {
var parent = klass.base[i];
if (i == 0) {
c.SUPER = parent;
c.prototype.SUPER = parent.prototype;
}
Ten.Class.inherit(c, parent);
Ten.Class.inherit(c.prototype, parent.prototype);
}
}
return c;
}
Ten.Class.inherit = function(child,parent) {
for (var prop in parent) {
if (typeof(child[prop]) != 'undefined' || prop == 'initialize') continue;
child[prop] = parent[prop];
}
}
/*
// Basic Ten Classes
**/
/* Ten.JSONP */
Ten.JSONP = new Ten.Class({
initialize: function(uri,obj,method) {
if (Ten.JSONP.Callbacks.length) {
setTimeout(function() {new Ten.JSONP(uri,obj,method)}, 500);
return;
}
var del = uri.match(/\?/) ? '&' : '?';
uri += del + 'callback=Ten.JSONP.callback';
if (!uri.match(/timestamp=/)) {
uri += '&' + encodeURI(new Date());
}
if (obj && method) Ten.JSONP.addCallback(obj,method);
this.script = document.createElement('script');
this.script.src = uri;
this.script.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(this.script);
},
addCallback: function(obj,method) {
Ten.JSONP.Callbacks.push({object: obj, method: method});
},
callback: function(args) {
// alert('callback called');
var cbs = Ten.JSONP.Callbacks;
for (var i = 0; i < cbs.length; i++) {
var cb = cbs[i];
cb.object[cb.method].call(cb.object, args);
}
Ten.JSONP.Callbacks = [];
},
MaxBytes: 8000,
Callbacks: []
});
/* Ten.XHR */
Ten.XHR = new Ten.Class({
initialize: function(uri,opts,obj,method) {
if (!uri) return;
this.request = Ten.XHR.getXMLHttpRequest();
this.callback = {object: obj, method: method};
var xhr = this;
var prc = this.processReqChange;
this.request.onreadystatechange = function() {
prc.apply(xhr, arguments);
}
var method = opts.method || 'GET';
this.request.open(method, uri, true);
if (method == 'POST') {
this.request.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
}
var data = opts.data ? Ten.XHR.makePostData(opts.data) : null;
this.request.send(data);
},
getXMLHttpRequest: function() {
var xhr;
var tryThese = [
function () { return new XMLHttpRequest(); },
function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
];
for (var i = 0; i < tryThese.length; i++) {
var func = tryThese[i];
try {
xhr = func;
return func();
} catch (e) {
//alert(e);
}
}
return xhr;
},
makePostData: function(data) {
var pairs = [];
var regexp = /%20/g;
for (var k in data) {
var v = data[k].toString();
var pair = encodeURIComponent(k).replace(regexp,'+') + '=' +
encodeURIComponent(v).replace(regexp,'+');
pairs.push(pair);
}
return pairs.join('&');
}
},{
processReqChange: function() {
var req = this.request;
if (req.readyState == 4) {
if (req.status == 200) {
var cb = this.callback;
cb.object[cb.method].call(cb.object, req);
} else {
alert("There was a problem retrieving the XML data:\n" +
req.statusText);
}
}
}
});
/* Ten.Observer */
Ten.Observer = new Ten.Class({
initialize: function(element,event,obj,method) {
var func = obj;
if (typeof(method) == 'string') {
func = obj[method];
}
this.element = element;
this.event = event;
this.listener = function(event) {
return func.call(obj, new Ten.Event(event || window.event));
}
if (this.element.addEventListener) {
if (this.event.match(/^on(.+)$/)) {
this.event = RegExp.$1;
}
this.element.addEventListener(this.event, this.listener, false);
} else if (this.element.attachEvent) {
this.element.attachEvent(this.event, this.listener);
}
}
},{
stop: function() {
if (this.element.removeEventListener) {
this.element.removeEventListener(this.event,this.listener,false);
} else if (this.element.detachEvent) {
this.element.detachEvent(this.event,this.listener);
}
}
});
/* Ten.Event */
Ten.Event = new Ten.Class({
initialize: function(event) {
this.event = event;
},
keyMap: {
8:"backspace", 9:"tab", 13:"enter", 19:"pause", 27:"escape", 32:"space",
33:"pageup", 34:"pagedown", 35:"end", 36:"home", 37:"left", 38:"up",
39:"right", 40:"down", 44:"printscreen", 45:"insert", 46:"delete",
112:"f1", 113:"f2", 114:"f3", 115:"f4", 116:"f5", 117:"f6", 118:"f7",
119:"f8", 120:"f9", 121:"f10", 122:"f11", 123:"f12",
144:"numlock", 145:"scrolllock"
}
},{
mousePosition: function() {
if (!this.event.clientX) return;
return Ten.Geometry.getMousePosition(this.event);
},
isKey: function(name) {
var ecode = this.event.keyCode;
if (!ecode) return;
var ename = Ten.Event.keyMap[ecode];
if (!ename) return;
return (ename == name);
},
targetIsFormElements: function() {
var target = this.event.target;
if (!target) return;
var T = (target.tagName || '').toUpperCase();
return (T == 'INPUT' || T == 'SELECT' || T == 'OPTION' ||
T == 'BUTTON' || T == 'TEXTAREA');
},
stop: function() {
var e = this.event;
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
} else {
e.cancelBubble = true;
e.returnValue = false;
}
}
});
/* Ten.DOM */
Ten.DOM = new Ten.Class({
getElementsByTagAndClassName: function(tagName, className, parent) {
if (typeof(parent) == 'undefined') {
parent = document;
}
var children = parent.getElementsByTagName(tagName);
if (className) {
var elements = [];
for (var i = 0; i < children.length; i++) {
var child = children[i];
var cls = child.className;
if (!cls) {
continue;
}
var classNames = cls.split(' ');
for (var j = 0; j < classNames.length; j++) {
if (classNames[j] == className) {
elements.push(child);
break;
}
}
}
return elements;
} else {
return children;
}
},
removeEmptyTextNodes: function(element) {
var nodes = element.childNodes;
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
node.parentNode.removeChild(node);
}
}
},
nextElement: function(elem) {
do {
elem = elem.nextSibling;
} while (elem && elem.nodeType != 1);
return elem;
},
prevElement: function(elem) {
do {
elem = elem.previousSibling;
} while (elem && elem.nodeType != 1);
return elem;
},
scrapeText: function(node) {
var rval = [];
(function (node) {
var cn = node.childNodes;
if (cn) {
for (var i = 0; i < cn.length; i++) {
arguments.callee.call(this, cn[i]);
}
}
var nodeValue = node.nodeValue;
if (typeof(nodeValue) == 'string') {
rval.push(nodeValue);
}
})(node);
return rval.join('');
},
onLoadFunctions: [],
loaded: false,
timer: null,
addEventListener: function(event,func) {
if (event != 'load') return;
Ten.DOM.onLoadFunctions.push(func);
Ten.DOM.checkLoaded();
},
checkLoaded: function() {
var c = Ten.DOM;
if (c.loaded) return true;
if (document && document.getElementsByTagName &&
document.getElementById && document.body) {
if (c.timer) {
clearInterval(c.timer);
c.timer = null;
}
for (var i = 0; i < c.onLoadFunctions.length; i++) {
c.onLoadFunctions[i]();
}
c.onLoadFunctions = [];
c.loaded = true;
} else {
c.timer = setInterval(c.checkLoaded, 13);
}
}
});
/* Ten.Style */
Ten.Style = new Ten.Class({
applyStyle: function(elem, style) {
for (prop in style) {
elem.style[prop] = style[prop];
}
}
});
/* Ten.Geometry */
Ten.Geometry = new Ten.Class({
initialize: function() {
if (Ten.Geometry._initialized) return;
var func = Ten.Geometry._functions;
var de = document.documentElement;
if (window.innerWidth) {
func.getWindowWidth = function() { return window.innerWidth; }
func.getWindowHeight = function() { return window.innerHeight; }
func.getXScroll = function() { return window.pageXOffset; }
func.getYScroll = function() { return window.pageYOffset; }
} else if (de && de.clientWidth) {
func.getWindowWidth = function() { return de.clientWidth; }
func.getWindowHeight = function() { return de.clientHeight; }
func.getXScroll = function() { return de.scrollLeft; }
func.getYScroll = function() { return de.scrollTop; }
} else if (document.body.clientWidth) {
func.getWindowWidth = function() { return document.body.clientWidth; }
func.getWindowHeight = function() { return document.body.clientHeight; }
func.getXScroll = function() { return document.body.scrollLeft; }
func.getYScroll = function() { return document.body.scrollTop; }
}
Ten.Geometry._initialized = true;
},
_initialized: false,
_functions: {},
getScroll: function() {
if (!Ten.Geometry._initialized) new Ten.Geometry;
return {
x: Ten.Geometry._functions.getXScroll(),
y: Ten.Geometry._functions.getYScroll()
};
},
getMousePosition: function(pos) {
// pos should have clientX, clientY same as mouse event
if ((navigator.userAgent.indexOf('Safari') > -1) &&
(navigator.userAgent.indexOf('Version/') < 0)) {
return {
x: pos.clientX,
y: pos.clientY
};
} else {
var scroll = Ten.Geometry.getScroll();
return {
x: pos.clientX + scroll.x,
y: pos.clientY + scroll.y
};
}
},
getElementPosition: function(e) {
return {
x: e.offsetLeft,
y: e.offsetTop
};
},
getWindowSize: function() {
if (!Ten.Geometry._initialized) new Ten.Geometry;
return {
w: Ten.Geometry._functions.getWindowWidth(),
h: Ten.Geometry._functions.getWindowHeight()
};
}
});
/* Ten.Position */
Ten.Position = new Ten.Class({
initialize: function(x,y) {
this.x = x;
this.y = y;
},
subtract: function(a,b) {
return new Ten.Position(a.x - b.x, a.y - b.y);
}
});
/*
// require Ten.js
**/
/* Ten.SubWindow */
Ten.SubWindow = new Ten.Class({
initialize: function() {
var c = this.constructor;
if (c.singleton && c._cache) {
return c._cache;
}
var div = document.createElement('div');
Ten.Style.applyStyle(div, Ten.SubWindow._baseStyle);
Ten.Style.applyStyle(div, c.style);
this.window = div;
this.addContainerAndCloseButton();
document.body.appendChild(div);
if (c.draggable) {
this._draggable = new Ten.Draggable(div, this.handle);
}
if (c.singleton) c._cache = this;
return this;
},
_baseStyle: {
color: '#000',
position: 'absolute',
display: 'none',
zIndex: 2,
left: 0,
top: 0,
backgroundColor: '#fff',
border: '1px solid #bbb'
},
style: {
padding: '2px',
textAlign: 'center',
borderRadius: '6px',
MozBorderRadius: '6px',
width: '100px',
height: '100px'
},
handleStyle: {
position: 'absolute',
top: '0px',
left: '0px',
backgroundColor: '#f3f3f3',
borderBottom: '1px solid #bbb',
width: '100%',
height: '30px'
},
containerStyle: {
margin: '32px 0 0 0',
padding: '0 10px'
},
// closeButton: 'close.gif',
closeButton: 'http://s.hatena.com/images/close.gif',
closeButtonStyle: {
position: 'absolute',
top: '8px',
right: '10px',
cursor: 'pointer'
},
_baseScreenStyle: {
position: 'absolute',
top: '0px',
left: '0px',
display: 'none',
zIndex: 1,
overflow: 'hidden',
width: '100%',
height: '100%'
},
screenStyle: {},
showScreen: true,
singleton: true,
draggable: true,
_cache: null
},{
screen: null,
windowObserver: null,
visible: false,
addContainerAndCloseButton: function() {
var win = this.window;
var c = this.constructor;
var div = document.createElement('div');
win.appendChild(div);
Ten.Style.applyStyle(div, c.containerStyle);
this.container = div;
if (c.handleStyle) {
var handle = document.createElement('div');
Ten.Style.applyStyle(handle, c.handleStyle);
win.appendChild(handle);
this.handle = handle;
}
if (c.closeButton) {
var btn = document.createElement('img');
btn.src = c.closeButton;
btn.alt = 'close';
Ten.Style.applyStyle(btn, c.closeButtonStyle);
win.appendChild(btn);
new Ten.Observer(btn, 'onclick', this, 'hide');
this.closeButton = btn;
}
if (c.showScreen) {
var screen = document.createElement('div');
Ten.Style.applyStyle(screen, Ten.SubWindow._baseScreenStyle);
Ten.Style.applyStyle(screen, c.screenStyle);
document.body.appendChild(screen);
this.screen = screen;
new Ten.Observer(screen, 'onclick', this, 'hide');
}
},
show: function(pos) {
pos = (pos.x && pos.y) ? pos : {x:0, y:0};
with (this.window.style) {
display = 'block';
left = pos.x + 'px';
top = pos.y + 'px';
}
if (this.screen) {
with (this.screen.style) {
display = 'block';
left = Ten.Geometry.getScroll().x + 'px';
top = Ten.Geometry.getScroll().y + 'px';
}
}
this.windowObserver = new Ten.Observer(document.body, 'onkeypress', this, 'handleEscape');
this.visible = true;
},
handleEscape: function(e) {
if (!e.isKey('escape')) return;
this.hide();
},
hide: function() {
if (this._draggable) this._draggable.endDrag();
this.window.style.display = 'none';
if (this.screen) this.screen.style.display = 'none';
if (this.windowObserver) this.windowObserver.stop();
this.visible = false;
}
});
/* Ten.Draggable */
Ten.Draggable = new Ten.Class({
initialize: function(element,handle) {
this.element = element;
this.handle = handle || element;
this.startObserver = new Ten.Observer(this.handle, 'onmousedown', this, 'startDrag');
this.handlers = [];
}
},{
startDrag: function(e) {
if (e.targetIsFormElements()) return;
this.delta = Ten.Position.subtract(
e.mousePosition(),
Ten.Geometry.getElementPosition(this.element)
);
this.handlers = [
new Ten.Observer(document, 'onmousemove', this, 'drag'),
new Ten.Observer(document, 'onmouseup', this, 'endDrag'),
new Ten.Observer(this.element, 'onlosecapture', this, 'endDrag')
];
e.stop();
},
drag: function(e) {
var pos = Ten.Position.subtract(e.mousePosition(), this.delta);
Ten.Style.applyStyle(this.element, {
left: pos.x + 'px',
top: pos.y + 'px'
});
e.stop();
},
endDrag: function(e) {
for (var i = 0; i < this.handlers.length; i++) {
this.handlers[i].stop();
}
if(e) e.stop();
}
});
/* Hatena */
if (typeof(Hatena) == 'undefined') {
Hatena = {};
}
/* Hatena.User */
Hatena.User = new Ten.Class({
initialize: function(name) {
this.name = name;
},
getProfileIcon: function(name) {
if (!name) name = 'user';
var pre = name.match(/^[\w-]{2}/)[0];
var img = document.createElement('img');
img.src = 'http://www.hatena.ne.jp/users/' + pre + '/' + name + '/profile_s.gif';
img.alt = name;
img.setAttribute('class', 'profile-icon');
img.setAttribute('width','16px');
img.setAttribute('height','16px');
with (img.style) {
margin = '0 3px';
border = 'none';
verticalAlign = 'middle';
}
return img;
}
}, {
profileIcon: function() {
return Hatena.User.getProfileIcon(this.name);
}
});
/* Hatena.Star */
if (typeof(Hatena.Star) == 'undefined') {
Hatena.Star = {};
}
/*
// Hatena.Star.* classes //
**/
if (window.location && window.location.host.match(/hatena\.com/)) {
Hatena.Star.BaseURL = 'http://s.hatena.com/';
} else {
Hatena.Star.BaseURL = 'http://s.hatena.ne.jp/';
}
Hatena.Star.Token = null;
/* Hatena.Star.User */
Hatena.Star.User = new Ten.Class({
base: [Hatena.User],
initialize: function(name) {
if (Hatena.Star.User._cache[name]) {
return Hatena.Star.User._cache[name];
} else {
this.name = name;
Hatena.Star.User._cache[name] = this;
return this;
}
},
_cache: {}
},{
userPage: function() {
return Hatena.Star.BaseURL + this.name + '/';
}
});
/* Hatena.Star.Entry */
Hatena.Star.Entry = new Ten.Class({
initialize: function(e) {
this.entry = e;
this.uri = e.uri;
this.title = e.title;
this.star_container = e.star_container;
this.comment_container = e.comment_container;
this.stars = [];
this.comments = [];
},
maxStarCount: 11
},{
flushStars: function() {
this.stars = [];
this.star_container.innerHTML = '';
},
bindStarEntry: function(se) {
this.starEntry = se;
for (var i = 0; i < se.stars.length; i++) {
if (typeof(se.stars[i]) == 'number') {
this.stars.push(new Hatena.Star.InnerCount(se.stars[i],this));
} else {
this.stars.push(new Hatena.Star.Star(se.stars[i]));
}
}
if (se.comments && !this.comments.length) {
for (var i = 0; i < se.comments.length; i++) {
this.comments.push(new Hatena.Star.Comment(se.comments[i]));
}
}
this.can_comment = se.can_comment;
},
setCanComment: function(v) {
this.can_comment = v;
},
showButtons: function() {
this.addAddButton();
this.addCommentButton();
},
addAddButton: function() {
if (this.star_container) {
this.addButton = new Hatena.Star.AddButton(this);
this.star_container.appendChild(this.addButton);
}
},
addCommentButton: function() {
if (this.comment_container) {
this.commentButton = new Hatena.Star.CommentButton(this);
this.comment_container.appendChild(this.commentButton.img);
}
},
showStars: function() {
var klass = this.constructor;
// if (this.stars.length > klass.maxStarCount) {
// var ic = new Hatena.Star.InnerCount(this.stars.slice(1,this.stars.length));
// this.star_container.appendChild(this.stars[0]);
// this.star_container.appendChild(ic);
// this.star_container.appendChild(this.stars[this.stars.length - 1]);
// } else {
for (var i = 0; i < this.stars.length; i++) {
this.star_container.appendChild(this.stars[i]);
}
},
showCommentButton: function() {
if (this.can_comment) {
this.commentButton.show();
if (this.comments.length) this.commentButton.activate();
} else {
// this.commentButton.hide();
}
},
addStar: function(star) {
this.stars.push(star);
this.star_container.appendChild(star);
},
addComment: function(com) {
if (!this.comments) this.comments = [];
if (this.comments.length == 0) {
this.commentButton.activate();
}
this.comments.push(com);
},
showCommentCount: function() {
this.comment_container.innerHTML += this.comments.length;
}
});
/* Hatena.Star.Button */
Hatena.Star.Button = new Ten.Class({
createButton: function(args) {
var img = document.createElement('img');
img.src = args.src;
img.alt = img.title = args.alt;
with (img.style) {
cursor = 'pointer';
margin = '0 3px';
padding = '0';
border = 'none';
verticalAlign = 'middle';
}
return img;
}
});
/* Hatena.Star.AddButton */
Hatena.Star.AddButton = new Ten.Class({
base: ['Hatena.Star.Button'],
initialize: function(entry) {
this.entry = entry;
this.lastPosition = null;
var img = Hatena.Star.Button.createButton({
src: Hatena.Star.AddButton.ImgSrc,
alt: 'Add Star'
});
this.observer = new Ten.Observer(img,'onclick',this,'addStar');
this.img = img;
return img;
},
ImgSrc: Hatena.Star.BaseURL + 'images/add.gif'
},{
addStar: function(e) {
this.lastPosition = e.mousePosition();
var uri = Hatena.Star.BaseURL + 'star.add.json?uri=' + encodeURIComponent(this.entry.uri) +
'&title=' + encodeURIComponent(this.entry.title);
if (Hatena.Star.Token) {
uri += '&token=' + Hatena.Star.Token;
}
new Ten.JSONP(uri, this, 'receiveResult');
},
receiveResult: function(args) {
var name = args ? args.name : null;
if (name) {
this.entry.addStar(new Hatena.Star.Star({name: name}));
//alert('Succeeded in Adding Star ' + args);
} else if (args.errors) {
var pos = this.lastPosition;
pos.x -= 10;
pos.y += 25;
var scroll = Ten.Geometry.getScroll();
var scr = new Hatena.Star.AlertScreen();
var alert = args.errors[0];
scr.showAlert(alert, pos);
}
}
});
/* Hatena.Star.CommentButton */
Hatena.Star.CommentButton = new Ten.Class({
base: ['Hatena.Star.Button'],
initialize: function(entry) {
this.entry = entry;
this.lastPosition = null;
var img = Hatena.Star.Button.createButton({
src: Hatena.Star.CommentButton.ImgSrc,
alt: 'Comments'
});
img.style.display = 'none';
this.observer = new Ten.Observer(img,'onclick',this,'showComments');
this.img = img;
},
ImgSrc: Hatena.Star.BaseURL + 'images/comment.gif',
ImgSrcActive: Hatena.Star.BaseURL + 'images/comment_active.gif'
},{
showComments: function(e) {
if (!this.screen) this.screen = new Hatena.Star.CommentScreen();
this.screen.bindEntry(this.entry);
var pos = e.mousePosition();
pos.y += 25;
this.screen.showComments(this.entry, pos);
},
hide: function() {
this.img.style.display = 'none';
},
show: function() {
this.img.style.display = 'inline';
},
activate: function() {
this.show();
this.img.src = Hatena.Star.CommentButton.ImgSrcActive;
}
});
/* Hatena.Star.Star */
Hatena.Star.Star = new Ten.Class({
initialize: function(args) {
if (args.img) {
this.img = args.img;
this.name = this.img.getAttribute('alt');
} else {
this.name = args.name;
var img = document.createElement('img');
img.src = Hatena.Star.Star.ImgSrc;
img.alt = this.name;
with (img.style) {
padding = '0';
border = 'none';
}
this.img = img;
}
new Ten.Observer(this.img,'onmouseover',this,'showName');
new Ten.Observer(this.img,'onmouseout',this,'hideName');
if (this.name) {
this.user = new Hatena.Star.User(this.name);
this.img.style.cursor = 'pointer';
new Ten.Observer(this.img,'onclick',this,'goToUserPage');
}
if (args.count && args.count > 1) {
var c = document.createElement('span');
c.setAttribute('class', 'hatena-star-inner-count');
Ten.Style.applyStyle(c, Hatena.Star.InnerCount.style);
c.innerHTML = args.count;
var s = document.createElement('span');
s.appendChild(img);
s.appendChild(c);
return s;
} else {
return this.img;
}
},
ImgSrc: Hatena.Star.BaseURL + 'images/star.gif'
},{
showName: function(e) {
if (!this.screen) this.screen = new Hatena.Star.NameScreen();
var pos = e.mousePosition();
pos.x += 10;
pos.y += 25;
this.screen.showName(this.name, pos);
},
hideName: function() {
if (!this.screen) return;
this.screen.hide();
},
goToUserPage: function() {
window.location = this.user.userPage();
}
});
/* Hatena.Star.InnerCount */
Hatena.Star.InnerCount = new Ten.Class({
initialize: function(count, e) {
this.count = count;
this.entry = e;
var c = document.createElement('span');
c.setAttribute('class', 'hatena-star-inner-count');
Ten.Style.applyStyle(c, Hatena.Star.InnerCount.style);
c.style.cursor = 'pointer';
c.innerHTML = count;
new Ten.Observer(c,'onclick',this,'showInnerStars');
this.container = c;
return c;
},
style: {
color: '#f4b128',
fontWeight: 'bold',
fontSize: '80%',
fontFamily: '"arial", sans-serif',
margin: '0 2px'
}
},{
showInnerStars: function() {
var url = Hatena.Star.BaseURL + 'entry.json?uri=' +
encodeURIComponent(this.entry.uri);
new Ten.JSONP(url, this, 'receiveStarEntry');
},
receiveStarEntry: function(res) {
var se = res.entries[0];
var e = this.entry;
if (encodeURIComponent(se.uri) != encodeURIComponent(e.uri)) return;
e.flushStars();
e.bindStarEntry(se);
e.addAddButton();
e.showStars();
}
});
/* Hatena.Star.Comment */
Hatena.Star.Comment = new Ten.Class({
initialize: function(args) {
this.name = args.name;
this.body = args.body;
}
},{
asElement: function() {
var div = document.createElement('div');
with (div.style) {
margin = '0px 0';
padding = '5px 0';
borderBottom = '1px solid #ddd';
}
var ico = Hatena.User.getProfileIcon(this.name);
div.appendChild(ico);
var span = document.createElement('span');
with(span.style) {
fontSize = '90%';
}
span.innerHTML = this.body;
div.appendChild(span);
return div;
}
});
/* Hatena.Star.NameScreen */
Hatena.Star.NameScreen = new Ten.Class({
base: [Ten.SubWindow],
style: {
padding: '2px',
textAlign: 'center'
},
containerStyle: {
margin: 0,
padding: 0
},
handleStyle: null,
showScreen: false,
closeButton: null,
draggable: false
},{
showName: function(name, pos) {
this.container.innerHTML = '';
this.container.appendChild(Hatena.User.getProfileIcon(name));
this.container.appendChild(document.createTextNode(name));
this.show(pos);
}
});
/* Hatena.Star.AlertScreen */
Hatena.Star.AlertScreen = new Ten.Class({
base: [Ten.SubWindow],
style: {
padding: '2px',
textAlign: 'center',
borderRadius: '6px',
MozBorderRadius: '6px',
width: '240px',
height: '120px'
},
handleStyle: {
position: 'absolute',
top: '0px',
left: '0px',
backgroundColor: '#f3f3f3',
borderBottom: '1px solid #bbb',
width: '100%',
height: '30px',
borderRadius: '6px 6px 0 0',
MozBorderRadius: '6px 6px 0 0'
}
},{
showAlert: function(msg, pos) {
this.container.innerHTML = msg;
var win = Ten.Geometry.getWindowSize();
var scr = Ten.Geometry.getScroll();
var w = parseInt(this.constructor.style.width) + 20;
if (pos.x + w > scr.x + win.w) pos.x = win.w + scr.x - w;
this.show(pos);
}
});
/* Hatena.Star.CommentScreen */
Hatena.Star.CommentScreen = new Ten.Class({
base: [Ten.SubWindow],
initialize: function() {
var self = this.constructor.SUPER.call(this);
if (!self.commentsContainer) self.addCommentsContainer();
return self;
},
style: {
width: '280px',
height: '280px',
overflowY: 'auto',
padding: '2px',
textAlign: 'center',
borderRadius: '6px',
MozBorderRadius: '6px'
},
handleStyle: {
position: 'absolute',
top: '0px',
left: '0px',
backgroundColor: '#f3f3f3',
borderBottom: '1px solid #bbb',
width: '100%',
height: '30px',
borderRadius: '6px 6px 0 0',
MozBorderRadius: '6px 6px 0 0'
},
containerStyle: {
margin: '32px 0 0 0',
textAlign: 'left',
padding: '0 10px'
},
getLoadImage: function() {
var img = document.createElement('img');
img.src = Hatena.Star.BaseURL + 'images/load.gif';
img.setAttribute('alt', 'Loading');
with (img.style) {
verticalAlign = 'middle';
margin = '0 2px';
}
return img;
}
},{
addCommentsContainer: function() {
var div = document.createElement('div');
with (div.style) {
marginTop = '-3px';
}
this.container.appendChild(div);
this.commentsContainer = div;
},
showComments: function(e, pos) {
var comments = e.comments;
if (!comments) comments = [];
this.commentsContainer.innerHTML = '';
for (var i=0; i<comments.length; i++) {
this.commentsContainer.appendChild(comments[i].asElement());
}
if (e.starEntry && !e.can_comment) {
this.hideCommentForm();
} else {
this.addCommentForm();
}
var win = Ten.Geometry.getWindowSize();
var scr = Ten.Geometry.getScroll();
var w = parseInt(this.constructor.style.width) + 20;
if (pos.x + w > scr.x + win.w) pos.x = win.w + scr.x - w;
this.show(pos);
},
bindEntry: function(e) {
this.entry = e;
},
sendComment: function(e) {
if (!e.isKey('enter')) return;
var body = this.commentInput.value;
if (!body) return;
this.commentInput.disabled = 'true';
this.showLoadImage();
var url = Hatena.Star.BaseURL + 'comment.add.json?body=' + encodeURIComponent(body) +
'&uri=' + encodeURIComponent(this.entry.uri) +
'&title=' + encodeURIComponent(this.entry.title);
new Ten.JSONP(url, this, 'receiveResult');
},
receiveResult: function(args) {
if (!args.name || !args.body) return;
this.commentInput.value = '';
this.commentInput.disabled = '';
this.hideLoadImage();
var com = new Hatena.Star.Comment(args);
this.entry.addComment(com);
this.commentsContainer.appendChild(com.asElement());
},
showLoadImage: function() {
if (!this.loadImage) return;
this.loadImage.style.display = 'inline';
},
hideLoadImage: function() {
if (!this.loadImage) return;
this.loadImage.style.display = 'none';
},
hideCommentForm: function() {
if (!this.commentForm) return;
this.commentForm.style.display = 'none';
},
addCommentForm: function() {
if (this.commentForm) {
this.commentForm.style.display = 'block';
return;
}
var form = document.createElement('div');
this.container.appendChild(form);
this.commentForm = form;
with (form.style) {
margin = '0px 0';
padding = '5px 0';
// borderTop = '1px solid #ddd';
}
//if (Hatena.Visitor) {
// form.appendChild(Hatena.Visitor.profileIcon());
//} else {
// form.appendChild(Hatena.User.getProfileIcon());
//}
var input = document.createElement('input');
input.type = 'text';
with (input.style) {
width = '215px';
border = '1px solid #bbb';
padding = '3px';
}
form.appendChild(input);
this.commentInput = input;
var img = this.constructor.getLoadImage();
this.loadImage = img;
this.hideLoadImage();
form.appendChild(img);
new Ten.Observer(input,'onkeypress',this,'sendComment');
}
});
/* Hatena.Star.EntryLoader */
Hatena.Star.EntryLoader = new Ten.Class({
initialize: function() {
var entries = Hatena.Star.EntryLoader.loadEntries();
this.entries = [];
for (var i = 0; i < entries.length; i++) {
var e = new Hatena.Star.Entry(entries[i]);
e.showButtons();
this.entries.push(e);
}
this.getStarEntries();
},
createStarContainer: function() {
var sc = document.createElement('span');
sc.setAttribute('class', 'hatena-star-star-container');
sc.style.marginLeft = '1px';
return sc;
},
createCommentContainer: function() {
var cc = document.createElement('span');
cc.setAttribute('class', 'hatena-star-comment-container');
cc.style.marginLeft = '1px';
return cc;
},
scrapeTitle: function(node) {
var rval = [];
(function (node) {
if (node.tagName == 'SPAN' &&
(node.className == 'sanchor' ||
node.className == 'timestamp')) {
return;
} else if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
return;
}
var cn = node.childNodes;
if (cn) {
for (var i = 0; i < cn.length; i++) {
arguments.callee.call(this, cn[i]);
}
}
var nodeValue = node.nodeValue;
if (typeof(nodeValue) == 'string') {
rval.push(nodeValue);
}
})(node);
return rval.join('');
},
headerTagAndClassName: ['h3',null],
getHeaders: function() {
var t = Hatena.Star.EntryLoader.headerTagAndClassName;
return Ten.DOM.getElementsByTagAndClassName(t[0],t[1],document);
},
loadEntries: function() {
var entries = [];
//var headers = document.getElementsByTagName('h3');
var c = Hatena.Star.EntryLoader;
var headers = c.getHeaders();
for (var i = 0; i < headers.length; i++) {
var header = headers[i];
var a = header.getElementsByTagName('a')[0];
if (!a) continue;
var uri = a.href;
var title = '';
// Ten.DOM.removeEmptyTextNodes(header);
var cns = header.childNodes;
title = c.scrapeTitle(header);
var cc = c.createCommentContainer();
header.appendChild(cc);
var sc = c.createStarContainer();
header.appendChild(sc);
entries.push({
uri: uri,
title: title,
star_container: sc,
comment_container: cc
});
}
return entries;
}
},{
getStarEntries: function() {
var url = Hatena.Star.BaseURL + 'entries.json?';
for (var i = 0; i < this.entries.length; i++) {
if (url.length > Ten.JSONP.MaxBytes) {
new Ten.JSONP(url, this, 'receiveStarEntries');
url = Hatena.Star.BaseURL + 'entries.json?';
}
url += 'uri=' + encodeURIComponent(this.entries[i].uri) + '&';
}
new Ten.JSONP(url, this, 'receiveStarEntries');
},
receiveStarEntries: function(res) {
var entries = res.entries;
if (!entries) entries = [];
for (var i = 0; i < this.entries.length; i++) {
var e = this.entries[i];
for (var j = 0; j < entries.length; j++) {
var se = entries[j];
if (!se.uri) continue;
if (encodeURIComponent(se.uri) == encodeURIComponent(e.uri)) {
e.bindStarEntry(se);
entries.splice(j,1);
break;
}
}
if (typeof(e.can_comment) == 'undefined') {
e.setCanComment(res.can_comment);
}
e.showStars();
e.showCommentButton();
}
}
});
/* Hatena.Star.WindowObserver */
Hatena.Star.WindowObserver = new Ten.Class({
initialize: funct
20070629230000改定
20070702125800バグ発見:スクリプト中にある「&&」が、「&&」になっている。増田の仕様らしい。
20070827224900改定
// ==UserScript== // @name anond pickup // @namespace http://anond.hatelabo.jp/20070608230645 // @description pickup trackback tree top section at Hatelabo::AnonymousDiary // @include http://anond.hatelabo.jp/* // ==/UserScript== (function() { var threshold_bm = 1; var threshold_tb = 1; var ignoreList = { "/20070801172335": 33, "/20070806163721": 10, }; var firstPager_l = document.evaluate("//div[@class='pager-l']",document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue; function Hide(){} Hide.prototype.setup = function() { this.style = document.createElement("style"); this.style.id = "hide"; this.style.type = "text/css"; document.getElementsByTagName("head")[0].appendChild(this.style); var self = this; this.a = new Object(); this.a.visible = document.createElement("a"); this.a.visible.id = "visible"; this.a.visible.href = "#"; this.a.visible.innerHTML = "visible hide section"; // this.a.visible.setAttribute("onclick","document.getElementById('hide').innerHTML = 'div.hide {display: block}';document.getElementById('visible').style.display = 'none';document.getElementById('unvisible').style.display = 'inline';"); this.a.visible.addEventListener("click", function(){self.visible()}, false); firstPager_l.parentNode.insertBefore(this.a.visible, firstPager_l); this.a.unvisible = document.createElement("a"); this.a.unvisible.id = "unvisible"; this.a.unvisible.href = "#"; this.a.unvisible.innerHTML = "unvisible hide section"; // this.a.visible.setAttribute("onclick","document.getElementById('hide').innerHTML = 'div.hide {display: none}';document.getElementById('visible').style.display = 'inline';document.getElementById('unvisible').style.display = 'none';"); this.a.unvisible.addEventListener("click", function(){self.unvisible()}, false); firstPager_l.parentNode.insertBefore(this.a.unvisible, firstPager_l); if (GM_getValue("visible", 0)) { this.visible(); } else { this.unvisible(); } } Hide.prototype.visible = function() { this.style.innerHTML = "div.hide {display: block}"; this.a.visible.style.display = "none"; this.a.unvisible.style.display = "inline"; GM_setValue("visible", 1); } Hide.prototype.unvisible = function() { this.style.innerHTML = "div.hide {display: none}"; this.a.visible.style.display = "inline"; this.a.unvisible.style.display = "none"; GM_setValue("visible", 0); } Hide.prototype.append = function(section) { if (section.className.match(/hide/)) { return; } section.className += " hide"; } Hide.prototype.clear = function(section) { section.className = section.className.replace(/ hide/g, ""); } Hide.prototype.is = function(section) { return section.className.match(/hide/); } var hide = new Hide(); hide.setup(); var target = document.evaluate( "//div[@class='section' and child::*[not(@class='sectionfooter') and descendant::a[starts-with(@href,'http://anond.hatelabo.jp/2') or starts-with(@href,'/2') and not(child::span[@class='sanchor'])]]]", document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null); for (var i=0; i<target.snapshotLength; i++) { hide.append(target.snapshotItem(i)); } var tbs = document.evaluate( "//p[@class='sectionfooter']/a[2]", document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null); for (var i=0; i<tbs.snapshotLength; i++) { var tb = tbs.snapshotItem(i); if (tb.innerHTML == "\u30c8\u30e9\u30c3\u30af\u30d0\u30c3\u30af(0)") { // hide.append(tb.parentNode.parentNode); bookmark(tb, 0); } else if (! hide.is(tb.parentNode.parentNode)) { trackback(tb, 1); } else { bookmark(tb, 1); } } function trackback(tb, callback) { GM_xmlhttpRequest({ method: "GET", url: "http://anond.hatelabo.jp/" + tb.pathname.match(/\d{14}/), onload: function(result) { var link = result.responseText.match(/<a name="tb">(.|\s)*/)[0].match(/<li>\s*<a href="http:\/\/anond.hatelabo.jp\/\d{14}"/g); var n = link.length; for (var l in link) { var m = "/" + link[l].match(/\d{14}/); if (m in ignoreList) { n -= ignoreList[m]; } } if (n < threshold_tb) { tb.innerHTML = tb.innerHTML.replace(/\)$/, "/"+n+")"); if (callback) { bookmark(tb); } } else { tb.innerHTML = tb.innerHTML.replace(/\)$/, '/<span style="color: red;">'+n+"</span>)"); } } }); } function bookmark(tb, callback){ GM_xmlhttpRequest({ method: "GET", url: "http://b.hatena.ne.jp/entry/rss/http://anond.hatelabo.jp/" + tb.pathname.match(/\d{14}/), onload: function(result) { var r = result.responseText.match(/<rdf:li rdf:resource=/g); if (r && r.length >= threshold_bm){ hide.clear(tb.parentNode.parentNode); if (callback) { trackback(tb); } } else { hide.append(tb.parentNode.parentNode); } } }); } })();
今はスッキリしているのは古いやつ
/// ==UserScript== // @name anond pickup // @namespace http://anond.hatelabo.jp/20070608230645 // @description pickup trackback tree top section at Hatelabo::AnonymousDiary // @include http://anond.hatelabo.jp/*?page=* // ==/UserScript== (function() { var target = document.evaluate( "//div[@class='section' and child::*[not(@class='sectionfooter') and descendant::a[starts-with(@href,'http://anond.hatelabo.jp/2') or starts-with(@href,'/2') and not(child::span[@class='sanchor'])]]]", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for(var i=0; i<target.snapshotLength; i++) { target.snapshotItem(i).style.display = "none"; } var trackback = document.evaluate( "//p[@class='sectionfooter']/a[2]", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for(var i=0; i<trackback.snapshotLength; i++) { if (trackback.snapshotItem(i).innerHTML == "\u30c8\u30e9\u30c3\u30af\u30d0\u30c3\u30af(0)") { trackback.snapshotItem(i).parentNode.parentNode.style.display = "none"; } else if (trackback.snapshotItem(i).parentNode.parentNode.style.display != "none") { count(trackback.snapshotItem(i)); } } function count(tb) { GM_xmlhttpRequest({ method: "GET", url: "http://anond.hatelabo.jp/" + tb.getAttribute("href").match(/[0-9]{14}/), onload: function(result) { var n = result.responseText.replace(/\n/g,"").match(/<a name="tb">.*/)[0].match(/<li>/g).length; if (n < 10) { tb.innerHTML = tb.innerHTML.replace(/\)$/,"/"+n+")"); } else { tb.innerHTML = tb.innerHTML.replace(/\)$/,'/<span style="color: red;">'+n+"</span>)"); } } }); } })();
以下の二つに留意、つまり乱用禁止。
取説未満
// ==UserScript== // @name anond pickup of the day // @namespace http://anond.hatelabo.jp/ // @description pickup section of the day at Hatelabo::AnonymousDiary // @include http://anond.hatelabo.jp/2* // ==/UserScript== (function(){ var trackbackThreshold = 10; var ignoreList = { "/20070801172335": 33, "/20070806163721": 10, }; // only section of the day if (! location.pathname.match(/^\/\d{8}$/)) { return; } // regist ancher that kick main routine var a = document.createElement("a"); a.href = "#"; a.innerHTML = "pickup of the day"; a.addEventListener("click", grab, false); var firstPager_l = document.evaluate("//div[@class='pager-l']",document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue; firstPager_l.appendChild(a); function Outline() { this.outline = document.createElement("ul"); this.text = document.createElement("textarea"); this.text.style.overflow = "auto"; this.text.style.width = "100%"; this.text.style.height = "15em"; this.text.innerHTML = "</ul><\n><ul>\n"; this.list = new Array(); } Outline.prototype.setup = function() { var parent = document.getElementById("body"); parent.insertBefore(this.outline, parent.firstChild); parent.insertBefore(this.text, parent.firstChild); } Outline.prototype.append = function(section) { var h3 = section.getElementsByTagName("h3")[0]; var sectionName = h3.firstChild.pathname.replace(/\//,""); var sectionText = h3.textContent.replace(/\s*$/,""); if (sectionText == "\u25a0") { sectionText = sectionName; } this.text.innerHTML += '<h2>[http://anond.hatelabo.jp/'+sectionName+ ":title="+sectionText.replace(/^\u25a0/,"").replace(/]/g,"&#93;")+"] "+ '<a href="http://b.hatena.ne.jp/entry/http://anond.hatelabo.jp/'+sectionName+'">'+ '<img src="http://b.hatena.ne.jp/entry/image/http://anond.hatelabo.jp/'+sectionName+'">'+ "</a></h2>\n"; h3.firstChild.name = sectionName; var li = document.createElement("li"); li.innerHTML = '<a href="#'+sectionName+'">' + sectionText.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">") + "</a>"; var nextSibling = 0; for (var i in this.list) { if (nextSibling < i && i < sectionName) { nextSibling = i; } } if (nextSibling) { this.outline.insertBefore(li, this.list[nextSibling]); } else { this.outline.appendChild(li); } this.list[sectionName] = li; } var outline = new Outline(); function CC(day) { this.li = document.createElement("li"); this.li.innerHTML = '<a href="/'+day+'" target="_blank">' + day + "</a>"; this.day = day; this.n = new Array(); } CC.prototype.pp = function(id) { this.n.push(id); if (this.n.length > 10) { this.li.innerHTML = '<a href="/'+this.day+'" target="_blank">' + this.day + "</a> " + this.n.length; } else { this.li.innerHTML += ' <a href="/'+id+'" target="_blank">*</a>'; } } function Count() { this.count = document.createElement("ul"); this.list = new Array(); } Count.prototype.setup = function() { var parent = document.getElementById("body"); parent.insertBefore(this.count, parent.firstChild); } Count.prototype.append = function(day, id) { var nextSibling = 0; for (var i in this.list) { if (nextSibling < i && i <= day) { nextSibling = i; } } if (nextSibling == day) { this.list[nextSibling].pp(id); } else { var cc = new CC(day); if (nextSibling) { this.count.insertBefore(cc.li, this.list[nextSibling].li); } else { this.count.appendChild(cc.li); } this.list[day] = cc; cc.pp(id); } } Count.prototype.appendSection = function(section) { var id = section.getElementsByTagName("h3")[0].firstChild.pathname.replace(/\//,""); var today = id.match(/\d{8}/)[0]; var anchors = section.getElementsByTagName("a"); for (var i=0; i<anchors.length; i++) { if (anchors[i].href && anchors[i].host == "anond.hatelabo.jp" && anchors[i].pathname.match(/\/(\d{8})\d{6}/) && RegExp.$1 != today) { this.append(RegExp.$1, id); } } } var count = new Count(); function Hide(){} Hide.prototype.setup = function() { this.style = document.createElement("style"); this.style.id = "hide"; this.style.type = "text/css"; document.getElementsByTagName("head")[0].appendChild(this.style); var self = this; this.a = new Object(); this.a.visible = document.createElement("a"); this.a.visible.id = "visible"; this.a.visible.href = "#"; this.a.visible.innerHTML = "visible hide section"; // this.a.visible.setAttribute("onclick","document.getElementById('hide').innerHTML = 'div.hide {display: block}';document.getElementById('visible').style.display = 'none';document.getElementById('unvisible').style.display = 'inline';"); this.a.visible.addEventListener("click", function(){self.visible()}, false); firstPager_l.parentNode.insertBefore(this.a.visible, firstPager_l); this.a.unvisible = document.createElement("a"); this.a.unvisible.id = "unvisible"; this.a.unvisible.href = "#"; this.a.unvisible.innerHTML = "unvisible hide section"; // this.a.visible.setAttribute("onclick","document.getElementById('hide').innerHTML = 'div.hide {display: none}';document.getElementById('visible').style.display = 'inline';document.getElementById('unvisible').style.display = 'none';"); this.a.unvisible.addEventListener("click", function(){self.unvisible()}, false); firstPager_l.parentNode.insertBefore(this.a.unvisible, firstPager_l); this.unvisible(); } Hide.prototype.visible = function() { this.style.innerHTML = "div.hide {display: block}"; this.a.visible.style.display = "none"; this.a.unvisible.style.display = "inline"; } Hide.prototype.unvisible = function() { this.style.innerHTML = "div.hide {display: none}"; this.a.visible.style.display = "inline"; this.a.unvisible.style.display = "none"; } Hide.prototype.append = function(section) { if (section.className.match(/hide/)) { return; } section.className += " hide"; count.appendSection(section); } Hide.prototype.is = function(section) { return section.className.match(/hide/); } var hide = new Hide(); // main routine function grab(){ if (! document.body.innerHTML.match(/<div class="pager-r">(\d+)/)) { return; } var pages = RegExp.$1 -0; if (pages <= 0 || pages > 40) { // check error and limit 1000 entry return; } //pages = 2; firstPager_l.style.display = "none"; outline.setup(); hide.setup(); count.setup(); var mainbody = document.evaluate("//div[@class='body']", document,null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue; mainbody.innerHTML = "\n"; for (var i=1; i<=pages; i++) { cat(mainbody, i); } } // page load and concatenate function cat(container, page) { container.innerHTML += "<!-- page " + page + " -->\n"; GM_xmlhttpRequest({ method: "GET", url: "http://anond.hatelabo.jp" + location.pathname + "?page=" + page, onload: function(result) { result.responseText.match(/<div class="body">((.|\s)*?)\s*<\/div>\s*<\/div>\s*<div class="pager-l">/); container.innerHTML = container.innerHTML.replace("<!-- page " + page + " -->", RegExp.$1); if (! container.innerHTML.match(/<!-- page \d+ -->/)) { // document.documentElement.innerHTML = document.documentElement.innerHTML.replace(/(src|href)=\"\//mg, "$1=\"http://anond.hatelabo.jp/"); pickup(); } } }); } // pickup section at last cat() concatenate after function pickup() { var target = document.evaluate( "//div[@class='section' and child::*[not(@class='sectionfooter') and descendant::a[starts-with(@href,'http://anond.hatelabo.jp/2') or starts-with(@href,'/2') and not(child::span[@class='sanchor'])]]]", document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null); for (var i=0; i<target.snapshotLength; i++) { hide.append(target.snapshotItem(i)); } var tbs = document.evaluate( "//p[@class='sectionfooter']/a[2]", document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null); for (var i=0; i<tbs.snapshotLength; i++) { var tb = tbs.snapshotItem(i); if (tb.innerHTML == "\u30c8\u30e9\u30c3\u30af\u30d0\u30c3\u30af(0)") { hide.append(tb.parentNode.parentNode); } else if (! hide.is(tb.parentNode.parentNode)) { trackback(tb); } } } // count trackbacks function trackback(tb) { GM_xmlhttpRequest({ method: "GET", url: "http://anond.hatelabo.jp/" + tb.pathname.match(/\d{14}/), onload: function(result) { var link = result.responseText.match(/<a name="tb">(.|\s)*/)[0].match(/<li>\s*<a href="http:\/\/anond.hatelabo.jp\/\d{14}"/g); var n = link.length; for (var l in link) { var m = "/" + link[l].match(/\d{14}/); if (m in ignoreList) { n -= ignoreList[m]; } } if (n < trackbackThreshold) { hide.append(tb.parentNode.parentNode); } else { tb.innerHTML = tb.innerHTML.replace(/\)$/, "/"+n+")"); outline.append(tb.parentNode.parentNode); } } }); } })();