« 2008年04月 | メイン | 2008年06月 »

2008年05月 アーカイブ

2008年05月09日

はてなスターのように「wwwww」を省略し「w3w」と表示するグリースモンキー

最近、インターネット上では、笑いを表現する時に「(笑)」のかわりに「w」を使う傾向が強くなっています。入力しやすい事、そして「w」の長さによってその笑いの度合いを表現できるため便利だからだと考えられます。しかし、HTMLは連続した半角英字を表示する際に自動的に折り返さず、半角英字を内包した要素が横に引き延ばされます。スタイルシート等で一応対策を打つ事が可能ですが、あまり見栄えは良くありません。
ところで、はてなスターというサービスがあります。詳細はここでは割愛しますが、このサービスでは気に入ったホームページに好きな数だけスター(☆)をつける事ができます。また、他の人がつけたスターも見る事ができるため、人気のホームページではスターが100を超える事があります。増え過ぎたスターが画面を覆い尽くす事はないのでしょうか。はてなスターではこの問題をスターを省略して表示する事で解決しています。例えば、スターが5個ついた場合には「☆☆☆☆☆」のように表示されますが、100個の場合は「☆98☆」のように表示します。
「w」によりレイアウトが崩れる問題をはてなスターのように解決できないかと思い、グリークモンキースクリプト(ユーザスクリプト)を作成しました。
このスクリプトを導入すると、「wwwwwwwwwwwwwwwwwwwwwwwwwwwwww」と入力されても「w28w」のように表示されます。またはてなスターと同じように数字をクリックすると「wwwwwwwwwwwwwwwwwwwwwwwwwwwwww」のように展開されます。
導入前
導入前
導入後
導入後
是非、このグリースモンキースクリプトを導入し快適なインターネット生活をご堪能下さい。
あとがき
また、バカなentryをしてしまった。後悔はしていない。そもそもこのグリモンがアホすぎる。挙動についてちょっと説明する。表示は文字でも良かったんだけどはてスタに似せるためにあえて画像で行っている。wの上にポインタを持っていっても、当然ながら誰がつけたwなのかは表示されない。[☆+]のように[w+]もつけたけど、もちろん保存はされない。追加したwを省略するwに含めるかどうか迷ったけど、末尾に追加するようにした。これは、はてスタで展開前にスターをつけた時場合、「☆98☆☆」のように末尾につけていたから。siteを読み込んだ時にのみ省略するようになっていて、後から動的に追加されたwの省略には対応していない。あと、はてスタよりも省略の閾値を低めにし、省略されやすくしてる。
是非、このグリースモンキースクリプトを導入し快適なwwwwwwwwww生活をご堪能下さいwwwww
2008/05/09:追記
sourceの中にゴミが残っていたので削除した。
挙動は変更なし。
2008/05/10:追記
はてブのコメントを見ていると、全角で「wwwwwwwwww」としている人がいました。なので全半角混在で「wwwwwwwwwwww」とされても省略するように変更しました。導入済の方は上書きインストールしてもらえれば大丈夫です。
2008/05/10:追記2
はてブコメントでgrassというプログラミング言語に対応していないという意見があった。いっその事全角半角だけでなく大文字小文字も問わない形式にしようかと思った。でも笑いを表現するのに大文字が使われる事は滅多にないのでこのままにしておく。どうしてもと言う人は、12行目の「[ww]」を「[wWwW]」に修正して下さい。
あと、スラッシュとバックスラッシュを駆使して「これで省略されないぜ\/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ \/\/ VV VV VV」とコメントされましたが、一つ重要な点を忘れてます。この書き方だと半角スペースが入っているので普通に自動改行されます。なので対応しません。
2008/05/11:追記
更に改良した。今回の機能追加は遊びではなく実用性を重視した。
今度は見た目がシンプルな文字のみのモード[word mode]を追加した。これまでの機能は[icon mode]と呼ぶ事にする。モードはユーザスクリプトコマンドから変更できる。(ユーザスクリプトコマンドはGreasemonkeyのメニューから実行できる。)
word modeとicon modeは省略時の表示方法はこれまでと同じだけど動作が違っている。最初の[w]をクリックすると全てを展開して表示する。最後の[w]をクリックすると省略されている[w]をひとつ展開するので、繰り返しクリックする事で好きなだけ展開ができる。それ以外の[w]をクリックするとクリックした[w]より後ろにある[w]を省略する。一部省略されている場合でも再度省略可能となっている。
2008/06/13:追記
リファクタリングとともに機能を追加した。リンク先を参照。

