javascript

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

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

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

1:はじめに

最近のリリースで"モダン"な書き方になったdojoですが、日本語のドキュメントがまだまだ多くはありません。 はじめての方も、"レガシー"な頃しか知らない方も、dojoでのプログラミングの雰囲気を味わってもらえればと思います。

2:今回のテーマ

今回は、dojoを使ってサーバのデータをajaxってデータを表示するまでを二回に分けて取り組みます。 題材として、次の機能を実装してみます。

リンクをクリックすると、サーバーから「ファイターズ外野手」のjsonデータを取得し、結果を成形してダイアログで表示

面白くはないですが...まぁ、まずは基本ってことで!

サーバーサイドは今回は範囲外なので、jsonファイルを同じディレクトリに配置するだけにします。 jsonファイルの中身はこんな感じ(ファイターズ公式サイトから作りました)

[{'num':'7','name':'糸井 嘉男','kana':'イトイ ヨシオ','pos':'外野手'},
{'num':'10','name':'ターメル・スレッジ','kana':'ターメル・スレッジ','pos':'外野手'}/*続く*/]

3:やってみましょう

次のステップの説明をします。

  1. dojoを使う準備:スクリプトの読み込みと書き方
  2. dojoを使う:お作法
  3. ajaxでのアクセス:request.getの使用
  4. 表示にdijitを使ってみる:ダイアログの表示,イベント処理(→次回)

3-1:dojoを使う準備

なにはなくても、dojoを使えるようにしましょう。他の有名ライブラリと同様、dojoもgoogleさんのCDNにホスティングされているので、ダウンロードや自サーバへの配置などの面倒はなくスクリプトタグ一発でロードできます。

<script src="//ajax.googleapis.com/ajax/libs/dojo/1.8.0/dojo/dojo.js"
data-dojo-config="async: true">

data-dojo-configはロードする時の設定条件を記述できます。asyncは、非同期ロードの設定です。falseなら、"base"となる関数を全て読み込むことになります。trueなら、ここでは必要最低限のロードにとどめ、後で必要なモジュールがでてきたらその時々にロードしましょうという意味になります。dojo高速化要因の一つですね。小さく産んで大きく育てるイメージでしょうか?違うか。

3-2:dojoを使う

ライブラリのロードができたので、次は実際にプログラムしてみましょう。先に述べたとおり、スクリプトをロードした段階では、便利なことはあまりできません。ajaxったり、domを操作したりということは、それぞれのモジュールを読み込まなくてはいけません。

レガシーなdojoでは、デフォルトで読み込まれるモジュールと後から読み込むモジュールが混在していました。たとえば、「ボタンを作って、それをある要素の子要素として追加する」場合、次のように書いていました。

//(dojoの)ボタンを使いたければ、dojo.requireでモジュールを読み込む
dojo.require("dijit.form.Button");

//こっからコーディング
var myButton = new dijit.form.Button({label:"click me!"});

// dojo.byIdは、document.getElementByIdをブラウザの差異を吸収
// してくれる便利関数のこと。
// これはdojo.requireしなくても使うことができる
dojo.byId("target_dom_id").appendChild(myButton.domNode);   

これがモダンになるとこうなります。

 //(dojoの)ボタンを使いたければ、requireでモジュールを読み込む
 require(["dijit/form/Button", "dojo/dom"], function(Btn, dom){
  //こっからコーディング
  var myButton = new Btn({label:"click me!"});

  // dom.byIdは、document.getElementByIdをブラウザの差異を
  //吸収してくれる便利関数のこと。
  //これはrequireの第一引数で"dojo/dom"としないと使うことができない。
  dom.byId("target_dom_id").appendChild(myButton.domNode); 
});

requireの第二引数の並び順は、第一引数の並び順に対応します。requireしたモジュールは、第二引数の関数内でのみ有効(利用可能)な事がわかると思います。なまらモダンですね!

あと、requireするときのモジュールの表し方の違いにも注目。レガシーはドット(.)区切り、モダンはスラッシュ(/)区切りです。

3-3:ajaxでのアクセス

どうすると思いますか?…はい正解です、ajaxするモジュールをrequireの第一引数で読み込み、第二引数の関数内で読み込んだ関数を実行させます。読み込むモジュール名と、関数さえわかれば簡単に実行できますよね。モジュールはdojo/request、関数はgetになります(リクエストメソッドがgetの場合です。ではpostの場合は?そうです、postです)

require(
            [
                "dojo/request"
            ],
            function(request) {
                 request.get("./data.json", {handleAs:"json"})
                        .then(function(data){
                              //リクエスト成功時。
                              //取得したデータはdataで参照できる。
                         });
            });

みたとおりですね。getの第一引数が、アクセスするURIになります。第二引数はajaxアクセスする際のパラメータで、ここではhandleAsで結果をどのように解釈するかを指定しています。次の.thenでは、リクエスト結果をハンドリングします。

ここでは引数として関数を一つ指定しています。一つ目はリクエスト成功時の処理です。先ほどhandleAsでjsonを指定していますので、ここでの関数の引数dataはjson形式として扱うことができます。

4:まとめ

雰囲気は伝わったでしょうか? このあたりを参考にしています。次回は、今回の続きで、ajaxしたものをダイアログに表示するところについて書きます。

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