Archive for the ‘JavaScript’ Category

売ります:重複購入したCSS・Ajax本

Wednesday, March 26th, 2008

Amazon でたまにやらかしてしまうのが、同じ本の重複購入。特に技術書は表紙も書名も似たようなものばかりで、読んだかどうか・買ったかどうか、深夜あまり良く考えずにボタンを押し後で後悔することになる。

読んでも開いてもいない本を持ってても意味ないので、以下2冊(種類)をどなたかにお譲りしたいと思ってます。ご希望の方はメールなどでお知らせください。

img_0399.jpg img_0400.jpg

※どちらも洋書ですが、出てくる単語は日本語圏でもよく使うものばかりで割と読めると思います。

packer decoder

Friday, January 18th, 2008

JavaScript の圧縮・難読化ツールの定番 /packer/ で pack したコードを decode するツールを作成。

packer decoder
http://blog.shimazu.org/utils/packer_decoder.html

たとえば

eval(function(p,a,c,k,e,r){e=function(c){return c.toString(a)};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p}('1.3.6.8(h,\\'e\\',9(){1.3.6.8(\\'m\\',\\'k\\',9(){0 g=1.3.6;0 5=1.3.c;0 d=1.o;0 a=5.7(\\'l\\');0 b=5.7(\\'j\\');i("0 2=f"+a.2.n(4));b.2=2})});',25,25,'var|YAHOO|value|util||D|Event|get|addListener|function|||Dom|L|load|String|E|window|eval|out|click|in|run|slice|lang'.split('|'),0,{}))

というコードをツールにかけると

YAHOO.util.Event.addListener(window,'load',function(){YAHOO.util.Event.addListener('run','click',function(){var E=YAHOO.util.Event;var D=YAHOO.util.Dom;var L=YAHOO.lang;var a=D.get('in');var b=D.get('out');eval("var value=String"+a.value.slice(4));b.value=value})});

といったコードが得られる。

#これを Js Decoder にかければインデントもしてくれる。

つくりは簡単だけど、自分的にとても役立っている。

2008/01/24追記
decode前のサンプルコードにミスがあり、decoderで正しく処理できてなかったので、修正。

OpenSearch

Sunday, January 6th, 2008

Firefox 2 や IE 7 で使えるようになったブラウザに組み込めるサイト検索の仕組み「OpenSearch」をこのサイトも対応したのでメモしておく。

opensearchbar.png

以下参考にさせていただいた。

定義XMLの作成

まず、検索URLなどを定義するXMLを作成する。

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
  <ShortName>blog.shimazu.org</ShortName>
  <Description>blog.shimazu.org</Description>
  <InputEncoding>utf-8</InputEncoding>
  <Image width="16" height="16">http://blog.shimazu.org/favicon.ico</Image>
  <Url type="text/html" method="GET" template="http://blog.shimazu.org/index.php?s={searchTerms}" />
</OpenSearchDescription>

Imageタグの箇所にはBase64形式のデータも格納可能で、[JavaScript] dataスキームURI生成(画像データのBase64変換) にて、「画像URL」の箇所に http://blog.shimazu.org/favicon.ico などと入力すると、

var data = 'data:image/x-icon;base64,'+
    'R0lGODlhEAAQALMAAP///+Xl5UBAQL+/v6ampllZWU1NTbOzs2ZmZvLy8oCAgMzMzJmZmebm5gAA'+
    'AAAAACH5BAAAAAAALAAAAAAQABAAAARGMMhJqwQ4a323xx0mDB8QAmN5jgSzbGthFALBBZqAYIRw'+
    '5wdMIgXCZYgoUjFnAwwEjcyqdijspEYRwSBQJH4lWDZctJglEQA7';

といった感じでBase64変換される。これを使うと以下のようになる。

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">
  <ShortName>blog.shimazu.org</ShortName>
  <Description>blog.shimazu.org</Description>
  <InputEncoding>utf-8</InputEncoding>
  <Url type="text/html" method="GET" template="http://blog.shimazu.org/index.php?s={searchTerms}" />