2008年05月16日

RubyistによるRubyのオンラインマガジン「Rubyist Magazine(通称るびま)」の通読を支援するGreasemonkey

正直タイトルが長いがしかたがない。
日本Rubyの会の公式siteではオンラインマガジン「るびま」が発行されている。
通読したいと思っているのだけど、記事が多くていったいどこまで読んだか正直わからなくなってなんともはがゆかった。これを解決するためにどこまで読んだかを記憶するuserscriptを作った。
文字で説明するよりも実際に動かしてみた方がはやいんだけど一応説明。
install後にるびまを開くと、メインコンテンツのリンクの前にステータスを表すアイコンが表示される。ステータスの意味はポインタをアイコンにあわせると表示されるので割愛。アイコンをクリックすると全ステータスのアイコンが表示される。変更したい状態のアイコンをクリックすると、そのステータスを保存し選択されたアイコンのみの表示となる。
ページの遷移やステータス変更のたびに全データを呼び出し、ステータス変更を反映後保存しているので、ウィンドウやタブを複数開いていても変な上書きはしない。つまり(表示上は一致しないけど)内部データとしては矛盾が起きないようにしている。
今後の予定
今は、リンク先のステータスを変更できるけど、現時点で表示しているベージのステータスは変更できないので対応したい。
複数のパソコンからるびまを読むような場合もあると思うので、データの出力機能と入力機能をつけたい。入力は上書きではなくステータス変更のタイムスタンプをもとにマージさせたい。
2008/05/16 追記
以下の二点修正しました。
アイコンの表示順を「未中済留除削」から「留未中済除削」に変更した。一番あり得る状態遷移の順番だと思います。
アイコンの位置が固定だった物を、現在の状態が一番最初に表示されるようにしました。前方にあったアイコンは順に後方に回り込みます。これにより、謝ってダブルクリックした際の誤操作も防ぐ事ができました。
2008/05/19 追記
データの出力(export)・入力(import)・結合(union,merge)の機能を追加しました。
Greasemonkeyのメニューから選択可能です。
2009/07/18 追記
これまでJSONライブラリは独自のものを使用していましたが、Firefox3.5ではJSONライブラリが使用できるようになっています。このため、「JSON.stringify」と「JSON.parse」を使用するように変更しました。

2008年05月20日

Kanasan.JS開催のお知らせと注意

Kanasan.JS、いよいよ今週末です。
二ヶ月近く間があいてしまいましたが、05/24にKanasan.JSを行います。
今回は、オライリーのJavaScript 第5版、通称サイ本の読書会です。
開催の告知場所
これまで、当ブログで開催の日程を確認していた方へのお願いです。
当ブログは、主催者のブログですが、Kanasan.JSに関してはGoogle Groupsでの告知を優先しています。
開催が決まっても、ここでは告知しない可能性があります。
主催者としても、Google Groups内のKanasan.JSのMLを優先しています。
このため、いち早く情報を得たい方は、下記URLを巡回して頂くか、MLへの登録をお勧めします。

2008年05月21日

全てのtextareaを自動的にリサイズするJavaScriptとGreasemonkey

