「GitHub」と一致するもの

AngularUIのui-calendarを使ってみた

  • 投稿日:
  • by

AngularUIにCalendarというサブプロジェクトがあるので、使ってみました。

https://github.com/angular-ui/ui-calendar

これは、FullCalendarというjQueryプラグインをAngularのディレクティブ化するもののようです。 ちょっと依存ライブラリが多くて使うのをためらったのですが、他に良い候補も見つからず、AngularUIに入っているのだからうまくラップされているのだろうということで。

READMEを読むと、bowerを使って依存関係を管理せよと書いてあるのですが、まだ理解していないものを使いたくなかったので、手動で設定しました。

分かってしまえばそれほど難しいものではありません。次のものを読み込めばいいだけです。

  • fullcalendar.css
  • jquery.min.js
  • jquery-ui.min.js
  • jquery-ui-i18n.min.js
  • angular.min.js
  • angular-ui.min.js
  • fullcalendar.js
  • calendar.js

必要であればjQueryUIのテーマのcssも読み込みましょう。

さて、ui-calendarを使うとng-modelが使えるようです。

<div ui-calendar="calendarOptions" ng-model="eventSources">

READMEにはこのように書いてありましたが、ここで、はまりました。ng-modelはeventSourceオブジェクトを指定するのではなく、events配列を指定するようです。READMEがソースの改変に追いついていないようです。もっと言うと、READMEではng-modelはオプション扱いですが、書かないとエラーになりました。

実際にevents配列を使ってみるのはこれからです。


追記。

ng-modelに指定するのは、events配列ではなく、eventSources配列であってました。でも、eventSourceオブジェクトの配列ではありません。READMEはeventSourceオブジェクトのリンクを指しているので分かりにくいです。

Node.jsで困るのはある機能を満たすためにどのパッケージを使っていいか分からないことです。発展途上ということで納得しましょう。発展途上というか生態系。

今回、Facebook認証をするためのモジュールを探しました。 stackoverflowで色々比較コメントがあり、それらやREADMEを参考にしました。

connect-authというのは名前もいいし、それなりのStar数もあります。シンプルでよさそうなのですが、よく使い方が分かりません。人気があるのは後発のeveryauthのようです。しかし、ドキュメントを読んでみてもどうもピンときません。なにか、感性が合わないような気がしました。

そこで、Passportを試すことにしました。 http://passportjs.org/guide/facebook/にドキュメントがあります。everyauthと比較するとコーディング量は多いかもしれませんが、なんとなくこちらの方が合う気がします。それでも、accessTokenが欲しいだけの場合は、userオブジェクトなんて作らなくてもいいのですけど。これはeveryauthも同じ(?)なので我慢するとします。

簡単に今使ってみた方法を紹介します。

まずは、ライブラリのロードです。サンプルをコピペしただけです。

var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;

続いて、FacebookStrategyの設定です。accessTokenだけ欲しかったので、それをuserオブジェクトにします。必要であれば、profileとかも入れればよいでしょう。userオブジェクトは、req.userで参照できるので、accessTokenはreq.user.accessTokenになります。

passport.use(new FacebookStrategy({
  clientID: process.env.FACEBOOK_APP_ID,
  clientSecret: process.env.FACEBOOK_SECRET,
  callbackURL: process.env.CALLBACK_URL
}, function(accessToken, refreshToken, profile, done) {
  done(null, {
    accessToken: accessToken
  });
}));

サンプルにあったシリアライザも入れておきます。これは書かなくてもよさそうと思ったのですが、ソースみてもデフォルトがあるように見えず、念のためいれておきます。

passport.serializeUser(function(user, done) {
  done(null, user);
});
passport.deserializeUser(function(obj, done) {
  done(null, obj);
});

強制的にログインさせるmiddlewareです。一度、ログインを促すページを表示するほうが親切かもしれません。

function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    next();
  } else if (req.url.lastIndexOf('/auth/', 0) >= 0) {
    next();
  } else {
    res.redirect('/auth/facebook');
  }
}

