jQuery.flickSimple.js Android版 Firefox等に対応しました。


スマートフォン対応、気をつけたいトラブル

何気なく見ていたのですが、このスライドでも jQuery.flickSimple が紹介されていることを知りました。

FirefoxOperaでも動く方が望ましい

確かにそうですね。これまでの jQuery.flickSImple.js は Firefoxで動作していなかったようです。という訳で、また jQuery.flickSimple.js に手を加えましたので、お知らせします。

これまで、Webkitブラウザ以外は眼中に無かった(=jQuery.animate()でアニメーションするようにしていた)ので、ベンダープリフィックス「-webkit-」のCSSしか指定していませんでしたが、「-moz-」や「-o-」「-ms-」といったベンダープリフィックスに対応するように更新してみました。前回の「Androidでの表示パフォーマンスを向上」した件とあわせて、また少し使いやすくなったのではないかと思っております。

一部のブラウザではまだ動作確認ができていませんので、何か不具合があればお知らせいただけるとありがたいです。

jQuery.flickSimple Androidでの表示パフォーマンスを向上しました。

jQuery.flickSimpleを更新し、Androidでの表示パフォーマンスを向上しました。

久しぶりに自分のブログを更新したので眺めていたら、以下のサイトで jQuery.flickSimple が取り上げられているのを見つけました。

スマートフォン向けスワイプ・フリック系ライブラリのまとめ | BALLOG

イトーヨーカドーとかのサイトに使われているなんて、まったく知りませんでした。取り上げていただき、また有用な情報を掲載していただき、ありがとうございます。>BALLOGの方

Androidでの動作」が「△」で、他と比べてイマイチなんだそうです。これではイカンと思い「◯」になっているライブラリがどのような実装になっているのか拝見したところ、みなさん CSSアニメーション(-webkit-transform: translate())を使用しているようですね。

以前は、iOSの場合は -webkit-transform: translate3d() を、Androidを含むその他の場合は jQuery.animate() を使用してアニメーションさせていました。Androidの場合 translate3d() を使うとおかしな挙動をすることがあったので、CSSアニメーション自体を使わない実装にしていたのですが、「translate3d()」でなく「translate()」であれば問題ないのですね。

実際、Android 2.3 の実機で比べてみたところ、確かに -webkit-transform: translate() の方がスムーズに動くようです。

という訳で、これまで Androidでイマイチなんだよなぁ、と思っていたみなさま、多少は良くなったと思いますので、お試しくださいませ。

10桁・13桁のISBNを相互に変換するPerlワンライナー

ISBN(世界的に使われている書籍の識別番号)には、10桁のものと13桁のものがあります。

http://ja.wikipedia.org/wiki/ISBN

仕事でISBNを相互に変換するプログラムが必要になったのですが、CPANモジュール(Business::ISBN)を使うほどの処理でもないし、単純な実装のものが見つからなかったので自前で実装しました。ついでに、これワンライナーでも書けるんじゃね、と思い立ったのでPerlワンライナーも作ってみました(ちょっと冗長なのでワンライナーにする意味はあまり無かったかなぁとも思いつつ)。

ISBN-13 → ISBN-10

perl -le '@a=map{$s+=(10-$i++)*$_;$_;}(grep{/\d/}split(//,shift))[3..11];$d=(11-$s%11)%11;print @a,$d==10?q{X}:$d' [ISBN]

ISBN-13 → ISBN-10(ハイフン付き)

perl -le '@a=map{$s+=(10-$i++)*$_;$_;}(grep{/\d/}split(//,shift))[3..11];$d=(11-$s%11)%11;printf(qq{%d-%d%d%d%d-%d%d%d%d-%d\n},@a,$d==10?q{X}:$d' [ISBN]

ISBN-10 → ISBN-13

perl -le '@a=map{$s+=($i++%2?1:3)*$_;$_;}(grep{/\d/}split(//,shift))[0..8];print 978,@a,(10-($s+8)%10)%10' [ISBN-10]

