PageLess と Turbolinks (Rails4) の組み合わせで、動作ページと非動作ページを切りかえる

Rails4 の [Turbolinks](https://github.com/rails/turbolinks) と [PageLess](https://github.com/jney/jquery.pageless) を、[Rails 3 の example](https://github.com/jney/jquery.pageless.demo/tree/master/example.rails3) に沿った形で組み合わせて使うと

* page A: PageLess が有効になっているページ (画面最下部までスクロールすると表示要素が追加でオートロードされる)
* page B: PageLess を使っていないページ

というケースで、

1. page A から page B に遷移しても、page B で PageLess が有効になったままになり、画面最下部までスクロールするとバックグラウンドで page A の page=2, page=3 (... page=n) が取得されてしまう
2. そのため page B から page A に遷移して画面最下部までスクロールすると、本来 page=2 から取得を再開して欲しいのに page=4 (page=n+1) から取得してしまう

というような問題が起きる。

[jquery.pageless.js のソース](https://github.com/jney/jquery.pageless/blob/master/lib/jquery.pageless.js) を読んでみると、最初の方に `$.pagelessReset()` という関数が定義されているので、page B にこれを入れてあげると 1. の問題は解決できる。ただ、その後 page B に戻っても page A で PageLess の動作が復帰しないという副作用が発生する。

そこで、抜本的な解決策として

1. TurboLinks でページ遷移する際 page:change というイベントが発生するので、そのハンドラで「毎回 $.pagelessReset() → PageLess を動作させるページなら再度 PageLess を開始」という処理を行う。
2. PageLess を動作させるページに「戻る」ボタンでも遷移した時、どのページまで読み込んだかをそのページに記録しておき、1. で PageLess を再開させる際は、その記録を元に再開させる。

という方法をとる。

1 については app/assets/javascripts ディレクトリに .js ファイルを用意して下記のような処理を入れる。

````application_global.js
$(document).on('page:change', function(e) {
  $.pagelessReset();

  // PageLess を動作させるページの path を列挙
  pageless_paths = { '/items': true, '/users': true };

  var path = document.location.pathname;
  if (pageless_paths[path]) {

    var total_pages  = Number($('#pageless-total-pages').text());
    var current_page = Number($('#pageless-current-page').text());
    var loader_image = $('#pageless-loader-image').attr('src');
    var writeCurrentPage = function () {
      $('#pageless-current-page').text(String($.pagelessCurrentPage()));
    };

    $('#results').pageless({ totalPages: total_pages,
			     currentPage: current_page,
			     url: path,
			     loaderMsg: "Loading more results",
			     loaderImage: loader_image,
			     complete: writeCurrentPage});
  }
});
````

関数 `$.pagelessCurrentPage()` は、現状の jquery.pageless.js には用意されていないので、下記のように自分で追加する。currentPage は jquery.pagelss.js 内部でインクリメント (++) されているのでこうやって値を取得するしかなさそう。

    diff ../jquery.pageless/lib/jquery.pageless.js app/assets/javascripts/jquery.pageless.js
    100a101,104
    >   $.pagelessCurrentPage = function () {
    >     return settingOrFunc('currentPage');
    >   };
    > 
    183c187,189
    <     $container.unbind(namespace);
    ---
    >     if ($container) {
    >       $container.unbind(namespace);
    >     }

修正後の 187〜189 行目では、上記 1 の使い方だと `$container` が未定義でも `$.pagelessReset()` が実行されエラーになるので、定義されているときのみ `unbind` するよう変更している (呼び出し側で try 〜 catch してもよい)。

`$.pagelessCurrentPage()` の結果は上記 application_global.js で PageLess を利用するページの view に #pageless-current-page という ID の要素へ記録している。下記が view に追加する要素。

````index.html.erb
<!-- pageless -->
<img id="pageless-loader-image" style="display: none" src="<%= image_path('load.gif') %>">
<div id="pageless-total-pages" style="display: none"><%= @items.total_pages %></div>
<div id="pageless-current-page" style="display: none">1</div>
````

また、ここでは totalPages に対応する数や `image_path()` の結果を rails で view にセットしている。

[Rails 3 の example](https://github.com/jney/jquery.pageless.demo/blob/master/example.rails3/app/views/articles/index.html.erb) では `pageless` という Rails の helper メソッドを view に埋め込んでいるが、これに該当する処理は上記の application_global.js で実行されるので削除する。

これですっきりと PageLess を Turbolinks と組み合わせて使えるようになった。