dojo toolkit

うろ覚えでプログラミング

この記事はEmber.js Advent Calendar 2013の参加作品です。では改めてこれの説明文を確認しましょう。

Ember.js だったり Ember.js じゃなかったり、なんかそんな感じで。

なるほど(強調は引用者)。はい、では本題です。


やること

先日Ember.jsのハンズオンに参加させていただき、今はその知見をはよ社内に広めんかいという苛烈なプレッシャーと戦っているわけですが、あまり興味のない人に「おっ」と言わせるには実際に動きを見せないとと思うのです。

それもできればシンプルなコードでー、と考えるとEmberホームページにある「名前を入力するとモデルが変わって画面の表示も変わる」AUTO-UPDATINGのサンプルがちょうどいい感じですかね。


13

あのコードは何度か写経してるので、今回は何も見ずにあれをかけるのかチャレンジしてみたいと思います。


準備書き書き

まずはライブラリとスタイルを取り込むところです。この辺はgoogleさんでホスティングしてくれてるから楽ちんですよね。CSSは本当はいろいろやってるんだろうけど、最低限。text-transform:uppercase;ってので大文字になるんですね。ほほう。


JS書き書き

次はJSでモデルの定義をしてやります。なんとなく、ドキュメントには「JavaScript書かなくてもいけるぜ!」って書いてあったような気もするのですが。。気のせいかな。


HTML書き書き

inputとoutputを先ほどモデルで定義した「model」でつないでやるイメージでしょうかね。ドキュメントをみるとrefパラメータはDeprecatedなんですかね。。まあ社内勉強会でイメージを伝える分には問題ないでしょう。



できた!

これが
00

こうなる!

18

うん、動いてますね。とはいえ、名前の所に入力したHTMLがエスケープされなかったり、モデル変更のタイミングがinputからフォーカスが外れたときとか、ちょっと動きが違う部分があるようです。うーん、ちゃんと書けるようになってたつもりでいたから残念。もう一度答え合わせがてら公式のホームページを見直してみたいと思います!

dojoするなら!:ちょっとアプリ作ってみますか

今回のテーマ

さてさて。だいぶdojoにも慣れてきましたし、ちょっとしたアプリを作ってみましょうか。 hello, world だけじゃつまんないですもんね。

手頃ないいネタないかなー、って面白そうなAPIありましたよ。

github Markdown Rendering API

みんな大好きgithub、のAPIですね。マークダウンで書いたテキストを渡すと、それをHTMLに変換したものを返してくれます。便利便利♪これを使って、簡易マークダウンエディタ作りましょう。手順はこんな感じ。

  • 画面にはテキストエリアがあって
  • そこにmarkdownで入力したテキストをajaxってサーバにpost
  • レスポンスのHTMLを描画

dojoで部品を探す

上記手順で、ajaxでサーバとやり取りする部分は前々回あたりでやりましたね。となると、今回やるべきは

  • テキストを(markdownで)入力するところ
  • サーバ通信するきっかけ
  • テキストを(HTMLで)出力するところ
のあたりで、dojoでうまいことできる部品があればいいなーってとこですね。 それでは、今回の目的にはどんなUIが考えられますかね?

UI案

案1:入力するところと、出力するところを横に並べて、間のボタンクリックのタイミングでサーバ通信する、とか?

案2:入力するところタブと、出力するところタブを作って、タブ切り替えのタイミングでサーバ通信する、とか?

イメージ図。
イメージ図

どちらでもできそうですね。でもせっかくdojo使うので面白いやつでいきましょう。

InlineEditBox

dijitの部品であるInlineEditBoxは、その名の通りインラインのeditboxです。…つ、つまり一見普通のHTML要素をクリックするとその部分がテキストエディタになって、編集することができます。編集後はもともと普通のHTML要素がアップデートされます。

言葉で説明するより、testを見ると一目瞭然ですね。

これって、先ほど述べた今回欲しいUIの3つの条件にばっちり満たしますよね。

こいつは使えそうってのは分かったけど、具体的にどう書けば良いのか?最近のバージョンに対応した素敵な解説本でも出ていれば、それを読みたいところですがそうもいかないので、公式のドキュメントに頼ります。まあdojoに限らないですけど

この2つ(とソース)があればなんとかなるもんです。dojoはこの2つとも充実してます。今回もそれをもとに、プロパティはこんな感じで設定しますよ。

  • 表示はHTMLで行いたいので、renderAsHtmlをtrueに。
  • 登録するボタンを表示したいので、autoSaveをfalseに。
  • 登録するボタンのラベル表示が「保存」だとなんなんで、buttonSaveを "preview"に。
  • 登録するボタンを押した時にxhr通信をしたいので、onChangeにその旨を記述。