「やるならここまで徹底して実装しようよ」という私は変態ですか?
そうですか。
codeは下の方。
デモは次のurl。
ついでにGreasemonkeyのuserscriptも。
難点はstyleの指定されていないtextareaなら全て自動的にリサイズしてしまう事。
修正するなら、addAutoResizeTextareaに全てのtextareaを渡さずに、任意のものを渡すようにすればいいってことで...。
2008/05/21 追記
大事なこと書き忘れてた。
元ネタは縦方向にのみだけど、こちらは横方向にも対応。
半角全角も判定している。
0x100移行にある"見た目が"半角の文字には残念ながら未対応。
そこまできちんとやるならフォントのグリフにまで手を伸ばさなくちゃならないけど、非現実的なのでこのままで。
2008/05/22 追記
はてなブックマークコメントで、id:rokuroxに「全角文字の対応がいまいちだから全角文字を大量に入力すると横幅がひどく長くなりますね」と突っ込まれましたが、これ全角であろうが半角であろうが際限なく横に伸びて行きます。
そう動くように作りました。
横だけでなく、下にもいつまでも広がっていきます。
元ネタの実装も際限ないです。
もし、制限を設けたいのであれば、
Math.max(Math.min(colsAndRows.cols+1,maxX),minX);
とすることで対応可能です。
但し、minX<=maxXであることを確認しなければ思わぬ動きをするので注意が必要です。
minX>maxXの時はswapするようにすれば良いかもしれません。
また、現状ではOperaに対応していません。
Operaに対応するには、addEventListenerの第三をfalseにする必要があります。
IMEからの場合、入力中だけでなく確定時にもkeyupイベントが発生しません。
resize処理は、focusが外れた時に発生するchangeイベントまでまたなくてはいけません。
このため、timer系の処理を追加し、定期的に処理する必要があります。
定期的な処理が全てのtextareaに対して行われるのは重くなる原因ですので、次のような実装が理想だと思います。
毎回resize処理を走らせるのではなく、前回走った時と内包する文字列が同一かどうか判定し、同一でない時初めてresize処理を行うようにします。
更に、いつでもtimer処理が走っているのも変ですので、focusイベント発生時にtimerを走らせ、blurイベント発生時にtimerを破棄するようにします。
以上、全て実装すればLibraryとしての価値が出てくるかと思います。
2008/05/23 追記
追記しようとしていた内容があまりにも長くなり過ぎたので別エントリーにしました。
(function(){
    var addEvent=
        function(element,eventName,handler){
            if(element.addEventListener){
                element.addEventListener(eventName,handler,true);
        }else{
            element.attachEvent("on"+eventName,handler);
        }
    }

addEvent(
    window,
    "load",
    function(){
        var getLength=
            function(str){
                return str.length+str.replace(/[\x0-\xff]/g,"").length;
            }
        var sort=
            (function(getLength){
                var _getLength=getLength;
                return function(a,b){
                    return _getLength(a)-_getLength(b);
                }
            })(getLength);
        var getColsAndRows=
            function(str){
                var ary=str.
                        replace(/\r\n/ig,"\n").
                        replace(/\r/ig,"\n").
                        split("\n");
                ary.sort(sort);
                return {
                    "cols":getLength(ary[ary.length-1]),
                    "rows":ary.length
                };
            }
        var resizeTextarea=
            function(){
                var colsAndRows=getColsAndRows(this.value);
                this.setAttribute("cols",colsAndRows.cols+1);
                this.setAttribute("rows",colsAndRows.rows+1);
            }
        var resizeTextareaHandler=
            function(textarea){
                var _textarea=textarea;
                return function(){
                    resizeTextarea.call(_textarea);
                }
            }
        var addAutoResizeTextarea=
            function(textarea){
                var handler=resizeTextareaHandler(textarea);
                handler();
                addEvent(textarea,"keyup",handler);
                addEvent(textarea,"change",handler);
            }
        var addAutoResizeTextareas=
            function(){
                var textareas=
                        document.getElementsByTagName("textarea");
                for(var i=0;i<textareas.length;i++){
                    addAutoResizeTextarea(textareas[i]);
                }
            }
        addAutoResizeTextareas();
    }
);
})();

2008年05月23日

続・全てのtextareaを自動的にリサイズするJavaScriptとGreasemonkey