<Image width="16" height="16" type="image/x-icon">data:image/x-icon;base64,R0lGODlhEAAQALMAAP///+Xl5UBAQL+/v6ampllZWU1NTbOzs2ZmZvLy8oCAgMzMzJmZmebm5gAAAAAAACH5BAAAAAAALAAAAAAQABAAAARGMMhJqwQ4a323xx0mDB8QAmN5jgSzbGthFALBBZqAYIRw5wdMIgXCZYgoUjFnAwwEjcyqdijspEYRwSBQJH4lWDZctJglEQA7</Image>
</OpenSearchDescription>

今回は単に画像URLの指定でXMLを作成し、 http://blog.shimazu.org/utils/opensearch.xml に置いた。

linkタグの追加

headタグの中に以下linkタグを追加する。

<link rel="search" type="application/opensearchdescription+xml" title="blog.shimazu.org" href="http://blog.shimazu.org/utils/opensearch.xml">

すると、以下のような登録メニューを出せるようになる。

opensearch.png

aタグの追加

「Meta」サイトバーに「Add to Search Bar」リンクを追加するため、以下スクリプトを追加した。

function installOpenSearch(engineURL) {
    if (!engineURL) return true;
    window.external.AddSearchProvider(engineURL);
}

(function(){
    var E = YAHOO.util.Event;
    var D = YAHOO.util.Dom;
    E.addListener(this, 'load', function(){
        if (typeof window.external == "object" && typeof window.external.AddSearchProvider == "function") {
            var ul = D.getNextSibling('sidebarMeta');
            if(ul) ul.innerHTML += '<li><a href="javascript:void(0)" onclick="return installOpenSearch(\'http://blog.shimazu.org/utils/opensearch.xml\');">Add to Search Bar</a></li>';
        }
    });
})();

上記に記載の

typeof window.external == "object" && typeof window.external.AddSearchProvider == "function"

という条件式は、「OpenSearch」対応ブラウザか否かを判別するが、Mozilla Japan – アドオン – Firefox – 検索エンジン に記載のスクリプトを参考にさせていただいた。

YUI Compressor on Debian GNU/Linux (Etch)

Sunday, December 30th, 2007

jsminpacker などと並び、定番になりつつある JavaScript コード圧縮ツール Yahoo! UI Library: YUI Compressor を Debian GNU/Linux (Etch) に導入したので、備忘までメモしておく。

以下 URL より YUI Compressor をダウンロードする。

Download the YUI Compressor
http://www.julienlecomte.net/yuicompressor/

YUI Compressor は Java によるコマンドラインツール、PHP でそれをラップしたウェブのインターフェースが用意されているが、両方を動かすため以下設定を行った。

/etc/apt/sources.list に non-free を追加し、以下のようにした(後述する sun-java5-jre パッケージのインストールにあたり、non-free の追加が必要になる)。

deb http://ftp.jp.debian.org/debian/ etch main contrib non-free
deb-src http://ftp.jp.debian.org/debian/ etch main contrib non-free

deb http://security.debian.org/ etch/updates main contrib non-free
deb-src http://security.debian.org/ etch/updates main contrib non-free

以下コマンドでパッケージインストール。

aptitude install php5 php5-cli sun-java5-jre

詳細は未調査だが、デフォルトのままだと PHP のクオート文字のエスケープ処理が自動的に入ってしまうため、/etc/php5/apache2/php.ini の以下設定を Off にして、自動処理を解除しておく。

; Magic quotes
magic_quotes_gpc = Off ; magic quotes for incoming GET/POST/Cookie data

これで設定が完了。ブラウザで該当する URL をたたくと以下画面が表示される。

yuicompressor.png

ためしに以下を入力し、「Compress」ボタンを押すと

(function(){
    var _str = "Hello world!!";
    alert(_str);
})();

以下のような結果が得られた。

(function(){var A="Hello world!!";alert(A)})()

YSlowによるパフォーマンス改善

Sunday, September 23rd, 2007