ISBN-10 → ISBN-13(ハイフン付き)

perl -le '@a=map{$s+=($i++%2?1:3)*$_;$_;}(grep{/\d/}split(//,shift))[0..8];printf(qq{978-%d-%d%d%d%d-%d%d%d%d-%d\n},@a,(10-($s+8)%10)%10)' [ISBN-10]

[ISBN-13] あるいは [ISBN-10] を実際の ISBNに置き換えて実行してください。指定するISBNは、ハイフン有りでも無しでも構いません。

ワンライナーですので、エラー処理などはしていません。不正なISBNを渡すと不正な値を返すと思います。

ちゃんと書くと、以下のようになるのでしょうかね。

# ISBN13 → ISBN10
sub isbn13_to_10 {
	my ( $isbn, $hyphen ) = @_;
	$isbn =~ s/\D//g;
	return if ( ! $isbn || $isbn !~ /^\d{13}$/ );
	
	my @isbn10 = (split(//, $isbn))[3..11];
	push @isbn10, isbn10_digit( @isbn10 );
	
	return sprintf( "%d-%d%d%d%d-%d%d%d%d-%d", @isbn10 ) if ( $hyphen );
	return join( '', @isbn10  );
}

# ISBN-10 のチェックディジットを求める
sub isbn10_digit {
	my @ints = @_;
	my $i = 0;
	my $sum = 0;
	foreach my $int ( @ints ) {
		$sum += (10 - $i) * $int;
		$i++;
	}
	my $digit = ( 11 - $sum % 11 ) % 11;
	return ($digit == 10 ? 'X' : $digit);
}

# ISBN10 → ISBN13
sub isbn10_to_13 {
	my ( $isbn, $hyphen, $prefix ) = @_;
	$prefix ||= '978';

	$isbn =~ s/[^0-9x]//ig;
	return if ( ! $isbn || $isbn !~ /^\d{9}[0-9x]$/i );
	
	my @isbn13 = ( split(//, $prefix), (split(//, $isbn))[0..8] );
	push @isbn13, isbn13_digit( @isbn13 );
	
	return sprintf( "%d%d%d-%d-%d%d%d%d-%d%d%d%d-%d", @isbn13 ) if ( $hyphen );
	return join( '', @isbn13 );
}

# ISBN-13 のチェックディジットを求める
sub isbn13_digit {
	my @ints = @_;
	my $i = 0;
	my $sum = 0;
	foreach my $int ( @ints ) {
		$sum += ($i % 2 ? 3 : 1) * $int;
		$i++
	}
	return ( 10 - $sum % 10 ) % 10;
}


# ISBNとして正しくない場合、正しいISBNを返す
# 正しいISBNを求められない場合は、-1 を返す
sub isnt_isbn {
	my $isbn = shift;
	$isbn =~ s/[^0-9x]//ig;
	return -1 if ( ! $isbn );
	
	if ( $isbn =~ /^\d{9}[0-9x]$/i ) {
		my @arr = (split(//, $isbn))[0..8];
		my $isbn10 = join( '', @arr, isbn10_digit( @arr ) );
		return $isbn10 if ( uc( $isbn ) ne $isbn10 );
		return;

	} elsif ( $isbn =~ /^\d{13}$/ ) {
		my @arr = (split(//, $isbn))[0..11];
		my $isbn13 = join( '', @arr, isbn13_digit( @arr ) );
		return $isbn13 if ( $isbn ne $isbn13 );
		return;
	}
	return -1;
}

jQuery.flickSimple 縦フリックに対応しました。

iPhoneの特徴的なインタフェースであるフリック操作を、iOSAndroid、PC上のブラウザで実現するjQueryプラグインjQuery.flickSimpeをアップデートしました。

今回のアップデートの目玉は、縦フリック対応です。

#縦だとフリックとは言わないのですかね。この辺りの操作の名前がよくわかりません・・・。

iPhoneAndroidで、overflow: scroll; にしたい時のスクロールの処理にも使っていただけると思います。

現時点で、まだAndroidの実機での動作が確認できていません。上手く動かないようであれば、お知らせをいただければと思います。また、お急ぎであれば、古いバージョンをお使いいただければと思います。

Jedit X で Markdown(とついでにPOD)

Markdownとは?

Markdownとは「軽量マークアップ言語の1つ」で、簡単な記法で書いたテキストをHTMLに変換してくれる仕組みです。Wikiや「はてな記法」みたいなものですね。

Markdown」というものがあることは知っていたのですが、githubの「README.md」がこの方式だったので、改めて記法などを調べてみた訳です。HTMLを埋め込めるなど、マニュアル等を作るのに使いやすそうですね。

既にいろんなCMSテキストエディタMarkdownに対応しているそうですが、愛用のテキストエディタJedit X」についての情報は見つけられなかったので、例のようにJedit Xのマクロ(=AppleScript)を作ってみました。

MarkdownSafariでプレビュー

Markdownのオリジナル版はPerlで実装されていて、以下でダウンロードできます。

http://daringfireball.net/projects/markdown/

まずはこれを入手して、「Markdown.pl」を Jedit X の「scripts」フォルダ(~/Library/Application Support/Jedit X/scripts/Markdown.pl)に入れておきます。

で、以下のようにAppleScriptを書きました。

tell document 1 of application "Jedit X"
    save
    set fPath to path as POSIX file
    set pPath to POSIX path of fPath
    set tmppath to pPath & ".preview.html"
    
    set existsflg to false
    tell application "Finder"
        set existsflg to exists file tmppath as POSIX file
    end tell
    
    if not existsflg then
        set scpt to "perl ~/Library/Application\\ Support/Jedit\\ X/scripts/Markdown.pl " & quoted form of pPath & " > " & quoted form of tmppath
        do shell script scpt
        
        tell application "Safari"
            activate
            open tmppath as POSIX file
        end tell
        
        delay 1
        do shell script "rm -f " & quoted form of tmppath
     end if
end tell

上記を「AppleScriptエディタ」にコピペして、「MarkdownSafariでプレビュー.scpt」とかの名前で保存、Jedit Xの「スクリプトウィンドウ」に放り込めば完成です。

元のファイル名に「.preview.html」を加えたファイルをテンポラリファイルとして作ってます。無闇に上書きしてしまうとまずいので、既に同名のファイルがある場合には何もしないようにしてあります。

Safariでプレビューしますが、他のブラウザがよければ、「tell application "Safari"」のくだりをお好きなブラウザに書き換えてもらえばよいですね。ちなみに、Chrome の場合は、

        tell application "Google Chrome"
            activate
            --     open tmppath as POSIX file
            open location "file://" & tmppath
        end tell

としないと開きませんでした。

ついでに POD も。PODをSafariでプレビュー

同じような軽量マークアップ言語の1つとして「POD = Plain Old Documentation」というPerlを書く人にはお馴染みの記法があります。これも同じようにできるなぁ、と思ったので作ってみました。

Mac OS X であればデフォルトで「pod2html」というコマンドが入っていますので、こちらはダウンロードとかする必要はありません。

tell document 1 of application "Jedit X"
    save
    set fPath to path as POSIX file
    set pPath to POSIX path of fPath
    set tmppath to pPath & ".preview.html"
    
    set existsflg to false
    tell application "Finder"
        set existsflg to exists file tmppath as POSIX file
    end tell
    
    if not existsflg then
        set scpt to "pod2html " & quoted form of pPath & " > " & quoted form of tmppath
        do shell script scpt
        
        tell application "Safari"
            activate
            open tmppath as POSIX file
        end tell
        
        delay 1
        do shell script "rm -f " & quoted form of tmppath
        do shell script "rm -f ./pod2htmd.tmp"
        do shell script "rm -f ./pod2htmi.tmp"
    end if
end tell

ちなみに、両方ともプレビューするだけなので出力したHTMLは消しちゃっていますが、出力するためのスクリプトも登録しておくと便利かもしれませんね。

iPhone と Android の onOrientationChange タイミングの違い

またスマートフォン対応サイトネタ、Androidネタです。

Androidのブラウザにて。Android 2.2から、iPhoneと同じように縦持ち・横持ちが変わった際に発生するイベント「window.onorientationchange」が使えるようになっているようです。ですが、このイベントが起きるタイミングがiPhoneAndroidで異なっているようです。

var $win = $(window);
var debug = $('#debug');
$win.bind( 'orientationchange', function() {
    debug.html( debug.html() + 'orient:' + $win.width() + ', ' );
} )
.bind( 'resize', function(){
    debug.html( debug.html() + 'resize:' + $win.width() + ', ' );
} );

上のJavaScriptを実行すると、iPhoneの場合は、

  • ウィンドウのサイズ変更 → resizeイベント → orientationchangeイベント

という順番でイベントが発生していることがわかります(なんだか、resizeイベントが2回発生するケースもあるみたい)。

ところが Android 2.2の場合は、

  • orientationchangeイベント → ウィンドウのサイズ変更 → resizeイベント

という順番になります。

ちなみに、Android 2.1以前は、typeof window.onorientationchange === 'undefined' なので、

  • ウィンドウサイズの変更 → resizeイベント

となっています。

orientationchangeイベントだけだと、iPhoneの場合は変更後の、Androidの場合は変更前の値を持ってきてしまうことになりますので、ウィンドウサイズを元に表示を変更しようとした場合にはおかしなことになってしまいます。以下のように判定をしている場合には、注意が必要ですね。

if ( typeof window.onorientationchange === 'object' ) {
     $(window).bind( 'orientationchange', function(){ hoge(); } );
} else {
     $(window).bind( 'resize', function(){ hoge(); } );
}

Androidの場合には、resizeイベントを使うようにすると、iPhoneと共通化ができると思います。

var isAndroid = navigator.userAgent.indexOf('Android') != -1;
if ( typeof window.onorientationchange === 'object' && ! isAndroid ) {
     $(window).bind( 'orientationchange', function(){ hoge(); } );
} else {
     $(window).bind( 'resize', function(){ hoge(); } );
}

ちなみにAndroidのresizeイベントは、アドレスバーが表示されている間はスクロールするだけで発生するようなので、重い処理はさせないほうが良さそうです。

Androidのタップ ハイライトについて

Androidのブラウザにて。Android 2.2 までと 2.3 で、アンカーやonclickイベントの付与された要素(エレメント)をタップした時に付くハイライトの挙動が変わっています。
Android 2.2 までは、以下のようになっているようです。

a) アンカーには、全てハイライトが付く。
b) onclickイベントが付与された要素には、ハイライトが付く。
c) 親要素にonclickイベントが付与されている場合、子要素にクリック可能な要素(アンカータグ、またはonclickイベントが付与された要素)が "1つしか存在しない場合" は、親要素がハイライトされる。2つ以上クリック可能な要素がある場合には、個別にハイライトされる。

a) ・ b) はいいとしよう。ハイライトを見せたくない場合には、以下のCSSで消すことができます。

  -webkit-tap-highlight-color: rgba(0,0,0,0);


c) については、具体例を挙げると、

  <div id="oya" onclick="hoge();">
    <a href="hoge.html"></a> | <a href="hoge.html"></a>
  </div>

 上記の場合は、「兄」と「弟」がそれぞれハイライトされます。これは問題ない。

  <div id="oya" onclick="hoge();">
    <a href="hoge.html">子供</a>
  </div>

 上記の場合、「子供」をタップしても、<div id="oya">〜</div>がハイライトされてしまいます。子要素のonclickイベントで、event.stopPropagation();(イベントのバブリングを中断)するようなケースもよくあるので、これは困った仕様ですね。

なんでこんな仕様にしてしまったのだろう・・・。ますますAndroidが発展途上のOSに思えてくる。

ちなみに、Android 2.3からは仕様が変わっています。