expressの設定です。セッションを使うのでその設定が必要です。

var app = express();
app.use(express.cookieParser());
app.use(express.session({ secret: 'foobar' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(ensureAuthenticated);

最後に、expressのルートの設定をします。failureRedirectは暫定です。

app.get('/auth/facebook', passport.authenticate('facebook'));
app.get('/auth/facebook/callback', passport.authenticate('facebook', {
  successRedirect: '/',
  failureRedirect: '/auth/loginfailed'
}));
app.get('/auth/loginfailed', function(req, res) {
  res.send('login failed');
});

以上、こんな感じで使うようです。/auth/facebookのようなルートを設定しなければならないのを面倒と考えるか、分かりやすいと考えるかが、Passportを受け入れられるかの境目かもしれません。

最近、connect-prerendererのIssueを報告してもらって、少しずつ不具合が見つかっては修正しています。

うまく解決したのは、

の二つ。前者は、

<div>
  count={{count}}
  <span>hoge</span>
</div>

のように、TextNodeとHTMLElementが並んでいるときに、 ng-bind-templateで上書きしてしまう問題でした。

<div>
  <span>count={{count}}</span>
  <span>hoge</span>
</div>

とコンパイル時になるように、Angular.jsをいじりました。 ただ、CSSがそれを想定しない書き方だと、表示に不具合がでるかもしれません。

後者は、doctypeがjsdomで消えている問題でした。こっちはすぐに直りました。

https://github.com/dai-shi/connect-prerenderer/issues/3 がなかなか手ごわく、まだ解決の糸口が見つかりません。 以前書いた、jsdomからAngularJSの不具合二つ目の問題です。

なんにしても、興味を持ってくれる人が増えるのはうれしいことです。 connect-prerendererはほとんど宣伝していないのに、Star数が増えてきました。それはそれで不思議。

facebook-node-sdkを使って、簡単なFacebook Graph APIの呼び出しをしていたのですが、不思議なエラーがでてました。

(#5) Unauthorized source IP address

というエラーです。

stackoverflowでも複数のスレッドで話題になっていました。IPが変わってしまっていて、エラーになっているということは分かりました。

herokuを使うと、デプロイしてから何時間か経つとIPアドレスが変わるようです。そこで、access tokenを同じものを使い続けると上記エラーがでるので、access tokenを取得し直す必要があります。

これは、OAuthExceptionのときに再取得するようにすればいいのですが、少しはまりました。access tokenを取得するAPIを呼ぶ時に事前にaccess tokenをクリアしておく必要がありました。そうしないと、access tokenを再取得しようとするときに上記のエラーが出ました。Facebook側の問題か、ライブラリ側の問題か難しいところですが、とりあえずは自分で回避するしかないです。

参考までにサンプルコードを載せておきます。

FB.api('hoge/feed', function(res) {
  if (res && res.error && res.error.type === 'OAuthException') {
    FB.setAccessToken(null);
    FB.api('oauth/access_token', {
      client_id: process.env.FACEBOOK_APP_ID,
      client_secret: process.env.FACEBOOK_SECRET,
      grant_type: 'client_credentials'
    }, function(res) {
      if (!res || res.error) {
        console.log('error occurred when getting access token:', res && res.error);
        cb(res);
        return;
      }
      FB.setAccessToken(res.access_token);
      FB.api('hoge/feed', cb);
    });
  } else {
    cb(res);
  }
});

今回はapplication access tokenを使う時に起こったエラーですが、普通のuser access tokenでも同じかもしれません(未確認)。


5/2追記。

上記のコードでも回避できずにエラーになったことが一度だけありました。再度調査中ですがその後再現しないので解決できないです。

5/6追記。

その後安定して動いています。前回の一度起こったエラーはたまたま別の要因があったと思っておきましょう。

突然ですが、Markdownでプレゼンスライドを作りたいと思いました。LibreOffice Impressを使うのは楽しくありません。最近使い慣れてきたMarkdownでさらっと作りたいです。そう、このブログもMarkdownで書いています。

Markdownで手軽に書く代わりに、見た目はそれなりに見えるものがいい、ということで、最近流行り(?)のHTML/CSSのプレゼンツールを調べてみました。

よさそうだなと思ったのは、

です。

プレゼンをmarkdownで書いたらええやん

にmarkdown2impress.plというのが紹介されています。Markdownを変換してHTMLにするようで、スライドの位置座標の指定にも対応しているようです。

さらに、

markdown2impress.plでついでにpdfも出したらええやん

という別のブログでPDFに出力する拡張が紹介されています。

これでやりたいことがすべてできると思って喜んでいたのですが、Reveal.jsを見たらもっとすごかった。

  • Markdownをそのまま読み込める
  • PDFの出力も標準サポート(Chrome only)

それだけでなく、Perl依存なしになるし、使ってみたところimpress.jsよりReveal.jsの方が動作が軽い気がしました。 impress.jsの方が表現力は豊かだと思いますが、もともとの発想がMarkdownで楽したいというものなのでReveal.jsを使うことにしました。

Reveal.jsを使う時はMarkdownを読み込むためのHTMLが必要です。READMEを読めば分かると思いますが、参考までにサンプルを書いておきます。

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>slides</title>
    <link rel="stylesheet" href="css/reveal.min.css">
    <link rel="stylesheet" href="css/theme/default.css" id="theme">
    <script>
        document.write( '<link rel="stylesheet" href="css/print/' + ( window.location.search.match( /print-pdf/gi ) ? 'pdf' : 'paper' ) + '.css" type="text/css" media="print">' );
      </script>
  </head>
  <body>
    <div class="reveal">
      <div class="slides">
        <section data-markdown="content.md" data-separator="^\n\n\n" data-vertical="^\n\n"></section>
      </div>
    </div>
    <script src="lib/js/head.min.js"></script>
    <script src="js/reveal.min.js"></script>
    <script>
      Reveal.initialize({
        dependencies: [
          { src: 'plugin/markdown/showdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
          { src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
        ]
      });
    </script>
  </body>
</html>

こんな感じでHTMLファイルを作っておいて、あとはcontent.mdを書けばそのままスライド表示されます。気をつけることは改行3つで区切ることくらいです。べんり~。

Bootstrapもいいのですが、ちょっと巨大すぎるので、代替品がないかなと思って探しました。

要件は、

  • スマホでも使えるようにレスポンシブ対応
  • あまりできることは多くなくてよい、ボタンとかフォームとかの見た目がきれいになればよい
  • できれば、CSSだけでJavaScript不要のフレームワークがよい

といったところです。

色々探しましたが、有名どころでJavaScript不要と言う要件を満たすものはあまりなく、結局見つけたのがこれです。

レスポンシブ対応のサイトをサクッと作れるフレームワーク『InK』

http://ink.sapo.pt/

この「InK」というネーミングですが、何が困るって、検索キーワードとして使えないことです。Google検索すると、"do you mean link?"とかなってしまう。そんなわけで、使用感などのレポートが見つからなかったです。どれだけ有名なのかもよく分かりません。

また、日本だと、

http://d.hatena.ne.jp/keyword/InK

と混同しそうです。

さて、話を戻すと、Inkは要件を満たしています。全体的な設計がシンプルで、CSSだけで構成されていていい感じです。早速ちょっと使ってみて感じたのは、レイアウトの指定が面白いということです。Bootstrapだと12 spanでfixedとfluidがありますが、Inkだとパーセント指定です。また、fixedはなくてfluidだけのようです(未確認)。fixedも使いたいケースがあるので、それは残念なところです。で、面白いのは、「Multiple Layouts」というレイアウトの指定方法です。これは、CSSのメディアクエリを3通り用意して、それぞれのレイアウトをCSSのクラス指定で定義するのです。

うまく説明できないので、サンプルを。

<div class="ink-l50 ink-m50 ink-s100">
  エリア1
</div>
<div class="ink-l50 ink-m50 ink-s100">
  エリア2
</div>

このようにすると、大画面と中画面では、エリア1とエリア2が横に並んで2カラムのレイアウトになり、スマホなどの小画面では、エリア1とエリア2が縦に並んで1カラムのレイアウトになります。ちなみに、大画面、中画面、小画面が、それぞれ、"l", "m", "s"に対応します。

あと、Bootstrapで困っていたレイアウト時のスペース追加も、Inkではink-vspaceとink-gutterで解決しそうです。もっとも、細かい制御をするときは結局CSSを書くことになりそうですが。

とりあえずは、レイアウトだけ試して満足しました。

久しぶりにFacebookアプリを作ることにしました。以前作った時から仕様がちょっと変わったので、勉強し直しです。

ちなみに、以前作ったアプリは修正していないので、動かなくなってしまっています。Java & JSPでGAE向けに作ったのであまりやる気が出なくなってしまいました。Node.jsで書き直そうかしらと思いつつも、作り直すならもうちょっと全体設計から見直したいと思って手がつけられていません。

話を戻すと、FacebookのGraph APIを使うためのライブラリを調べました。

http://developers.facebook.com/tools/third-party-sdks/#nodejs

にいくつかリストアップされています。

リポジトリの名前が同じものがあり少しややこしいです。NPMのパッケージ名は違います。Star数が同じなのはたまたまのようです。

さて、少しずつ特徴があります。amachang/facebook-node-sdkとnode-facebook-sdkはオリジナルのFacebook PHP SDKを再現したライブラリになっています。Thuzi/facebook-node-sdkはブラウザ向けのFacebook JavaScript SDKと同じAPIをサーバ側でも実現したものです。これはとてもnode.jsらしいと思いました。fbgraphは、また路線が違ってJavaScriptっぽくJSON APIに書き直したような感じです。

今回はFacebookアプリと言ってもあまり複雑なことをするつもりがなかったのと、以前PHP SDKを見たことがある(そして、わざわざJavaに移植した)ので、PHP SDK互換のものを使おうと思いました。二者択一ならとりあえずStar数を信じてみようということで、amachang/facebook-node-sdkを入れてみました。

ところが、初めに作ったサンプルでつまずきました。applicationのaccess tokenを使ってGraph APIを呼ぶのですが、エラーになるのです。うーん、なぜだ、と思ってソースを眺めると、あれ?application access tokenを取得するAPIが想像していたもの(以前、Rubyのライブラリを使ったことがあった)と違います。こりゃ、動かないわけです。もしかしたら、Facebookの仕様が変わったのかもしれません。深追いするのは止めました。たぶん、user access tokenを使っている範囲では正常なのでしょう。

やはり、Star数の多いものから使おうと、Thuzi/facebook-node-sdkとfbgraphを天秤にかけます。README.mdを読んで比較しました。結果、fbgraphにはapplication access tokenを取得する方法が書いてなく、できるとしてもすっきりしないと予想しました。一方、Thuzi/facebook-node-sdkにはapplication access tokenを取得する方法が書いてありました。application access tokenはサーバ側のコーディングのみで使用可能なため、Facebook JavaScript SDKには入っていないnon-standardな機能です。

作ったサンプルも動作し、満足です。application access tokenを使おうとしている人には参考になるかもしれません。ただし、現時点での話であることをお忘れなく。将来的には状況は変わるかもしれません。

参考までに、コードの抜粋はこちらに。

大変、失礼しました。

Gunosy RSSがGoogle Readerで更新されていないなぁ、と思ってはいたのですが、もしや!と思ったら、案の定エラーを吐いてました。

さかのぼること4/15からですね、エラーが出ていたのは。本家GunosyのUIデザインが変わっていたのですね。そういうことですか。

幸い、少ない修正で対応できました。(JSONPath)[https://github.com/s3u/JSONPath]というライブラリのおかげです。興味がある方はソースを見てみてください。

https://github.com/dai-shi/gunosy-rss

しかしながら、非公式サービスというのはこういうときに弱いですね。本家Gunosyが学習できるURLでRSS配信してくれればいいのですが、やはりRSSユーザはマイノリティですかね。

RSS Pipesの一機能として、スマホ向けのRSSリーダーみたいなものを作ってみようかと思います。

まずは、KineticJSの勉強をしているところです。 HTML5 Canvas KineticJS Tutorials を参考にしながら作っていきます。

HTMLのコードを説明します。

初めに、KineticJSの読み込みます。

<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.4.2.min.js"></script>

試しに使う場合はこのままでいいでしょう。デプロイするときはローカルに持ってこようと思います。

次に、自分のスクリプトを読み込みます。

<script src="test.js" defer="defer"></script>

deferを指定しておくことで、HTMLのロード後に読み込まれます。

空のbodyにIDを指定しておきます。

<body id="container"></body>

こうしておくことで、KineticJSのstageをbodyの直下に作ります。

さて、ちょっとだけCSSが必要です。

html, body {
  margin: 0;
  padding: 0;
  overflow: hidden;
}

これを指定しないと、Canvasの周りにマージンができてしまって、Full Canvasになりません。また、overflowを指定しないと、ChromeやFirefoxでスクロールバーが出てしまいました。

続いて、本題のJavaScriptのコードを説明します。

KineticJSのステージを作ります。

var stage = new Kinetic.Stage({
  container: 'container',
  width: window.innerWidth,
  height: window.innerHeight
});

widthとheightを表示領域一杯にすることで、Full Canvasとなります。

レイヤーを作ります。

var layer = new Kinetic.Layer();

表示領域一杯の四角形オブジェクトを作ります。

var rect = new Kinetic.Rect({
  x: 0,
  y: 0,
  width: stage.getWidth(),
  height: stage.getHeight(),
  fill: 'black'
});

黒にしてみました。

Hello Worldの文字オブジェクトを作ります。

var text = new Kinetic.Text({
  x: stage.getWidth() / 2,
  y: stage.getHeight() / 2,
  text: 'Hello World!',
  fontSize: 30,
  fontFamily: 'Arial',
  fill: 'lightgray'
});

ステージのサイズから計算して中央に配置しています。x,yは文字オブジェクトの左上の座標です。そこで、ちょっとずらして文字オブジェクトの中心に合わせます。

text.setOffset({
  x: text.getWidth() / 2,
  y: text.getHeight() / 2
});

最後に、四角形オブジェクトと文字オブジェクトをレイヤーに追加して、そのレイヤーをステージに追加して、終わりです。

layer.add(rect);
layer.add(text);
stage.add(layer);

これで、Canvasのみを使ってHello Worldを表示するページを作ることができました。アプリと呼べるようになるまでにはまだまだかかりそうですね。

実行結果はこんな感じです。

コードはGistにアップしておきました。 https://gist.github.com/dai-shi/5404537

RSS Pipesの一機能として、スマホ向けのRSSリーダーみたいなものを作ってみようかと思います。

RSSリーダーなんて世の中にたくさんあるので、普通のものを作っても面白くありません。そこで、勉強がてらHTML5でスマホアプリにしてみようと考えました。しかも、フルキャンバスで。canvasというのはグラフィック用の機能ですが文字も書けるわけで、それですべてを作ったら面白いのではないかと思いました。

さて、HTML5 Canvasは何年か前に少しだけ触りましたが、最近はライブラリも充実しているのではないでしょうか。検索してみると、

HTML5のcanvasを劇的に使いやすくするJavaScriptライブラリまとめ5つ

を見つけました。また、stackoverflowで、

Current State of Javascript Canvas Libraries(2012)?

を見つけました。使ってみないと分からないだろうと思いますが、これらの情報から、KineticJSを試してみることにしました。

今日のところはここまで。これから少しずつ進捗を書いていけたらいいなと思っています。