コードで書くとこんな感じになります。

mdEditor = new InlineEditBox({
    editor: Textarea,
    renderAsHtml: true,
    buttonSave: "preview",
    buttonCancel: "cancel",
    autoSave: false,
    onClick: function(){
        // クリックされたときには、markdown形式の方のテキストをセット
        this.set("value", inputString);
    },
    onChange: function(){
        var mdEditorVal = this.get("value");
        if (string.trim(mdEditorVal) != string.trim(previewString)){
            // ajaxするところ
            request.post(
                "./md",
                {
                    data:{
                        text: mdEditorVal
                    }
                }).then(
                    function(text){
                        // うまく結果を受け取ったらHTMLになったテキストをセット
                        inputString = mdEditorVal;
                        previewString = text;
                        mdEditor.set("value", text);
                    },
                    function(error){
                        console.log("An error occurred: " + error);
                    }
                );
        }
    }
}, "markdown_editor"); // ターゲットdomのid

サーバー側を駆け足で

サーバー側はメインとなるmarkdownエンジンは前述のとおりgithubなんで、特になんもないです。ただ、JSONPのAPIがないんで、プロキシってあげます。個人的に今年はpython勉強年なんで、pythonのbottle.pyを使ってみました。

@post('/md')
def md():
    requestedParam = request.POST
    params = dict(text=requestedParam.text, mode="gfm")
    res = urlopen('https://api.github.com/markdown', json.dumps(params))
    return res.read()

簡単便利♪

こんな感じになりました

初期表示

15

クリックすると…

47

マークダウンで書いてプレビューを押すと…

37

HTMLになりました!

11

全体をgithubにおいておきます。

https://github.com/haseg/dojo-md-editor

dojoするなら!:グリッド(dgrid)を使ってみよう(2)

はじめに

前回の続きです。 dojo界の次世代gridでありながら、標準ではまだ使えないdgridの設定方法についてです。

dgridはこちらで開発が進められています。

READMEを読むと、インストール方法については、CPMというパッケージマネージャを使う方法と手動で設定する方法が書かれています。

CPMを使うのが簡単なのでしょうが(自分は試してないですが)、今回は手動で設定してみましょう。 というのは、次のように設定したいからです。

こう設定したい

dojoの設定はCDNを使うと楽ちんですよね。

本当はdgridも同じようにホスティングしてもらえればいいのですが、 まてどくらせどそんな気配はないので、

  • dojoはCDNを使う
  • dgridと仲間たちは自分で設定したのを使う

という方針ですすみます。

もったいつけましたが

手順は簡単です。

  1. ”仲間たち”というのは、put-selectorとxstyleのことで、これらとdgridの3つのモジュールを適当な場所に配置します。
  2.  dojoを読み込むときに、モジュールとしてdgridと仲間たちの事を教えてあげます。

やってみましょう

ダウンロード:

以下のURLからダウンロードします。

配置:

上の3つを解凍し、適当なディレクトリに同列に配置します。例えば、mydgridというディレクトリを作ったら次のようになります。

├── mydgrid
│   ├── dgrid
│   ├── xstyle
│   └── put-selector

dojo本体はCDNからなので、ここには入れません。

パスの設定:

もしもdgird等と同じディレクトリにdojoを配置すれば(上の例だとmygrid配下にdojoがあれば)パスの設定は必要なく、dojoを読みこめば、dgirdもそのまま使うことができます。dgridの下にある、

dgrid / test / index.html
では、
<script src="../../dojo/dojo.js" data-dojo-config="async: true">

とやってやるだけですが、これでOKなのです。

今回は、dojo読み込み時に、dgirdと仲間たちがどこに配置されているかを教えてやらなければなりません。これは、dojoConfig に設定します。index.htmlを例にすると、そこからはdgridのパッケージがある位置は

../../dgrid

になります。パッケージ名とその場所を

{
  name: 'dgrid',
  location: location.pathname.replace(/\/[^/]+$/, '') + '/../../dgrid'
}

といった感じで指定してやります。

その指定が3つと、dojoの読み込みはCDNから。これらをまとめると、先ほどのindex.htmlのdojo読み込みの書き方は

となります。これで動かせます。

どうでしょう

意外と簡単ですよね! でもやっぱりCDNでdgridもあればいいと思うし、さっさとdojo本体に取り込まれればいいなと思うのでした。

