Pipesを使って、実用的なことをしよう、というお話です。Pipesで広告エントリの除去という記事を書いたのですが、あまり自分でも使っていませんでした。Pipesをいじりました。やりたいことというのは、RSSのURLの修正です。RSSのURLにリダイレクトURLが使われていることがあります。bit.lyなどの短縮URLが使われている場合です。通常は困らないのですが、そのRSSをプログラムで処理しようとする場合に、短縮URLではなく最終的なURLが欲しい場合があります。めずらしいケースだとは思います。Pipesの仕組みの上だけではできず、新たな関数を作り込む必要がありました。具体的には、getRedirectURL()という関数を作りました。ところが、このgetRedirectURL()は同期的には結果を返すことができません。Pipesのフィルターは同期的に書くように作られていたので困りました。仕方なく、promiseを使うことにしました。フィルターの方でもpromiseを扱えるようにする必要があるため、Qを使えるようにしました。これでブロックするようなコードも書けてしまうので、悪意コード対策がいずれ必要になりますね。promiseにタイムアウトの概念を持ち込めれば簡単にできるかしら。Pipesで書いたフィルターがこちらです。Q.all(promises);}https://gist.github.com/dai-shi/8934864にも同じものを同じものを置いてあります。リダイレクトが多重になっている場合を想定してループにしてみましたが、promiseをちゃんと理解していればもっとうまく書けるのかもしれません。どなたか改良してくれたら、うれしいです。これでサーバ側の処理がますます重くなるので、キャッシュ機構を入れる必要がでてきそうです。そのうち、気が向いたらやりますか。今のところ、それほどユーザがいないのでほっておいても大丈夫です。それはそれでさびしいものの。Canvasのみを使ってどこまでスマホアプリが作れるのか挑戦中です。Googleリーダがなくなるから、それの代替として作ろうと始めましたが、Googleリーダの期限までには完成しそうにありません。今日は、RSSの記事のリンクを開く機能を作りました。CanvasではHTMLは表示できません。iframeを使うことで表示しました。iframeの表示はjQueryを使いました。JavaScriptを使っていると、DOM操作はちょっと古びたものに感じます。RSSのリンクを開くためのボタンも作ってみました。右上の方に矢印のアイコンを置いて、それを押すとiframeが開きます。DataをKineticのpathで読み込みました。コードはこんな感じです。0.43});全コードはこちらです。https://github.com/dai-shi/canvas-rss-reader/実行サンプルはこちらです。http://canvas-rss-reader.herokuapp.com/未読既読の機能までできたら、とりあえずは使えるようになるかと思うのですが、どうでしょう。Canvasのみを使ってどこまでスマホアプリが作れるのか挑戦中です。今回は、フリックで横スライドに挑戦しました。時間が空いてしまったのは、どうやって実装するかイメージがわかなかったからです。試行錯誤した結果、比較的満足いくものになりました。普通のスマホアプリと同じくらいの操作性を目指しつつ、KineticJSの機能をフル活用して少ないコーディングで実現することです。横スライドも、縦スクロールと同様にドラッグ&ドロップの機能を活用しました。正確にはフリックを判定しているわけではなく、ドロップ後の位置でスライドするかどうか判定しています。使ってみると、直感と異なることもあるのですが、それは今後の課題ということで。今回、Canvasでアプリを作る時に意識をしているのは、軽快さです。普通に作ったアプリより軽く感じるWebアプリを作れるのかがポイントです。自分のスマホではかなり軽快にスライド動作ができるようになっています。他のスマホではどうなのか気になります。お持ちのスマホで試してみてください。下記の実行サンプルをスマホのブラウザで開くだけです。http://canvas-rss-reader.herokuapp.com/全コードはこちらです。https://github.com/dai-shi/canvas-rss-reader/この時点のコードを参照するには、本日のコミットを参照してください。上記実行サンプルは、今後最新版に変わっていってしまいますので、ご注意を。大切な発見を書くのを忘れていました。TweenのonFinishは呼ばれないことがあってはまりました。Tweenでノードを動かしている時に、ドラッグ&ドロップをすると、終了時にonFinishが呼ばれませんでした。setTimeoutを使うことで解決しました。KineticJSのバージョンは、4.5.2です。この仕様が将来のバージョンでどうなるかは不明です。Canvasのみを使ってどこまでスマホアプリが作れるのか挑戦中です。以前、RSS取得を実装したので、今回はそれっぽく表示してみることにしました。RSSのタイトルと概要をリスト表示するだけです。一つのアイテムあたりに80pxの高さを使いました。KineticJSなのかCanvasなのか分かりませんが、フォントサイズをpxで指定するため、手軽にレイアウトできました。スクロール処理もちゃんと動き、上々です。改行の処理が甘いですね。甘いというレベルではなくおかしいですね。このあたり、Canvasでアプリを作るときのつらさかもしれません。はまりそうなので、今回は手を出さないことにしました。今回は実行結果のスクリーンショットをとりました。全コードはこちらです。https://github.com/dai-shi/canvas-rss-reader/実行サンプルはこちらから。http://canvas-rss-reader.herokuapp.com/どのRSSフィードを表示するかもクエリパラメータでURL指定できるのですが、詳しい話はまた今度にします。Canvasのみを使ってどこまでスマホアプリが作れるのか挑戦中です。スクロールの処理を実装しています。KineticJSでできるだけ簡単にやろうと考えて、ドラッグ&ドロップのイベントをつかってやりました。スマホで使うには、やはり慣性スクロールが重要です。正しい呼び方は知りませんが、あの指を離してもしばらくスクロールしているあれです。まじめに物理シミュレーションをしようかとも思ったのですが、使いやすければいいだろうということで感覚的にパラメータ調整しました。KineticJSではここらあたりが限界でしょうか。ちなみに、iPhoneの複数のアプリでスクロール操作を試してみましたが、アプリによって挙動が違うことに気づきました。Safariではスクロールが止まるのが早いですが、Twitterではしばらくスクロールしています。今まであまり意識していなかったので気づかなかったです。あと、スクロール途中にタッチして止めることが相当重要だとうことを再認識しました。コードは少し長くなってしまったので載せません。特記するポイントはないです。バウンスするところと組み合わせるのがすこしやっかいでした。全コードはこちらです。https://github.com/dai-shi/canvas-rss-reader/実行サンプルはこちらから。http://canvas-rss-reader.herokuapp.com/うまくいったらライブラリ化したいと思いつつも、今は決めうちのコードになっています。Canvasのみを使ってどこまでスマホアプリが作れるのか挑戦中です。今回は、スクロール時のバウンスに挑戦です。スクロールの端で戻るやつです。米特許商標局、アップルのバウンススクロール特許は無効と予備的判断。対サムスンでも争点こんなニュースになっているやつです。KineticJSにはTweenという機能があって、スムーズな動きが簡単に表現できます。ちなみに、Tweenというのは、http://en.wikipedia.org/wiki/Inbetweeningのことのようですね。見ながらやったのですが、一つはまったことがあります。最初にどのドキュメントをみたのか定かではありませんが、今日までKineticJSのv4.4.2を使ってました。このバージョンではチュートリアル通りのコードを実行するとエラーになります。最新のv4.5.2を使ったら解決しました。コードはこんな簡単に書けてしまいました。tween.play();});今回も、実行結果はスクリーンショットでは見せられないので、下記からどうぞ。アニメーション系はスクリーンショットは使えませんね。動画にするのは手間がかかりすぎる気がします。http://canvas-rss-reader.herokuapp.com/全コードはこちらです。https://github.com/dai-shi/canvas-rss-reader/tree/adfe56808e98da9936c690b85bd169aabca4bb13コミットの日付を見れば分かるでしょうということで、次回からはコミット指定のURLの記載は省略します。Canvasのみを使ってどこまでスマホアプリが作れるのか挑戦中です。前回の結果、スクロール動作が遅いことが気になりました。KineticJSを使うとノードの操作やイベント処理などは格段に使いやすくなるものの、描画という点ではオーバーヘッドになっているようです。ノード数が増えれば増えるほど遅くなるのでしょう。http://www.html5canvastutorials.com/kineticjs/html5-canvas-shape-caching-with-kineticjs/に画像としてキャッシュすることで、高速化する方法が記述されていたので試してみました。その結果、だいぶ改善されました。これなら実用に耐えそうです。逆にノード毎のイベントハンドラーが使えないことになります。KineticJSですが、活用できていないことになってしまうのかもしれません。このあたりは引き続き考えてみましょう。コードはこんな感じになりました。数日間以内には新しいバージョンになってしまいます。昨日のバージョンはたった1日の公開でした。http://canvas-rss-reader.herokuapp.com/全コードはこちらです。https://github.com/dai-shi/canvas-rss-reader/tree/9061aeab3ab034beca7fdaa9a472d3f3225671d5必要であれば、このコミットをチェックアウトして自力で走らせることもできます。Canvasのみを使ってどこまでスマホアプリが作れるのか挑戦中です。題材はRSSリーダーです。Pipesの補完機能として考えています。前回に続き、スクロールを実装しました。その前に、テキストの配置について補足します。前回は、setOffsetを使いました。分かりにくかったので、ループの中でy座標をインクリメントするように変更し、背景の高さもあわせて大きくするようにしました。詳しくはコードを参照してください。本題のスクロール処理についてです。スマホを想定しているので、スクロールバーではなく、タッチ(ドラッグ)スクロールです。はじめは、touchstart/mousedownイベントを使って自力でスクロール処理を書いてみましたが、スクロールするたびにdraw()で再描画をしたところ、とても遅くなってしまいました。そこで、KineticJSが用意しているDrag&Dropの仕組みを使う方法に変更しました。この方がすっきり書けました。どこまで細かい制御ができるかはこれからのお楽しみです。コードはこんな感じです。}});想像していたより、スクロールがスムーズではありません。Canvasを直接操作した場合と比較していませんが、KineticJSのオーバーヘッドがそれなりにあるのでしょうか。数日間以内には新しいバージョンになってしまいます。http://canvas-rss-reader.herokuapp.com/全コードはこちらです。https://github.com/dai-shi/canvas-rss-reader/tree/3d370b3386b7f46116b892ac4cf37d5282d3910aところで、スマホで試したら、最後までスクロールできないみたいです。スクロールも遅いです。課題浮上かもしれません。dai-shiだいぶ間が空いてしまいましたが、HTML5を使ってどこまでスマホアプリが作れるのか、挑戦しようと進めています。題材はRSSリーダーです。Pipesの補完機能として考えています。Worldを表示するところまででした。今回は、RSSを取得してテキスト表示してみました。スクロールできません。クリックもできません。RSSはjQueryを使って読み込むことにしました。コードはこんな感じです。}});updateRssContent()でキャンバスにかきますが、座標も自分で計算しないといけません。layer.draw();}setOffsetを使うよりいい方法があるのではないかと想像しますが、まだ探していません。実行結果はこんな感じです。最新版はherokuでも実行可能です。http://canvas-rss-reader.herokuapp.com/今回は、GitHubにコードをアップしました。https://github.com/dai-shi/canvas-rss-reader/tree/42ddd815e88304c6217c8c5f9f978d97c39fc34aそう、プロジェクト名もcanvas-rss-readerにしました。キャンバスを使うとあたりまえですが文字列選択ができないですね。JavaScriptでクリップボードって制御できるのでしょうか。http://www.w3.org/TR/clipboard-apis/このあたりをウオッチすることになるのでしょうか。Pipesの一機能として、スマホ向けのRSSリーダーみたいなものを作ってみようかと思います。RSSリーダーなんて世の中にたくさんあるので、普通のものを作っても面白くありません。そこで、勉強がてらHTML5でスマホアプリにしてみようと考えました。canvasというのはグラフィック用の機能ですが文字も書けるわけで、それですべてを作ったら面白いのではないかと思いました。Canvasは何年か前に少しだけ触りましたが、最近はライブラリも充実しているのではないでしょうか。検索してみると、HTML5のcanvasを劇的に使いやすくするJavaScriptライブラリまとめ5つを見つけました。Libraries(2012)?を見つけました。使ってみないと分からないだろうと思いますが、これらの情報から、KineticJSを試してみることにしました。今日のところはここまで。これから少しずつ進捗を書いていけたらいいなと思っています。Pipesは、JavaScriptでフィルターを書く、RSSアグリゲーターです。先に作ってしまいました。検索と言っても、表示されているものを絞り込むだけです。AngularJSには標準でフィルターというものが組み込まれているので非常に簡単にできました。ソースコードに検索ボックス配置の1行と、フィルター追記の1行で済んでしまいました。Bootstrapのレイアウトでもう数行いじりましたが、トータルで5行の改変のみです。興味ある方は、diffを見てみてください。https://github.com/dai-shi/rss-pipes/commit/c250c8a7d9b03476503c78fda5a2f0ab5cef5894#views/partials/home.jadeお手軽です。詳しくは、AngularJSのチュートリアルを参照しましょう。Pipesは、JavaScriptでフィルターを書く、RSSアグリゲーターです。フィルターJavaScriptはブラウザ上で誰でも書くことができます。バグ入りのコードや、悪意のあるコードも書くことができます。そのような不正なコードにどう対処するかがポイントになります。PipesはNode.jsで動いています。Node.jsにはvmというモジュールがあって、サンドボックス環境を作ることができます。Node.jsを使ったことがある方は分かると思いますが、モジュールを書いてrequireするとexportsしたもの以外は名前が衝突しません。これはrequireでモジュールをロードする時にサンドボックス環境で評価しているからです。Pipesでもこの仕組みを使ってJavaScriptのコードを評価しています。よって、ブラウザ上から入力されたJavaScriptコードによって、サーバ側のNode.jsにアクセスされることはありません。ところが、vmモジュールのマニュアルをよく読むと書いてあるように、このモジュールを使うことで安全になるわけではありません。安全にコードを走らせるためにはサブプロセスを使うように、と書いてあります。いうことかと言うと、Node.jsはシングルスレッドで動作するため、vmでサンドボックス環境を作ったとしてもそこで使用されるリソース(CPUパワーやメモリ)を制限することはできず、リソースを不用意に使われてしまう可能性があります。{}というJavaScriptを走らせるとNode.js全体が固まってしまいます。Pipesでサブプロセスを使うわけにはいきません。(もしかして、使うこと自体はできるのかも?)そこで、無限ループを判定するような仕組みをいれています。counter++;}のようにして、counterが一定値を越えた場合に強制的に止めればよいのです。これで、どの程度の危険が回避できたかは定かではありません。正確にCPUの使用率を測っているわけでもありませんし、メモリについてはノータッチです。それでも、無限ループで固まることは回避できているので、少なくとも悪意のないコードでしたら、問題のない範囲と思っています。将来的に、vmモジュールのサンドボックス環境でリソース制限までしてくれるようにはならないでしょうかね。Pipesですが、機能を追加しました。PipesはRSSのアグリゲーターでフィルターをJavaScriptで編集します。編集はWebブラウザ上で行うので、いわゆるWikiのようなシステムです。誰でも編集できてしまうので、そのうちSPAM行為をする利用者もでてくるかもしれません。なるくらいになったらうれしいわけですが。SPAM行為をされてから対策すればよいと思っていたですが、SPAM対策がされていないことで、利用者が躊躇してしまうのは本望ではありません。そこで、簡単なロック機能を作りました。編集するときにロックコードを入力すると、以降そのロックコードを入力しないと更新できなくなります。ロックコードを忘れたら、本人でも更新できなくなります。いうときは、あきらめて新しいフィルターとして再登録しましょう。「複製」ボタンがあるので、簡単です。Pipesを使ってJavaScriptの勉強をしよう、の第三弾です。Pipesの例を紹介しましたが、はてなブックマークの場合ははてなが提供するRSSでキーワードフィルタリングできてしまいます。そこで今日は、キーワードが含まれていた場合タイトルを書き換える方法を例題にします。フィードを流し読みするときは、タイトルに気になるキーワードが入っていると目に留まりませんか。自然と目でキーワードフィルタリングしているのかもしれません。そこで、それを助けるためにタイトルを強調表示してみましょう。★マークをつけるのはどうでしょうか。次のようなJavaScriptコードになります。articles;}前回と同じように、indexOfでキーワードを探して、見つかった場合はarticle.titleに文字列を追加しています。Pipesで動くサンプルはこちらです。hatena/JavaScript関連のブックマーク/タイトル強調表示もう、ネタがなくなってきたかも。PipesはJavaScriptでフィルターを書くRSSアグリゲーターです。存在するアイテムをコピーして新しく登録する「複製」機能が欲しいと思って実装方法を考えていたのですが、思いのほか簡単にできました。備忘メモしておきます。{...});のようになっています。/homeに複製ボタンがあり、それを押すと/editに遷移します。/homeから/editに複製元のデータを渡したいということです。$rootScopeを使いました。$scope.saved.data;として復元します。$scope.saved.data;としました。スマートな方法があるのかもしれませんが、今回はこれでよしとします。Pipesを使ってJavaScriptの勉強をしよう、の第二弾です。これ、連載にできるかしら。フィードを流し読みするときは、タイトルに気になるキーワードが入っているかが重要だと思います。キーワードでフィルタリングするというのはありがちですね。次のようなJavaScriptコードになります。newArticles;}キーワードが一つでも見つかったら、breakでforループを抜けて次に進むところがポイントです。Array.forEachを使うと、iとlenの変数が不要になるのですが、その場合JavaScriptだとループを抜け出せないのです。今回はindexOfで書いてみましたが、ここを正規表現でマッチさせる方法もあります。今回の例だと、/javascript/iという簡単な正規表現で書けるので、そのほうが一般的かもしれません。正規表現を使う時はループの外側で事前に定義してprecompileするようにしましょう。article.titleだけではなく、article.descriptionもチェックするとタイトルではなくdescriptionにキーワードが含まれているかもチェックできます。今回は、タイトルだけにとどめました。Pipesで適用した例が、下記にあります。hatena/JavaScript関連のブックマークこの例ははてなブックマークの新着エントリーを使いましたが、はてなブックマークを使うだけならはてなが提供するRSSで対応できましたね。http://b.hatena.ne.jp/keyword/JavaScript?mode=rssつづく。dai-shiRSSを処理すると言えば、まずは広告エントリの除去でしょうか。Pipesの利用例でもよくありそうです。Pipesの場合はJavaScriptでフィルターを書きます。newArticles;}このような感じになります。同じものを置いています。今、思ったのですが、これってJavaScriptの勉強に結構使えるのではないでしょうか。比較的短いコードで実用的な機能が作れるので。Pipesで適用した例が、下記にあります。news/itmedia&cnetjapanこのコードをコピペするだけで、他のRSSの処理もできるようになります。PipesというWebサービスを作りました。Pipesから連想されるとちょっと困るような、困らないような感じですが、いわゆるRSSアグリゲーターです。フィードを表示するUIはなくて、RSSを出力します。汎用性がないといったところです。比較することには意味がないですね。Pipesを作った理由は、ログインせずにRSSを作れるアグリゲーターが欲しかったJavaScriptでフィルターを書きたかったみんなでRSSを作れるようにしたかった単に作りたかったからです。できたてほやほやで、この段階でどれだけの人にアピールできるか分かりません。要望があればお知らせください。Pipes上記リンクからどうぞ。オープンソースで提供されています。ライセンスの範囲内で自由に使うことができます。慣れている人は説明なしですぐにできると思いますが、どれだけ簡単にできるかを示すため手順を書いておきます。toolbeltがインストールされ、SSH鍵が登録済であることGitHubのアカウントがあること(なければ作る)gitがインストールされていることまず、GitHubからソースコードを取得します。https://github.com/dai-shi/gunosy-rssにアクセスして、右上のForkボタンを押して、自分のリポジトリにします。自分のリポジトリのページに行ってリポジトリのURLを確認します。仮に、git@github.com:<username>/gunosy-rss.gitだったとします。git@github.com:<username>/gunosy-rss.gitをコマンドラインで実行するとダウンロードされます。gunosy-rssでディレクトリを移動します。次に、herokuにアプリケーションを作ります。<appname>を実行するだけです。<appname>は省略も可能です。apps:infoとします。それぞれ、git@heroku.com:<appname>.gitとhttp://<appname>.herokuapp.com/だったとします。SITE_PREFIX=http://<appname>.herokuapp.com/として、環境変数を登録します。git@heroku.com:<appname>.gitとして、リモートリポジトリを登録します。herokuとして、herokuにアップロードして、完了です。http://<appname>.herokuapp.com/<gunosyid>.rssでRSSフィードが生成されます。実は、GitHubのアカウント作らずForkもしなくても、上記のことはできます。requestが送れるようにForkするのが、GitHubらしいのではないでしょうか。<appname>とする必要があるかもしれません。RSSを使うと、クリック情報が反映されないためつまらなくなる可能性があるということでした。これは設定に相当の知識を必要としたため、「上級者向け」としました。RSS設定ページを作りました。してクッキーの知識など必要ですが、多少分かりやすくなったのではないか、と期待します。RSSフィード生成Webサービスから、「設定ページ」を開いてください。記事のURLを開いて404エラーにならなければ、ユーザIDの設定は正常です。このあたりも自動化できたらよさそうとは思っています。