Shift + 矢印でリンクをフォーカスして Enter で onclick イベントは発生しない?

いやしますよね?
ニコニコ動画トップ のカテゴリメニューでおきた現象で疑問に思う.

画像のように Shift + 矢印でリンクをフォーカスして Enter を押すと http://www.nicovideo.jp/# へ飛んでしまう.マウスでクリックしたときと同じように onclick イベントが発生して XHR でページが置き換わると思ったんだが.

<a href="#" onclick="alert('i');">hoge</a>
<a href="#" onclick="alert('j');">fuga</a>

こんな簡単な HTML を作って同じ事をやってみたけど,思ったとおり Shift +_矢印後 Enter で onclick イベントが発生.


Opera のもうひとつのリンクを巡る方法として "A",”Q”キーを使うものがあるが,それも同じくニコ動カテゴリメニューでは oncklick イベントが発生せず.さらに,FirefoxChrome でタブキーを使ってリンクを巡って Enter も同じく onclick イベントが発生せず.
素直にマウス使えよと思うんだけど何が違うのか気になるな.
未解決.

環境

関係ないけど Opera が一番バージョン番号小さいのね...*1

*1:バージョン番号なんて飾りですよと

jQuery と CSS3 の :target セレクタを使ってスライドショーを作ってみた

:target セレクタの便利さを試してみたかったので作ってみた.


デモ: jQuery Slideshow with CSS3 :target selector


上下キーでページ切り替え.単純なページ切り替えしか実装していない.文字が追加で表示されるとか横から何か飛び出てくるとかはできない.
JavaScript 側ではフラグメント識別子を変更しているだけという手抜き仕様.


スライドショーといえば Opera Show が手軽なんだけど,Opera 以外じゃ動かないからね.


コード

使い方

HTML
<div>
	<p>page 1</p>
</div>
<div>
	<p>page 2</p>
</div>

<script type="text/javascript">
$("div").slideShow(); //それぞれの div を 1 スライドに
<script>

指定した要素に "slide" というクラスをつけている.

CSS
/* html と body を height: 100% にしているのは .slide の height を 100% にするため*/
html {
	height: 100%; 
}
body {
	height: 100%;
}
.slide {
	height: 100%;
	display:none;
}
.slide:target {
	display:block;
}

あとは .slide をお好みのスタイルにするだけ.

文字列から曜日を返す

function getDay(s) {
    return ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"][new Date(Date.UTC.apply(this,s.match(/(\d{4})?[^\d]*(\d{1,2})[^\d]*(\d{1,2})/).slice(1).map(function(e,i){switch(i){case 0:return e?e:(new Date()).getFullYear();case 1:return e-1;default:return e}}))).getDay()];
}

/*
getDay("2010/10/15") // Fri
getDay("2010年/10/16") // Sat 
getDay("10/17") //Sun **2010年に実行した場合
getDay("2010/9/1") // Wed
getDay("121") // 12月1日と解釈されてWedを返す.こういう場合1201 や 0121のように4桁で書くよね?
*/

1行で見にくい.
最後の例のように少し穴があるように思われる.
Firefox 3.6 + Firefbug 1.5.4 で動作確認

以下コードの解説

続きを読む

jQuery プラグイン 書いた

http://gist.github.com/590362
要素を縦方向のみリサイズできるように.要素の下につかんでドラッグできる要素を追加.

http://gist.github.com/592245
テキストエリアを自動で伸ばす.動作がカクカクで気持ち悪い.


デモ

delicious の recent ページにユーザリストをつけてみる