サーバがアメリカ西部にある+サーバレンタル契約がエントリープランなので、やむなし的なところはあるけど、この blog の表示速度は概してよくなく、パフォーマンス改善が必要な状態にあった。そこで、YSlow を使って、ボトルネックの洗い出し、および、ボトルネック解消による効果検証を行った。

YSlow
http://developer.yahoo.com/yslow/

YSlow のベースとなる考え方は Exceptional PerformanceHigh Performance Web Sites (slides) に示されているが、以下13項目を実行に移すことがパフォーマンス改善につながるとしている。JavaScript/CSS を外部ファイルに、といった基本的なことのみならず、CSS はページ冒頭に、JavaScript はページ下部に、といったもう一歩踏み込んだ形で改善方法を示しているのが、興味深い。

Rules for High Performance Web Sites

  1. Make Fewer HTTP Requests
  2. Use a Content Delivery Network
  3. Add an Expires Header
  4. Gzip Components
  5. Put CSS at the Top
  6. Move Scripts to the Bottom
  7. Avoid CSS Expressions
  8. Make JavaScript and CSS External
  9. Reduce DNS Lookups
  10. Minify JavaScript
  11. Avoid Redirects
  12. Remove Duplicate Scripts
  13. Configure ETags

Exceptional Performance より)

この個人 blog で CDN なんて無理、広告やアクセス統計で外部ドメインの JavaScript を読み込んでるので、DNS Lookup を減らしようがない、といったところはあるけど、上記に基づき、いくつか改善を行ったので、メモしておく。

改善1 – mod_gzip による gzip 化

まず Gzip 化について。Gzip 化にあたり、使用しているサーバ環境(Debian GNU/Linux Sarge)では、以下パッケージが必要になるので、apt-get でインストール。

libapache-mod-gzip
http://packages.debian.org/sarge/libapache-mod-gzip

※注
apache 2.0 以降は、mod_gzip ではなく mod_deflate を使う模様。現在の環境が、apache 1.3 系なため、mod_gzip を使う前提で話を進める。

/etc/apache/modules.conf に以下記述が追加されていることを確認する。

LoadModule gzip_module /usr/lib/apache/1.3/mod_gzip.so

apache の設定ファイルに、以下記述を追加する。

<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_can_negotiate Yes
mod_gzip_update_static No
mod_gzip_temp_dir /tmp
mod_gzip_keep_workfiles No

mod_gzip_minimum_file_size 500
mod_gzip_maximum_file_size 0
mod_gzip_maximum_inmem_size 60000
mod_gzip_min_http 1000
mod_gzip_handle_methods GET POST

mod_gzip_dechunk yes

mod_gzip_item_include file \.css$
mod_gzip_item_include file \.js$
</IfModule>

Netscape 3-4 で gzip 化された JavaScript が読めない、といった環境ごとに細かいバグがあるようだけど、取り急ぎ放置。

改善2 – PHP 側での gzip 化

上記だけでは、HTML ファイルの gzip 化がなされないので、PHP の設定ファイル /etc/php4/apache/php.ini に以下設定を追加した。

zlib.output_compression = On

改善3 – Expires Header

次に Expires Header について。以下を apache の設定ファイルに追加することにより対応完了。

ExpiresActive On
ExpiresDefault "access plus 10 years"

改善4 – ETag

次に ETag について。以下を apache の設定ファイルに追加することにより対応完了。

FileETag none

改善5 – CSS ファイル統合

この blog では、以下3つの CSS が使われており、YUI のものだったり、WordPress のテーマ付属のものだったり、と由来は異なるが、全ページに読み込まれるものなので、main.css ということでひとつにまとめた。

  • reset-fonts-grids.css
  • autocomplete.css
  • style.css

なお、JavaScript については、先日の 記事検索の autocomplete 化 の際に統合済み。

効果測定

上記の改善を踏まえ、http://blog.shimazu.org/ での読み込みスピードで実施前後の比較を行った。

まずページ容量について。Firebug でページ容量を比較すると、

  • 改善前: 276KB
  • 改善後: 148KB

ということで、同じコンテンツなのに gzip 化により半分近い容量削減となった。改善前(左)・改善後(右)のキャプチャは以下のとおり。