参考:http://dojotoolkit.org/documentation/tutorials/1.8/cdn/

dojoするなら!:グリッド(dgrid)を使ってみよう(1)

はじめに

例えばちょっとしたwebサービスを作るときに、まず欲しくなる(必要とされる)データの表現方法といったらあれですよね!今回はdojoを使い、データをグリッドで表示してみましょう。

※今回のテーマはtwitter-bootstrap等で実現できるレイアウトのグリッドではなく、データ表示の為のグリッド(エクセルチックなやつ)についてです。

背景

なぜライブラリ?

なんらかのデータをグリッドで表示しようとするとき、まず思いつくのはtableタグを駆使して表示させる方法です。

単純に表示させるだけであれば、それでも良いでしょう。ですが例えば「列名をクリックしたら並び順を逆順にする」とか「セルを直接編集する」といった事をしたくなると(きっとしたくなります)実装は手間ですよね。

「グリッド表示をやりたいけど、実装は手間」となるとライブラリの出番です。dojoでももちろんあります。

グリッド表示のライブラリ

dojoでグリッドを扱うモジュールはグリッドでできること(行をネストできるかとか、フィルタリングができるかどうかとか)によっていくつかあります。

それらのモジュールはdojox/gridにあります。こちらのリファレンスガイドで確認してみましょう。dojox/gridありますよね。

dojoxgrid

。。。あれ?ステータスがDeprecated(推奨しない/廃止)??

モダンdojoではdojox/gridの彼らは使われなくなっていくんですね。知らなかった。。でもって、モダンdojoではどうなるかというと、新しいdgridというのが使われるみたいです。

dojox/gridを廃止にして、dgridを使いますと言っておきながら標準では使えない(別途ダウンロード・設定が必要)のでちょっと面倒ですが、それをするメリットはあるのか否か。次回、実際に使うところをやってみますね。

dojoするなら!:ajaxって表示してみよう(2)

今回のテーマ

他のライブラリと同様、dojoにも生のjavascriptでは実装が面倒な部分を 簡単にしてくれる便利な関数がそろっています。これを利用することで、ブラウザ互換の問題を意識することなくプログラミングしていくことができます。ありがたや。

今回はそれら関数の使い方、プラス、dojoが誇る美麗なUIで表示する方法についてです。

やってみましょう

作るプログラムは前回の続きですよ。ajaxで持ってきた選手のjsonデータを良い感じに処理して、 ダイアログにその内容を単純に表示するまで、です。 次のステップの説明をします。

  1. 便利関数たち
  2. ダイアログの表示

便利関数たち

この表を みてもらうと、どんな関数があるかわかります。ajaxやDOM/HTML関連のもの(前回やりましたね)、cookieやdrag&drop関連のものなどいろいろあります。あるといいなは、だいたいあるかと思います。

使い方は前回ajaxの関数を使いましたが、流れはそれと同じです。使いたい関数を含むモジュールをまずrequireして、それからその関数を呼び出します。

今回は、選手情報の入った連想配列をイテレータで値を順に処理しつつ、HTMLのテンプレートにそれらの値をはめ込んで返す処理をしてみます。

require([
    "dojo/_base/array",
    "dojo/string",
    "dojox/html/entities"
], function(arrayUtil, string, htmlent){
    // テストデータ
    var _data = [
        { num: 23, name: "山田 栄治"},
        { num: 16, name: "ポール・<b>サンダー</b>・ワット"},
        { num: 33, name: "飯田 宏"}
    ], _content = "";

    // イテレータはarrayのforEach関数
    arrayUtil.forEach(_data, function(item) {
        // テンプレート的にデータをはめ込む
        _content += string.substitute(
            "<div>背番号:${num},氏名:${name}</div>", item,
            function(arg) {
                // substituteの第三引数は、テンプレートに
                // はめ込む前に実行する関数
                // ここでは、htmlのタグをエスケープする処理
                // (dojox/html/entities/encode)を行う
                return htmlent.encode(""+arg);
            });
    });
    
    // 結果
    console.log(_content);
});

どうですか!生のjavascriptでやろうと思ったらうんざりしますよね。ちなみに実行結果はこうなります。
12
 

これまでのレガシーなdojoでは、便利関数たちは「dojo.xxx」で使うことができました。例えばforEachを使いたければ、特に何かをrequireすることなく、dojo.forEachと書くだけでした。

モダンなdojoでは、

forEach使いたいけど、これは何のモジュールだっけ?
あぁ、dojo/_base/arrayね。じゃー、これをrequireしてっと。