久々に JavaScript 書いてみたよ。
recent の タグページ(例: http://delicious.com/tag/opera)のサイドバーにそのタグをブックマークしたユーザのリストを表示するスクリプト
ユーザの並びがソートされてないのはめんどくさいから。手直しするならこの辺。



ダウンロード


動作確認: Windows Opera 10.60, Firefox 3.6

クラスをつけたり消したり

function hasClass(elm, _class) {
    if(!elm || !_class) return;
//    var regexp = new RegExp('\\b'+ _class + '\\b'); // \ をエスケープしないと駄目なことを知らずにはまった
//    var regexp = new RegExp('(^|[^\\w-])' + _class + '([^\\w-]|$)');
    var regexp = new RegExp('(^|\\s)' + _class + '(\\s|$)'); // 単純にこれでいける?
    return regexp.test(elm.className);
}

function addClass(elm, _class) {
    if(!elm || !_class) return;
    if(!hasClass(elm, _class)) {
        elm.className += ! elm.className ? _class  : ' ' + _class;
    }
}

function removeClass(elm, _class) {
    if(!elm || !_class) return;
    if(hasClass(elm, _class)) {
        elm.className = elm.className.replace(new RegExp(_class, 'g'), '')
                                     .replace(/\s+/g, ' ')
                                     .replace(/^\s|\s$/, '');
    }
}

JsUnit を使うために書いてみた。

JsUnit 用の テストコード

function testHasClass() {
    var el = document.createElement('div');
    el.className = 'hoge fuga foobar foo-bar';
    assert(hasClass(el, 'hoge'));
    assert(hasClass(el, 'fuga'));
    assertFalse(hasClass(el, 'foo'));
    assertFalse(hasClass(el, 'bar'));
    assertFalse(hasClass(el, 'oge'));
}
function testAddClass() {
    var el = document.createElement('div');
    addClass(el, 'hoge');
    assert(el.className == 'hoge');
    addClass(el, 'fuga');
    assert(el.className == 'hoge fuga');
    addClass(el, 'hoge');
    assert(el.className == 'hoge fuga');
}
function testRemoveClass() {
    var el = document.createElement('div');
    el.className = 'hoge fuga foobar fuga';
    assert(el.className == 'hoge fuga foobar fuga')
    removeClass(el, 'fuga');
    assert(el.className == 'hoge foobar');
    removeClass(el, 'hage');
    assert(el.className == 'hoge foobar');
    removeClass(el, 'hoge');
    assert(el.className == 'foobar');
}


JsUnit については JsUnit を使った JavaScript のユニットテスト - WebOS Goodies が詳しい。

追記

hasClass 駄目だな。クラス名に "foo-bar" が含まれているとき "bar" or "foo" でも true が返ってくる。

追記 2

とりあえず "-" ハイフン問題は大丈夫になった。他の文字にも対応すべきだろうけどパス。

追記 3

正規表現修正。単純になったけど、これで大丈夫かしら。テストの意味が…。

Opera の右クリックイベント検出

IE, Firefox, Safari だと

var d = document.getElementById('hoge');
d.oncontextmenu = function(e) {
    if(window.event) event.returnValue = false; // for IE
    else e.preventDefault();
    // なんらかの処理
}

のようなコードで右クリックでコンテキストメニューを表示させないで処理を実行できる。


しかし Opera の場合、同じような動作を実現することはできない。
まずデフォルトの状態だと右クリックを JavaScript で検出することさえできない。
検出できるようにするには、
Preferences -> Advanced -> Content -> JavaScript Options -> Allow script to recive right clicks*1
のチェックをつける。
さらに Opera には oncontextmenu というイベントハンドラがないので

d.addEventListener('mousedown', function(e) {
    if(e.button == 2) {
        // なんらかの処理
   }
}, false);

のように mousedown イベントをみる必要がある。まだ問題がある。コンテキストメニューを表示させないで処理を実行することができない。 preventDefault() でも駄目。


解決策ではないんだけど alert() を処理に含めればコンテキストメニューを表示させないで実行できる。もちろんアラートダイアログはでるけどね。


最後の手段として Opera 自体のコンテキストメニューを無効にしてしまう方法がある。
opera:config#UserPrefs|AllowContextMenus
のチェックをはずせば OK。ただし、いかなる場所でコンテキストメニューが表示されないので不便すぎる。

*1:日本語に読み替えてね