改善前改善後

YSlow の Performance Grade と呼ばれる指標でも比較してみた。すると、

  • 改善前: Performance Grade: F (56)
  • 改善後: Performance Grade: C (75)

といった感じで、こちらも改善が見られた。詳細結果は以下のとおり。

performance2.png

最後に、ページ読み込み速度を、yslow のステータスバーに読み込み時間を表示する機能を使って計測した。10回計って、平均を算出、という方法で、

  • 改善前: 3.9954秒
  • 改善後: 3.1822秒

という数字上はそれほど差が大きくないが、体感的には少し早くなったかな?という感じがする。詳細結果は以下のとおり。

performance.png

ということで、YSlow によるボトルネック洗い出しとその改善を行ったが、Gzip は設定に若干てこずったものの、その他は簡単に実行可能な改善策で、結果を見ても、これらの施策は非常に有用な印象を持った。今後開発など進めるうえで表示パフォーマンスが気になったら、まず今回のような改善策を試そうと思う。

記事検索の autocomplete 化 (2)

Sunday, September 2nd, 2007

autocomplete.png

実装完了。

YUI のコードをコピペしただけで、インタラクションがちょっと中途半端(?)だけど。詰め作業は追ってやるつもり。

記事検索の autocomplete 化

Friday, August 31st, 2007

ブログを書く間もないほど仕事があわただしい日々が続いているが、以前からやろうとしている記事検索の autocomplete 化について、備忘までにメモしておく。

実装しようとしている autocomplete とは、(いうまでもないかもだけど)検索キーワードを何文字かキータイプしただけで何らかの補足情報が出る仕組み。「何らかの補足情報」とわざとぼかして書いたのは、サイトやアプリケーションによって、中身が微妙に違うからで、以下のように「関連語・頻出語の提示」と「ダイジェスト結果の提示」に分かれる(と思われる)。

関連語・頻出語の提示

ダイジェスト結果の提示

今回やろうとしているのは、「ダイジェスト結果の提示」のほう。関連するものの呼び出しとか素敵だけど、実装が手間そうだし、それ以前にそんなに記事も多くないので、割と簡単な「ダイジェスト結果の提示」で進めることにした。

まずはサーバ側での対応から。WordPress 向けテーマファイルをいろいろ見ているうちに、うまく使えそうな以下コードがあった(一部省略)。

<?php
require("../wp-blog-header.php");
$posts = query_posts('posts_per_page=10&s='.$_GET['s'].'&what_to_show=posts');
?>
<?php
if (!$posts) {
    echo '<div>Sorry, no results.</div>';
} else {
    foreach ($posts as $post) {
        start_wp(); ?>
        <div>
            <a href="<?php echo get_permalink() ?>" title="Permanent Link to '<?php the_title(); ?>'"><?php the_title(); ?></a>
            <a href="<?php comments_link(); ?>" title="Go the the comments for this entry"><?php comments_number('0', '1', '%'); ?></a><br />
            <?php /* If 'Dunstan's Time Since' plugin is installed use it; else use default. */
            if (function_exists('time_since')) {
                echo time_since(abs(strtotime($post->post_date_gmt . " GMT")), time());
                echo ' ago';
            } else {
                the_time('F jS, Y');
            }
            ?>
        </div>
<?php
    }
}
?>

これによりでシンプルな検索結果一覧を表示できるので、JSON とか受け取りやすいフォーマットに整形すれば JavaScript や Flash などでいろんなインタラクションがつくれそう。

フロントエンドでの実装には Yahoo! UI Library: AutoComplete を使用予定。安定した動作、上下キーでフォーカス移動、そして何より、Yahoo! トップページ での利用実績が強みと思われる。

補足:
PHP コードに登場する ‘Dunstan’s Time Since’ plugin とは日時の相対表示を実現するプラグインの模様。以下から取得でき、割とシンプルな実装で、使い勝手がありそう。
http://binarybonsai.com/wordpress/time-since/

Yahoo! User Interface Library 開発者の講演(@アップルストア銀座)

