ひたすら無題 Ver2.0 “Sleipnir+SeaHorseで全サイトはてブ化”をできるようにした
http://sasuket.blog7.fc2.com/blog-entry-59.html
ひたすら無題 Ver2.0 Social Bookmark Viewer for Sleipnir+SeaHorse
http://sasuket.blog7.fc2.com/blog-entry-62.html
Sleipnir+SeaHorseで全サイトはてブ化v3 - kaz::hatena
http://d.hatena.ne.jp/kaz24/20060922/1158870862
旧版の Social Bookmark Viewer で 404 Blog Not Found なんかを見ていただくとわかるのですが、Social Bookmark Viewer の表示がサイトの見出しの裏に入ってしまって、文字は重なって読めないわ、消そうにも隠れててクローズボタン押せないわ、閲覧サイトによっては邪魔極まりない動作をしていました。
まあ、サイトのレイアウトなんかはいろいろあるわけで、どんなHTML書いてそうなっているかなんて推定できないのでしょうがない部分もあるんですが、せめて邪魔なときは消したりできないものかと悩んだ末に。
じゃあ最前面に出して動くようにしてやればいいんじゃね?

デキタヨー\(^o^)/
フローティングウィンドウ化には Prototype Window を使用しました。
ちなみに、SocialBookmarkViewer が有効だとGoogle Calendar、Google Reader、Google Maps、Remember the Milk で動作に支障が出ることを確認しています。
prototype.js や Prototype Window が干渉しているのか、DOM使って余計な要素を追加しているのが悪いのか。もしかしたら、Ver2.0では表示できるけれど、Ver3.0で表示できないサイトもあるかもしれません。今のところ、その逆のほうが多い印象ですが。
特に Ajax を使用しているサイトで何か動きがおかしい場合、SocialBookmarkViewer を疑ってください。
それから私は AutoPagerize for SeaHorse を併用していたため、はてなダイアリーなんかは読み進めるたびにページ下部に次のページが読み込まれて、SocialBookmarkViewer の表示部がどんどん押し流れてよめねーよ、というお馬鹿な状態になっていたのですが、フローティングウィンドウ化したおかげで、次のページが追記されてもその場に残り続けるようになってくれたのは予想外に便利。
これでいちいちブックマークの内容見るために右上の■をクリックして停止させる必要がなくなりました。
その他はreadme.txt参照。
ダウンロード
せっかくなので置いてもらおうかな…
置いてもらいました → Sleipnir Unofficial Extensions Center
■Ver3.0.2 ダウンロード
● Ver.3.0.2 - 2008/06/14
・後で読む(http://atode.cc/)アイコンを追加
・2chの上部キーワード(iframe)を無限に読み込みに行く不具合(初期状態でウィンドウ化しなければ発生しない)の対策に OPEN_SLEEP 設定を追加。
● Ver.3.0.1 - 2008/05/21
・特殊なレイアウトのページでエラーになる不具合を修正
● Ver.3.0.0 - 2008/05/13
▼機能追加
・特定のレイアウトのページでブックマーク表示部が、要素の陰に隠れて見えなかったり、読みにくかったり、表示されなかったりしたためフローティングウィンドウ化し、常に最前面に表示されるように変更
・設定で初期状態をページ末尾に追記か、フローティングウィンドウで選択できるようにした
・HatebuFriends(http://labs.irons.jp/hatebufriends/)へのリンクを追加
・livedoor クリップの表示を強化
・Yahoo!ブックマーク表示機能を追加
・fc2ブックマーク表示機能を追加
・Webスカウター表示機能を追加
・Simple API 表示機能を追加(意味なし)
▼仕様変更
・全面的に書き換え
・設定ファイルを分離(設定変更をしてもSeaHorse スクリプトの再読み込みが不要になりました)
・スタイルシートを分離
・誰もブックマークしていないページでも、はてなブックマークや del.icio.us に追加するためのアイコンは表示するように変更
▼不具合修正
・閲覧ページのCSSに影響されないよう、スタイル設定を全面的に見直し(多少マシになった)
・Google PAGERANK 表示ができなくなっていたので修正
・はてなブックマークでコメントなしのブックマークを出力しない場合、"最大件数以内のブックマークからコメントなしを省いていた"のを、"コメントありのブックマークを最大件数まで抽出"するように修正
・del.icio.us のタグクラウドの日本語タグ文字化けを改善
フローティングウィンドウ化した Social Bookmark Viewer Ver3.0
前回『ひたすら無題 Ver2.0 “Sleipnir+SeaHorseで全サイトはてブ化”をできるようにした』にて、『Sleipnir+SeaHorseで全サイトはてブ化v3』の不具合訂正を行ったわけですが、調子に乗っていろいろごてごて付け加えてみました。
Social Bookmark Viewer

上記画面ははてなブックマークのトップページを開いたところ。
変更点はこんなところです。
- del.icio.usに対応
- del.icio.us で使用されているタグをタグクラウドで表示
- buzzurlに対応
- livedoor クリップにもこっそり対応
- リンク先を同一ウィンドウに開くが、新しいウィンドウで開くか選択できるようにした
- その他細々と
livedoor クリップは無理やり表示しているので、デフォルトはオフになっています。
簡単に設定変更できるものは頭のほうにコメントつけてますので、適当にいじってください。
⇒バージョンアップ版できました。
フローティングウィンドウ化した Social Bookmark Viewer Ver3.0
私は Sleipnir 使いなのですが、最近はてなブックマークを使い始めたので、以下の SeaHorse スクリプトを導入。はてなブックマークの情報がページの下に出てくる。
kaz::hatena - Sleipnir+SeaHorseで全サイトはてブ化v3
ところがこちらのコメント欄で報告があるとおり、特定のページで「サーバーが見つかりません」と言うエラーが出るようです。というか実際にガンガン出てきましたので修正版を作りました。とりあえず、数日いじって「サーバーが見つかりません」エラーが全く出なくなったので、公開しておきます。
どうもJapanizeでも同じ現象が発生しているようでしたので、修正方法をさくっといただきました。もう数年前にスキルが消えうせたのでほぼコピーです。
// ==UserScript== // @name Hatena Bookmark Comments Viewer for Sleipnir+SeaHorse Plus // @author sasuket // @namespace http://sasuket.blog7.fc2.com/ // @description Show Hatena Bookmark's comments at the bottom of your browser. // @include http://* // ==/UserScript== function hbcv_callbackfunc(obj) { var max_comment_num = 30; var show_tag_only = false; function getDate(date) { var y = date.getFullYear(); var m = date.getMonth() + 1; var d = date.getDate(); if (m < 10) m = "0" + m; if (d < 10) d = "0" + d; return y + "/" + m + "/" + d; } if(obj && obj.count>0) { var bm=obj.bookmarks; var hbm_cmt = document.getElementById('hbm_cmt'); hbm_cmt.innerHTML = "<a href=\"http://b.hatena.ne.jp/entry/" + escape(document.location.href) + "\" style=\"color: red; font-weight: bold; text-decoration: underline; background-color: #ffcccc\">" + obj.count + "user" + (obj.count>1 ? "s" : "") + "</a> | <a href=\"javascript:void(0);\" style=\"color: blue; text-decoration: underline;\" onClick=\"javascript:document.getElementById('hbm_cmt').style.display='none',void(0);\">CLOSE</a><br/><br/>"; for(i=0;i<bm.length;i++) { if(bm[i].comment || (show_tag_only && bm[i].tags.length>0)) { var name = bm[i].user; var date = getDate(new Date(bm[i].timestamp)); hbm_cmt.innerHTML += "<span style=\"color: black;\">" + date + "</span> <img src=\"http://www.hatena.ne.jp/users/" + name.substring(0,2) + "/" + name + "/profile_s.gif\"> <span style=\"color: blue;\">" + name + "</span> <span class=\"tags\" style=\"color: gray;\">" + bm[i].tags.join(',') + "</span> <span style=\"color: black;\">" + bm[i].comment + '</span><br/>'; } if (i==max_comment_num) { break; } } } } ( function (c) { //Add var is_called; if (document != null && is_called != true && self.location.href==top.location.href) { is_called = true; //ADD Start if (document.readyState != 'complete') { if (c < 8000) { var f = arguments.callee; c *= 2; setTimeout(function () { f(c); }, c); } return; } //ADD End if (self.location.href==top.location.href) { var div = document.createElement('div'); div.id = "hbm_cmt"; var is_done = document.getElementById("hbm_cmt"); //Add if (is_done != null) { return; } //Add div.innerHTML = "<a href=\"javascript:void(0);\" style=\"color: blue; text-decoration: underline;\" onClick=\"javascript:document.getElementById('hbm_cmt').style.display='none',void(0);\">CLOSE</a><br/><br/>"; div.style.cssText = "width: 90%; background-color: #f0f0f0; border: solid 1px #cccccc; margin: 5px; padding: 5px; text-align: left;"; document.body.appendChild(div); var uri = top.location.href; script = document.createElement('script'); script.src = 'http://b.hatena.ne.jp/entry/json/?callback=hbcv_callbackfunc&url=' + escape(uri); document.body.appendChild(script); } } })(100); //ADD
JavaScript 触るのなんて数年ぶりですよ。DOMがぼちぼち出てきた頃以来なので内容読むだけなのに戸惑う戸惑う。リファレンスくらい買いなおそうかな…(´・ω・`)
ボタンを押したときに、そのボタンが disable になります。この方法を使うとボタンが押されて次の処理に入ろうとしているというのが直感的に分かるのと、二重送信防止にもなるということでユーザビリティが改善できます。
先のエントリーの関数を onsubmit に、今回のコードを onlick にといちいちするために HTML のテンプレートを書き換えたりするのがめんどくさい、という場合はハンドラへの登録も JavaScript で自動化してしまえばよくて、
- body の onload ハンドラで document.forms によりページ内の form をすべて取得
- それぞれの form の中に含まれるボタンな要素の onclick プロパティに上記のにメソッドを代入
- form の onsubmit プロパティにボタンを disable にするメソッドを代入
と順番に下っていく形でやっていくとうまくいくと思います。
上記記事を見て勉強がてら作ってみることに。
最近 JSAN なんてものを見つけて JavaScript 熱が再燃したのはいいのだけれど、Netscape が 3とか4とかの時期にちょっとかじったくらいなのでさっぱりわからない。何時からこんな便利くさい関数(いや、メソッドか?)が?かろうじて読めるけど、全然書けませんよ?
私の知っているJavaScriptと言ったらアレですよ?むやみにステータスバーに文字が踊ったりとかですね?
というかなんだかこのリファレンスなんの役にもたたないーっ?!
・
・
・
出直してきます……orz
というわけでコピペコピペでなんとか形に。 HTML 上で JSAN.js と bar.js を script 要素で指定したらそれでおしまいということにしてみました。ついでに、form target 属性で別窓開く場合は無効にしています。無駄に。
あと、JSANで、Prototypeと、それが使用するファイルとってこないと動きません。実に無駄なことに。
<script type="text/javascript" src="/static/js/lib/JSAN.js"></script> <script type="text/javascript" src="/static/js/bar.js"></script> ... <form action="foo.cgi" method="get"> <input class="button" name="baz" type="submit" value="baz送信" /> </form>
var jsan = new JSAN('/js/lib', 'lib'); jsan.use('DSS'); var dss = new DSS(); window.onload = function() { dss.setDisableSubmitButtons(); };
if ( ! jsan ) jsan = new JSAN(); jsan.use('prototype'); var DSS = Class.create(); DSS.prototype = { initialize : function(){ }, setDisableSubmitButtons : function(){ var forms = document.forms; var form = null; var obj = this; for (var i = 0; i < forms.length; i++) { form = forms[i]; if (form.target.length == 0 || form.target == "_self"){ if (!form.onsubmit) { var elements = form.elements; var element = null; for (var i = 0; i < elements.length; i++) { element = elements[i]; if ((element.type || "").toLowerCase() == "submit") { element.onclick = function() { obj.setHiddenValue(this); }; } } form.onsubmit = function() { obj.disableSubmitButtons(this); }; } } } }, disableSubmitButtons : function(form) { form = $(form); var elements = form.elements; var element = null; for (var i = 0; i < elements.length; i++) { element = elements[i]; if ((element.type || "").toLowerCase() == "submit") { this.disableElement(element); } } }, disableElement : function() { var element = null; for (var i = 0; i < arguments.length; i++) { element = $(arguments[i]); if (element) { element.disabled = true; } } }, setHiddenValue : function(button) { if (button.name) { var q = document.createElement('input'); q.type = 'hidden'; q.name = button.name; q.value = button.value; button.form.appendChild(q); } } };
今度リファレンス買いなおしてこよう……orz