Turbolinks for iOS のデモアプリ

Turbolinks for iOS のデモアプリを動かした際の覚書です。

# 環境

- Turbolinks for iOS 1.0.2
- OS X El Capitan
- Xcode 7.3.1
- Ruby 2.3.0
- Sinatra 1.4.7

# Server
必要なGemをインストールしてSinatraアプリを起動する。

```bash
cd TurbolinksDemo/server
bundle install --path vendor/bundle
bundle update
bundle exec rackup
```

# iOS
1. turbolinks-ios.xcworkspaceファイルをXcodeで開く。
2. TurbolinksDemo Schemeを選択し実行する。

![ios_demo_1.png](https://qiita-image-store.s3.amazonaws.com/0/5179/5f0b53de-fce6-9787-9126-42f3a342eabe.png)

![ios_demo_2.png](https://qiita-image-store.s3.amazonaws.com/0/5179/fe414508-1ad9-87b6-8688-2b35453af97a.png)


# Open a new view controller

```/one``` ページへのリンク。
[turbolinks-ios/TurbolinksDemo/server/lib/turbolinks_demo/views/index.erb](https://github.com/turbolinks/turbolinks-ios/blob/v1.0.2/TurbolinksDemo/server/lib/turbolinks_demo/views/index.erb)

```html
<ul>
  <li><a href="/one">Open a new view controller</a> by following a regular link.</li>
```

[turbolinks-ios/TurbolinksDemo/server/lib/turbolinks_demo/app.rb](https://github.com/turbolinks/turbolinks-ios/blob/v1.0.2/TurbolinksDemo/server/lib/turbolinks_demo/app.rb#L15-L18)

```rb
    get '/one' do
      @title = 'Page One'
      erb :one, layout: :layout
    end
```

[turbolinks-ios/Turbolinks/WebView.js](https://github.com/turbolinks/turbolinks-ios/blob/v1.0.2/Turbolinks/WebView.js#L54-L91)
Turbolinks を用いたリンク。iOS 用の Adapter を適用している。
[（参考）Turbolinks.visit の流れ](http://qiita.com/usutani/items/f0d84a06c7d4feb889d9)

# See the loading indicator

[turbolinks-ios/TurbolinksDemo/server/lib/turbolinks_demo/app.rb](https://github.com/turbolinks/turbolinks-ios/blob/v1.0.2/TurbolinksDemo/server/lib/turbolinks_demo/app.rb#L26)
ページを返す際に ```sleep 2``` を入れてプログレスバーを表示させている。

```rb
    get '/slow' do
      sleep 2
      @title = 'Slow Page'
      erb :slow, layout: :layout
    end
```

# Trigger an HTTP 404

存在しないページへのリンクを用意。
iOS（クライアント側）の```demoViewController.presentError```が呼ばれる。

[turbolinks-ios/TurbolinksDemo/ApplicationController.swift](https://github.com/turbolinks/turbolinks-ios/blob/v1.0.2/TurbolinksDemo/ApplicationController.swift#L81-L82)

```swift
extension ApplicationController: SessionDelegate {
...
    func session(session: Session, didFailRequestForVisitable visitable: Visitable ...
...
            case 404:
                demoViewController.presentError(.HTTPNotFoundError)
```

# Visit a protected area

[turbolinks-ios/TurbolinksDemo/ApplicationController.swift](https://github.com/turbolinks/turbolinks-ios/blob/v1.0.2/TurbolinksDemo/ApplicationController.swift#L80)

```case 401``` で ```/sign-in``` ページを返す。

[turbolinks-ios/TurbolinksDemo/server/lib/turbolinks_demo/app.rb](https://github.com/turbolinks/turbolinks-ios/blob/v1.0.2/TurbolinksDemo/server/lib/turbolinks_demo/app.rb#L40-L48)

# Load a native view controller

```/numbers``` へのリンク。

[turbolinks-ios/TurbolinksDemo/ApplicationController.swift](https://github.com/turbolinks/turbolinks-ios/blob/v1.0.2/TurbolinksDemo/ApplicationController.swift#L62-L65)

```swift
extension ApplicationController: SessionDelegate {
    func session(session: Session, didProposeVisitToURL URL: NSURL, ...
        if URL.path == "/numbers" {
            presentNumbersViewController()
```

[ApplicationController.swift#L45-L48](https://github.com/turbolinks/turbolinks-ios/blob/v1.0.2/TurbolinksDemo/ApplicationController.swift#L45-L48)

```swift
    private func presentNumbersViewController() {
        let viewController = NumbersViewController()
        pushViewController(viewController, animated: true)
    }
```

# Follow an external link
https://github.com/turbolinks/turbolinks へのリンク。

# Post a message from JavaScript

[turbolinks-ios/TurbolinksDemo/server/lib/turbolinks_demo/views/layout.erb](https://github.com/turbolinks/turbolinks-ios/blob/v1.0.2/TurbolinksDemo/server/lib/turbolinks_demo/views/layout.erb#L9-L14)

```js
      document.addEventListener("click", function(event) {
        if (event.target && event.target.matches("[data-behavior~=post-message]")) {
          webkit.messageHandlers.turbolinksDemo.postMessage("Hello from JavaScript!");
          event.preventDefault();
        }
      });
```