という流れになります。面倒ですが、できるだけ標準でロードするモジュールを少なくしたい=速くしたいという気持がびんびんに伝わってきます。使いたい関数とモジュールの対応を覚えるまでは、慣れが必要ですね。

余談ですが、forEachについて。javascriptにもforEachがありますけど、dojoのforEachとは 配列に値がない場合の動きがちょっと違うんですよ。

require(
  ["dojo/_base/array"],
  function(arrayFunc){
    var test = [0, 1];
    test[3] = 3;

    console.log("配列");
    console.log(test);

    console.log("-------");
    console.log("javascriptのforEach");
    test.forEach(function(item){
      console.log(item);
    });

    console.log("-------");
    console.log("dojoのforEach");

    arrayFunc.forEach(
      test,
      function(item){
        console.log(item);
      }
    );
  }
);
実行結果
配列
[0, 1, undefined × 1, 3]
-------
javascriptのforEach
0
1
3
-------
dojoのforEach
0
1
undefined
3

ダイアログの表示

次はダイアログを表示してみます。コーディングの前に、美麗なUIを実現するスタイルの設定をしましょう。

まずは、stylesheetの読み込みです。これもgoogleさんのCDNにホスティングされてますね。

<link href="//ajax.googleapis.com/ajax/libs/
dojo/1.8/dijit/themes/claro/claro.css" rel="stylesheet">

URLにある"claro"ってなにかというと、dojoが用意しているスタイルのテーマになります。claroの他にtundra, nihilo, soriaの3種類用意されていて、それぞれフォント、色合いや文字サイズなどが違ってきます。

それぞれの違いはここで。 読み込んだテーマをbodyタグのclassに設定することで、ページ全体に適用します

<body class="claro">

この準備さえできれば、後はこれまでと同じです。ダイアログのモジュールをrequireして、その関数を呼び出すだけです。

require(["dijit/Dialog"],  //ダイアログのモジュールはdijit/Dialogにあります。
  function(Dialog){
    // タイトル・スタイル・中身を設定して・・・
    var _dialog = new Dialog({
                    title:"選手一覧",          
                    style:"width:300px",       
                    content:"選手の情報を一覧にしました。" 
                  });
    // show()を呼ぶとダイアログが表示されます。
    _dialog.show()
  }
);
実行結果

32

ダイアログのパラメータについては、初期化するときだけではなく後から設定/変更することが可能です。

require(["dijit/Dialog"],  //ダイアログのモジュールはdijit/Dialogにあります。
  function(Dialog){
    // タイトル・スタイル・中身を設定して・・・
    var _dialog = new Dialog({
                    title:"選手一覧",          
                    style:"width:300px"
                  });

    // contentは後から設定
    _dialog.set("content", "選手の情報を一覧にしました。" );

    // show()を呼ぶとダイアログが表示されます。
    _dialog.show()
  }
);

まとめ

今回の一覧の流れを一つにするとつぎのようになりました。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ajax sample</title>
    <link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/dojo/1.8/dijit/themes/claro/claro.css"></link>
    <script src="//ajax.googleapis.com/ajax/libs/dojo/1.8.0/dojo/dojo.js"
            data-dojo-config="async: true"></script>
    <script>
      
        require(
            [
                "dijit/Dialog",
                "dojo/on",
                "dojo/dom",
                "dojo/request",
                "dojo/_base/array",
                "dojo/string",
                "dojox/html/entities",
                "dojo/domReady!"
            ],
            function(Dialog, on, dom, request, arrayUtil, string, htmlent) {
        
                var _dialog = new Dialog({title:"プレーヤー一覧", style:"width:300px;"}),
                showDialog = function(dlg, data){
                        var _content = "";

                        arrayUtil.forEach(data, function(item){
                            _content += string.substitute("<div>背番号:${num},氏名:${name}</div>", item,
                                        function(d){return htmlent.encode(""+d);});
                        });

                        dlg.set("content", _content);
                        dlg.show();
                }

                on(dom.byId("show_dialog_button"), "click", function(evt){
                    request.get("./fighters.json", {handleAs:"json"})
                           .then(
                               function(data){
                                   showDialog(_dialog, data);
                               }, function(err){
                                   console.log(err);
                               });
                })
                
            });
    </script>
</head>
<body class="claro">
  <button type="button" id="show_dialog_button">show dialog</button>
</body>
</html>

実行結果
22

さり気なくクリックイベントの処理が入っていますが、まあ見ての通りですね(^^)

Twitter プロフィール
コメントなどあったら、お気軽に♪
カテゴリ別アーカイブ
タグクラウド
QRコード
QRコード