Sunday, July 8th, 2007

CSS Nite公式ブログ によると、8月10日(金)19:00-20:10、YUI (Yahoo! User Interface Library) の Thomas Sha 氏 によるスピーチがアップルストア銀座にて行われるとのこと。

US からわざわざ来日されてのスピーチということで、都合がつけば参加するつもり。

’Save This Page’ Button – Yahoo!ブックマークに対応

Thursday, June 7th, 2007

del.icio.usはてなブックマーク に引続き、Yahoo!ブックマーク に対応。下記を参考に、登録ボタンと登録数表示の両方をとりつけてみた。

登録数表示の JavaScript コードのスタイルが若干古め?な感じなので、ちょっと困ってしまった。登録数を表示するには、表示したい箇所に

<script type="text/javascript" src="http://num.bookmarks.yahoo.co.jp/ybmno.php"></script>

を入れればよいことになっている。ブラウザでロードすると、この script タグは、以下を返してくるが、

document.write('<a href="http://bookmarks.yahoo.co.jp/url?url=http%3A%2F%2Fblog.shimazu.org%2Farchives%2F117">1')

いきなり HTML に書き込んでいるのに加え、a タグの閉じタグがなく自分で付け足すほかなし、といった感じでプログラム制御がとてもしづらい感じになってしまっている。せめて登録数だけ返すとか、id 指定に基づき既存の HTML タグに値を入れ込むとか、JSONP とか、表示と分離された実装が望ましいように思う。

結局、以下のようなコードを記事テンプレートに書き、

<a href="http://bookmarks.yahoo.co.jp/action/post"
onclick="window.open(); return false;">
Add to Yahoo! Bookmarks</a>
<span id="yahoobookmarks">
<script type="text/javascript" src="http://num.bookmarks.yahoo.co.jp/ybmno.php">
</script>
</a></span>

※一部省略
※あらかじめ span タグは display:none; を指定

JavaScript 外部ファイルには(若干回りくどい)以下コードを追加した。

(function(){
var E = YAHOO.util.Event;
var D = YAHOO.util.Dom;
// snip
E.addListener(this, 'load', function(){
	var a = D.get('yahoobookmarks').childNodes[1];
	var i;
	if( a && (i=parseInt(a.innerHTML)) ) {
		a.innerHTML = i + (i==1?'user':'users');
		D.setStyle('yahoobookmarks','display','inline');
	}
});
})();

過去の関連記事:

追記(2007/06/08):
同僚 T 氏からいただいた指摘を受け、JavaScript コードを若干修正。

Flickr 風の検索フォーム

Tuesday, May 29th, 2007

searchinput.png

ページ要素を整理すべく、検索フォームの場所を(ヘッダ部分に)移動のうえ、Flickr 風なインタラクションをもったかたちに改良。あわせて input タグに accesskey 属性を追加し、キーボード操作で検索フォームにカーソル移動できるようにした。

HTML は以下のとおり。

<form method="get" action="http://blog.shimazu.org/index.php">
<input type="text" accesskey="f" name="s" id="searchinput" />
</form>

JavaScript コードは以下のとおり。実装において、Yahoo! UI Library (YUI) の yahoo-dom-event.js を使用した。最近よく見る直感的なインタラクションだけど、コードは思いのほか直感的ではない。

(function(){
var defalutvalue = 'Search...';
var edited = false;
var E = YAHOO.util.Event;
var D = YAHOO.util.Dom;
E.addListener('searchinput', 'focus', function(){
    if(this.value == defalutvalue && !edited) this.value = '';
});
E.addListener('searchinput', 'blur', function(){
    if(this.value == '') {
        this.value = defalutvalue;
        edited = false;
    } else {
        edited = true;
    }
});
E.addListener(this, 'load', function(){
    D.get('searchinput').value = defalutvalue;
});
})();

実装途中で気づいたけれど、Firefox の accesskey の操作がバージョン 2.0 から変わった模様。従来、[ Alt + Access Key ] だったのが、[ Alt + Shift + Access Key ] となっている。