Haxeでpushstate対応のRouter作った

HaxeでSPAを作ろうと思い立ちました。
Haxeで書くのでjQueryに依存しないルーティングライブラリが欲しかったのですがそういったexternが探しても見つからない。
[Kazitori.js](http://kazitori.org/)というライブラリはexternもあるし、外部ライブラリにも依存してなくていい感じだったのですが、事後処理を登録出来ないところがネックで利用を断念…
そんな訳で自作してしまった。
（Kazitori.jsを調べた後で書き出したせいか、多くの影響をKazitori.jsから受けております。）

# RouterHx

RouterHxはjavascriptまたはhaxe(jsターゲット)で利用出来るpushstate対応のrouterライブラリです。

javascriptの他のライブラリに依存することなく利用することが出来ます。

古いブラウザでは動作しません。
リンクをパーマリンクに変換するような気の利いたことも出来ません。

`addEventristener`,`querySelectorAll`,`pushState(popState)`が使えないブラウザはごめんなさい。

## ダウンロード

GitHubで公開してます
`git clone　https://github.com/k-motoyan/routerhx`

Haxeの場合は`haxelib`からインストール出来ます
`haxelib git routerhx https://github.com/k-motoyan/routerhx`

## 基本的な使い方

Routerクラスをインスタンス化して、`add`メソッドにURL、処理を持つクラス名、クラスから実行したいメソッド名を指定します。

### javascriptの場合
```js
function App() {
  this.index = function() {
    console.log("app index");
  }
  this.greet = function(message) {
    console.log(message);
  }
}

var router = new RouterHx();
router.add("/", "App", "index");
router.add("/greet/<message>", "App", "greet");
```

### Haxeの場合
```hx
import routerhx.Router;

class Main {
  public function new() {
    var router = new Router();
    router.add("/", "App", "index");
    router.add("/greet/<message>", "App", "greet");
  }

  static function main() {
    new Main();
  }
}

class App {
  public function index() {
    trace("app index");
  }
  public function greet(message) {
    trace(message);
  }
}
```

## pushstateしてみる

RouterHxはルーティングを定義するだけではpushStateどころか登録した処理は実行されません。
`raisePushState`メソッドを実行することで、対象のセレクタをpushステート対応のエレメントに変化させます。

aタグをクリックしたらrouterに登録した処理を実行させたいといった場合のサンプルです。

### javascriptの場合

```js
var router = new RouterHx();
router.raisePushState("a", "click", "href");
```

### Haxeの場合

```hx
import routerhx.Router;

class Main {
  public function new() {
    var router = new Router();
    router.raisePushState("a", "click", "href");
  }

  static function main() {
    new Main();
  }
}
```

`raisePushState`メソッドは指定したセレクタをまとめてpushState対応のエレメントに変化させるもので、
個別にrouterに登録したURLを実行した時もあると思います。
そういった場合は`run`メソッドを実行することで、routerに登録したURLを実行することが可能です。

### javascriptの場合
```js
var App = function() {
  this.index = function() {
    console.log("app index");
  }
}

var router = new RouterHx();
router.add("/", "App", "index");
router.run("/");
```

### Haxeの場合
```hx
import routerhx.Router;

class Main {
  public function new() {
    var router = new Router();
    router.add("/", "App", "index");
    router.run("/");
  }

  static function main() {
    new Main();
  }
}

class App {
  public function index() {
    trace("app index");
  }
}
```

## マイクロフレームワーク風な書き方

RouterHxはルーティングの設定の方法が2つあります。
一つ目は最初に書いた`add`メソッドにインスタンス、インスタンスから実行するメソッドを記述する方法でした。
この方法はアプリケーションの規模が大きくなった場合にコードの構造化をやりやすくします。

規模が小さいアプリケーションの場合は、`addCb`メソッドに単純にコールバックを登録することでもルーティングを登録することが出来ます。

### javascriptの場合

```js
var router = new RouterHx();
router.addCb("/", function() {
  console.log("index");
});
router.addCb("/greet/<message>", function(message) {
  console.log(message);
});
```

### Haxeの場合

```hx
import routerhx.Router;

class Main {
  public function new() {
    var router = new Router();
    router.addCb("/", function() {
      trace("index");
    });
    router.addCb("/greet/<message>", function(message) {
      trace(message);
    });
  }

  static function main() {
    new Main();
  }
}
```

## RouterHxインスタンス単位での事前処理・事後処理

`setBefore`、`setAfter`を利用することで、RouterHxのインスタンス単位に事前処理、事後処理を登録することが可能です。

### javascriptの場合
```js
var router1 = new RouterHx();
router1.setBefore(function() {
  console.log("router1 proc start.");
});
router1.setAfter(function() {
  console.log("router1 proc end.");
});

var router2 = new RouterHx();
router2.setBefore(function() {
  console.log("router2 proc start.");
});
router2.setAfter(function() {
  console.log("router2 proc end.");
});
```

### Haxeの場合
```hx
import routerhx.Router;

class Main {
  public function new() {
    var router1 = new Router(),
        router2 = new Router();

    router1.setBefore(_before1);
    router1.setAfter(_after1);
    router2.setBefore(_before2);
    router2.setAfter(_after2);
  }

  inline function _before1(): Void {
    trace("router1 proc start.");
  }
  inline function _after1(): Void {
    trace("router1 proc end.");
  }
  inline function _before2(): Void {
    trace("router2 proc start.");
  }
  inline function _after2(): Void {
    trace("router2 proc end.");
  }
}
```

## RouterHxに登録したインスタンス単位の事前処理・事後処理

 RouterHxに登録したインスタンスに`before`、`after`メソッドを登録しておくことでそのインスタンスのメソッド実行前・実行後に行う処理を登録しておくことが可能です。

`setBefore`、`setAfter`がRouterHxインスタンスのグローバルな事前処理・事後処理であるのに対して、
この方法はRouterHxに登録したインスタンス単位の事前処理・事後処理を登録することになります。
処理の順番は下記のようになります。

①`setBefore`で登録した処理
②`before`メソッドに記述した処理
③RouteHxのルーティングに登録した処理
④`after`メソッドに記述した処理
⑤`setAfter`で登録した処理

### javascriptの場合
```js
var App = function() {
  this.before = function() {
    console.log("app before");
  };
  this.index = function() {
    console.log("app index");
  };
  this.after = function() {
    console.log("app after");
  };
}

var router = new RouterHx();
router.add("/", "App", "index");
```

### Haxeの場合
```hx
import routerhx.Router;

class Main {
  public function new() {
    var router = new Router();
    router.add("/", "App", "index");
  }

  static function main() {
    new Main();
  }
}

class App {
  public function before() {
    trace("app before");
  }
  public function index() {
    trace("app index");
  }
  public function after() {
    trace("app after");
  }
}
```

## 今後の展望
作っていたら中々使い勝手いいんじゃない？と思える出来栄えになったので今後もメンテ続けて行けたらと思う。
取り敢えずは↓の実装を進めていきたいな…

- `raisePushState`って名前がおかしいので直す
- オプションでURLをhash bangに切り替えられるようにする