はてなブックマークコメントで、再度id:rokuroxから突っ込みが。画像とともに、「全角が半角のちょうど2倍ではないから駄目。」と。意味がやっと理解できました。
全角が半角の2倍ではない件に対して考えられる原因は三つ。あくまで自分の知識の範囲内でありますが。全てフォントのグリフの問題。どれかが原因だと思いますが、手元にWindows環境がないため、的がはずれている可能性もあります。
まず、よくあるパターンとして、font-familyに等幅フォント(monospace)を指定していないため、プロポーショナルフォント(proportional)が使われている点。これは、単純にstyleを指定すれば解決しますが、この手のcodeでそこまで操作していいのかどうかという問題があります。問題というよりも思想かもしれませんが。Greasemonkeyとして実装するのであれば、全site閲覧時に実行されます。「textareaの伸縮を合わせるためだけにためにそこまでするのか」という点があり今回は見送りました。
次に、フォントそのものの問題。半角の倍の幅と全角の幅があっていない可能性。全角/半角という概念は見た目からくる俗称であり、本来文字の幅が一定とは決まっていません。あくまで活版印刷とその延長上にあるコンピュータ上の文字表現能力では、この方が都合が良かったからです。この制約がなくなって登場してきたのが上記のプロポーショナルフォントです。更に、フォントの作成上、漢字圏の文字の幅とラテン圏の文字の幅が2:1である必要はありません。慣習的に2:1になっているのです。フォントのデザインが2:1となっていてもDTP作業時に字詰め(これをカーニングといいます)が行われることもあります。ちょっと話がそれました。
最後に、Windows固有の問題。これは実装時にも考慮してませんでした。随分前にはまって苦労したのですが、すっかり忘れてました。詳細は下にリンクを貼っておきますのでそちらをどうぞ。簡単にいうと、フォントサイズを指定する際、ポイントで指定する場合は3の倍数でないと半角と全角の幅の比が1:2になりません。これを防ぐには一つ目の原因と同様にstyleを指定する必要があります。同様にGreasemonkeyにそこまでさせるかという問題、さらに絶対単位か相対単位のどちらを用いるのかという問題もあります。
以上の理由により、今回のcodeではtextareaのcolsとrowsしかさわっていません。styleを指定してそのまま使われる可能性よりも、指定せずに置いた方が無難だと考えました(言い訳になりますが、書きはじめた段階では、addAutoResizeTextareaの中には「textarea.style.fontFamily="monospace";」と書かれていました。)。あと、憶測ですが、三番目が一番あやしいのではないかと思っています。
おまけ : 10.5という文字サイズ
昔のWindowsのアプリケーションでは10.5ptという非常に中途半端な文字サイズが選択肢にありました(今では11ptに置き換わっています)。何故、このようなサイズなのかというと、ピクセル換算した時に14pxと非常に都合の良い値となるためです。1ポイントが1/72インチというのは知られていますが、1/50や1/60、1/100ではなく1/72であるのは理由があります。72の約数は、「2,3,4,6,8,9,12,18,24,36」と豊富にあります。約数が多いという事は組版上、非常に都合がいいのです。例えば、1/4インチである18ポイントの場合を考えてみます。
18,9+9,6+12,6+6+6,...etc
1/100インチを1ポイントとした場合、約数は2,4,5,10,25,50だけです。1/60では「2,3,4,6,10,12,15,20,30」ですが、その後の組み合わせに多少無理が生じますし、6~10の間がありません。ここまでで収まっていればまだ良いのですが、まだ続きます。Macの場合、ディスプレイにおいても同じく1/72が基準となっています。こちらの単位はdpi(dot per inch)です。これはWYSIWYGが考慮されいるからだと思います。しかし、Windowsの場合、画面表示は96dpiです。ワープロ等で12ポイント(1/6インチ)で指定した文字を、画面でも1/6インチで表示しようとすると16ドット必要になります。「1,2,3,4,6,8,9,12,18,24,36,72」をWYSIWYGの為に変換すると(4/3を乗算)、「1+1/3,2+2/3,4,5+1/3,8,10+2/3,12,16,24,32,48,96」となり非常に混沌としてきます。しかも、画面表示の上で12ドット(1/8インチ)では小さ過ぎ16ドット(1/6インチ)では大き過ぎたため、間に14ドットの文字を定義してしまいました。これをポイントに換算すると、
14(dot) * 3/4(point/dot) = 10.5(point)
となります。これが10.5という文字サイズの正体です。