こんばんは、martinです。久しぶりの更新です。アップした写真をお洒落に見せるスクリプトがIE9βでは動かないとのご指摘があったので、IE9βでも動くようにアップデートしました。既存のものをそのまま置き換えるだけで良いと思います。
IE9βでは、念願のCANVAS要素がサポートされています。なので、IE8以下では従来のようにVMLを利用、IE9以上であれば他のモダンブラウザと同じようにCANVAS要素で描画するようにしています。
最新版のphotoeffect.jsを添付しておきます。
2010/10/15
こんばんは、martinです。久しぶりの更新です。アップした写真をお洒落に見せるスクリプトがIE9βでは動かないとのご指摘があったので、IE9βでも動くようにアップデートしました。既存のものをそのまま置き換えるだけで良いと思います。
IE9βでは、念願のCANVAS要素がサポートされています。なので、IE8以下では従来のようにVMLを利用、IE9以上であれば他のモダンブラウザと同じようにCANVAS要素で描画するようにしています。
最新版のphotoeffect.jsを添付しておきます。
— posted by martin at 07:54 am Comment [64] TrackBack [0]
2010/7/31
カテゴリー » 開発日誌 » JavaScript
もう7月も終わりですね、martinです。相変わらず時の流れは速いもので。
このサイトのブログの基本テーマ(スキン)「Basic」では、試験的にHTML5を導入しています。HTML5では新しい要素がいくつか追加 されていますが、IE9未満のブラウザでは、articleやheader, navなどのクールで新しい要素に対するスタイルシート指定が効かない、という事が昔から知られています。これに対するアプローチとして、 document.createElementを使うとスタイルシートでの指定が可能になるよ、というのがよく知られています。初出は Sjoerd Visscher さんあたりでしょうかねぇ。document.createElement(”article”); // 未知の要素articleに対してIEでもCSS指定が可能になる
このdocument.createElementを使うテクニックは、いろんなところで見かけることができて、有名どころでは、Remy sharp氏のhtml5.js あたりですね。
もっとも、このテクニックを使っただけでは、IEでHTML5化を効かせたページを印刷したときまでは反映されないので、これに対しては、IE Print Protector がよく知られていると思います(個人的には、印刷のサポートまではあまり興味がありませんが)。
で、このcreateElementを使うテクニックは、ベタに書けば以下のような感じになります。
// ここでは簡潔化のため、以下の6個の新要素に絞ってます。 <!--[if lt IE 9]> var html5_elements = ["header", "nav", "article", "section", "aside", "footer"]; for (var i = 0, len = html5_elements.length; i < len; i++){ document.createElement(html5_elements[i]); // 各要素に適用 } <![endif]-->どこで最初に見かけたのか失念しましたが、これを一行(ワンライナー)で簡潔に済ませたスクリプトを見たときはいたく感心しました。Dean Edwards氏のブログ もこうなっています。
"header,nav,article,section,aside,footer".replace(/¥w+/g, function(a){document.createElement(a)});上のポイントは、replaceメソッドの引数に関数を指定できて、その関数内では、正規表現にマッチした要素を適宜適用していく点です。ループみたいなことを勝手にやってくれる点ですね。おそらくこれ以上短くは書けないのではないかと思うのですが、息抜きに自分なりにいくつか考えてみました。
"header,nav,article,section,aside,footer".split(',').sort(function(a){return document.createElement(a)*1});これも、似たような発想からですね。自動でなんかやってくれるという。
with("header,nav,article,section,aside,footer".split(',')))while(length)document.createElement(pop());ここではwith構文を使ってみました。これもなかなかシンプルです。同じくwithと、Enumeratorを使って、
with(new Enumerator("header,nav,article,section,aside,footer".split(',')))for(;!atEnd();moveNext())document.createElement(item());これは、ちょっと長いし、Enumerator Object はマイナーですかね。
短さ命で、グローバル変数の汚染なんて気にしないぜっ、という向きには以下のようなものもありかと思います。
s="header,nav,article,section,aside,footer".split(',');while(s[0])document.createElement(s.pop());
for文関連では、
for(i in s="header,nav,article,section,aside,footer".split(','))document.createElement(s[i]);とか
for(i=0;n="header,nav,article,section,aside,footer".split(',')[i++];document.createElement(n));とかですかねぇ。
ちなみに、配列を作るのに、文字列にsplit()をかませるというのは、よく見かける手法です。ここでの、6個ぐらいの要素数ではあまり差は出ませんが、要素数が増えてくると、逐一ダブルクォート(or シングルクォート)で括っていくやり方と大きく差が付いてきます。
var html5_elements = ["header", "nav", "article", "section", "aside", "footer"]; // これより var html5_elements = "header,nav,article,section,aside,footer".split(','); // こっちが記述が短い
正規表現から配列も出来ますね。
var html5_elements = "header,nav,article,section,aside,footer".match(/¥w+/g);
以上、トリビアルなエントリーでした
— posted by martin at 12:18 pm Comment [0] TrackBack [1]
2010/7/27
カテゴリー » 開発日誌 » JavaScript
こんにちは、martinです。なかなかまとまった時間が取れないので、ppBlogの最新版をリリースできずにいます
最新版のバージョンとしては、v1.9.0を予定しています。新機能としては、コメント認証機能だとか、HTML5を意識したppBlogエンジンでしょうか(ちなみにテーマBasicのソースはHTML5仕様ですよ)。
で、このHTML5なんですが。過去のエントリーでいくつかあるように、最新版では、記事投稿の際に複数ファイルアップロードが可能になっています。HTML5のFileAPI を積極的に採り入れたものにしようか、それとも「レガシーな」もので実現させるか迷いましたが、とりあえず「レガシー」なバージョンで行こうと思います。理由はいくつかありますが、一番の理由は、どうもHTML5のFileAPIの使い勝手が悪い点です。
ブログでの写真投稿において、一度に複数枚の写真を選択してアップロードできる点は、HTML5を使う魅力のひとつですが、この「複数枚のファイルを選択」というのが、どうも洗練されていない印象です。例えば、アップする写真を複数枚決めてそれをアップロードする場合を考えてみます。頭の中では、大まかに写真をのせる順番が決まっていて、ファイル選択画面から、コントールキー(CTRL)を押しながら、順序良く写真をいくつか選んだとします。最新のブラウザなら以下のように、multipleを指定するだけで、この複数枚選択という動作が可能になります。
<input type="file" name="src[]" multiple />
でも、残念なことに、この選んだ順序というのは、FileList には反映されないのです。否応なしに、ファイル選択画面上で表示されている通りの順序になるようです。何か、選んだ順序を紐付けするような属性が欲しくなります。
もうひとつ。選んだ複数枚のファイルは、FileList配列に収められて、あたかも配列のようにDOM操作が可能ですが、この配列は、readonly、つまり読み取り専用 のようです。たとえば、ちょっと余分に画像を選んじゃったよ、という場合に、その余分なファイルだけをリストから除きたいというケースは、間違いなく出てくると思いますが、そういう操作は出来ないようです。再度、すべてのファイルを選び直す必要があります。これは、ユーザーには使い勝手が悪いですね。
というわけで、上記の理由により、ppBlogではW3C FileAPIの積極的な採用は見送りました。でも、HTML5に頼らずとも、一度に複数枚のファイルのアップロードは可能です。Stickmanさんが、2005年に、すでにそういうギミックを見付けていました 。最初見たときは、目から鱗でした。やってることはすごくシンプルなんですが、まさにコロンブスの卵ですね。で、彼のスクリプトは、ppBlogにはちょっと冗長でしたので、参考にしつつ、ppBlog仕様にしました。実際のデモを見てみましょう。尚、デモでは「アップロード」ボタンは、文字通りただのボタンなので、実際にはファイルはアップロードされませんが、雰囲気は十分に伝わると思います。
レガシーな複数ファイルアップロードのデモ →http://p2b.jp/demo/EasyFileUpload.html
また、Firefox最新版など、File APIに十分対応しているブラウザでは、選んだ画像をサムネイル表示するようにしています。Firefoxだと以下のようなスクリーンショットです。Firefox以外では、普通に選んだ画像のファイル名が選んだ順にリスト表示されます。
この部分のスクリプトは以下の感じ。
if(window.File && window.FileList && window.FileReader){ // FileAPIに対応しているなら var file = el.files[0]; if(file.type.match(/image.*/)){ var reader = new FileReader(); // FileReader オブジェクト! reader.onload = function(){ var span = d.createElement("span"); span.innerHTML = '<img class="thumb" src="' + this.result + '" alt="preview" /> (' + Math.round(file.size / 1000) + ' KB)'; li.insertBefore(span, li.lastChild); }; reader.readAsDataURL(file); // 画像データの読み込み } }
レガシーなインターフェイスですが、任意のリストを削除出来ますし、HTML5仕様より却って高機能(=使い勝手が良い)な気がします。
ちなみに、デモのソースを見ていただけると分かりますが、INPUT[type=file]要素に、レガシーにonchangeイベントハンドラを仕込んでいます。document.addEventListerで監視しても良いのですが、IEでは、onchangeイベントがバブルしないようで
余談ですが、「目から鱗」の語源は、新約聖書の「使徒行伝(しとぎょうでん)」中のエピソード、見えなくなっていたパウロ (サウロ)の目からうろこのようなもの(コンタクトレンズ?)が外れて再度見えるようになったという「パウロの回心」からですね。「豚に真珠」と同様、日本とか中国由来と思いきや、新約聖書からの諺です。
— posted by martin at 09:28 pm Comment [4] TrackBack [0]
2010/6/1
おはようございます、martinです。前々回ぐらいに、HTML5を用いたプログレスバー付きのファイルアップロードのデモを示しました。この手のスクリプトは、プログレスバーの表示にFlashやJavaを用いていることが多いのですが、ファイルサイズが大きくなる傾向になったり、設置がややこしかったりします。
何件かソース希望のリクエストがあったので、ppBlogからのスピンアウトとして配布しようと思います。配布するやつは、PHPとJavaScript(+CSS)だけでプログレスバーを実現していて、設置も比較的簡単ではないでしょうか。添付ファイルを展開すると以下のファイルが含まれています。
基本的には、展開したフォルダを然るべき場所にまるごとアップロードして、index.htmlにアクセスすればOKかなと思います。サーバーによっては、PIXディレクトリのパーミッションの指定が必要かもしれません(707とか)。
画像を保存するディレクトリは、PIXにしていますが、これは適当に名前を変えても良いでしょう。fileUpload.phpの最初の方で指定出来ます。
$pix_dir = 'PIX/'; // 画像を保存するディレクトリ。パーミッションは707とか。
うまく動けば、アップロード中は以下のような画面になっているかと思います。
*あくまでサンプルです。最低限の実装なので、セキュリティ関連は、各自でいじって下さい。JavaScriptをいじれば、プログレスバーに加えて、全体の何パーセントが完了みたいなことも出来るでしょう。
— posted by martin at 02:29 pm Comment [0] TrackBack [1]
2010/4/30
こんばんは、martinです。以前、Flex(Flash)を用いた複数ファイルのアップローダー を紹介しましたが、実はHTML5だけで出来るのになぁ、と思っていました。現時点で、IE8を除く主要なブラウザでは軒並み、HTML5のINPUT要素に対するmultiple属性に対応しているので、それによる実装をppBlogに施してみました。複数ファイルを選択可能にするには、input要素にmultipleを指定するだけです。
<input type="file" name="src[]" id="src" multiple />
とりあえず実装してみただけですが、きちんと動作しました(ここのエントリー は画像を複数枚一度にアップロードした)。UIをどうするかで試行錯誤しましたが、プロトタイプにしてはまぁまぁかなと思っています。
さて、複数の(画像)ファイルがアップロード出来るようになると、アップロードする枚数に応じて、サーバーにデータを渡す間、じっと待たされるようになります。現状、HTML5のみではぼーっと待つしかありません なので、アップロードの進捗状況を示すプログレスバーが欲しくなります。この手のスクリプトはウェブ上にいろいろありますが、どれもFlashを用いたり、Perl(+JavaScript)を用いたりしたものです。出来ればPHP(+JavaScript)のみで完結させたい。
いろいろ調べてみると、PHPとJavaScriptのみでは、ファイルアップロードに伴なうプログレスバーのギミックを提供するのは無理という記述ばかりです。というのもPHPには、ファイルアップロードの途中経過を知らせる仕組みが備わっていないからです。実は、PHP5.2以上であれば、PECL APC拡張機能を組み込んで可能 なのですが、サーバー側で PECL APCエクステンションをインストールする必要があり、これはレンタルザーバー等では敷居が高いでしょう。
なので(Perlはあまり好きになれないという理由もあり)PHPとJavaScriptのみによる実装を考えてみました。まずは、PHPにおける、POST メソッドによるファイルアップロード時の挙動を知る必要があります。マニュアルによれば、基本的に以下の手順を踏みます。PHPでのネックは、この1番目の進捗状況を知るメソッドが備わっていないことです(なのでこの部分だけはPerlで処理するスクリプトがある)。サーバーサイドで提供しないのであれば、こちらからゲットしに行きましょう。アップロード中のデータは、テンポラリディレクトリに溜まっていくので、そのディレクトリのサイズは徐々に大きくなるはずです。なので、そのディレクトリのサイズを定期的に監視すればOKということになります。この「定期的に監視」という部分にJavaScriptのAjaxを使えば良いわけです。
ディレクトリのサイズは、以下の記述で取得可能です。$tmp_dir = '/tmp'; // 取得したいテンポラリディレクトリ $size = 0; // ディレクトリのサイズ $d = opendir($tmp_dir); while($file = readdir ($d)){ if(is_file($tmp_dir.'/'.$file)){ $size += filesize($tmp_dir.'/'.$file); } } closedir($d); echo($size); // ディレクトリの合計サイズを得る
なお、上の例では、テンポラリディレクトリは/tmpですが、これを取得したい場合は、ファイルアップロード時に現れる変数の$_FILES['src']['tmp_name']を利用して、
dirname($_FILES['src']['tmp_name']);
で取得可能です。
あとは、AjaxとPHPで、このディレクトリサイズを返すような記述をして、それをJavaScript側に渡し、プログレスバーっぽく見せればOKとなります。具体的なデモ を見てみましょう。うまく行けば、転送中のブラウザ画面は下のようなスクリーンショットになります。Firefox3.6.3やSafari, Google Chromeの最新版で動くと思います。
— posted by martin at 01:14 am Comment [6] TrackBack [0]
Comments