Rails4 の Turbolinks と PageLess を、Rails 3 の example に沿った形で組み合わせて使うと
- page A: PageLess が有効になっているページ (画面最下部までスクロールすると表示要素が追加でオートロードされる)
- page B: PageLess を使っていないページ
というケースで、
- page A から page B に遷移しても、page B で PageLess が有効になったままになり、画面最下部までスクロールするとバックグラウンドで page A の page=2, page=3 (... page=n) が取得されてしまう
- そのため page B から page A に遷移して画面最下部までスクロールすると、本来 page=2 から取得を再開して欲しいのに page=4 (page=n+1) から取得してしまう
というような問題が起きる。
jquery.pageless.js のソース を読んでみると、最初の方に $.pagelessReset()
という関数が定義されているので、page B にこれを入れてあげると 1. の問題は解決できる。ただ、その後 page B に戻っても page A で PageLess の動作が復帰しないという副作用が発生する。
そこで、抜本的な解決策として
- TurboLinks でページ遷移する際 page:change というイベントが発生するので、そのハンドラで「毎回 $.pagelessReset() → PageLess を動作させるページなら再度 PageLess を開始」という処理を行う。
- PageLess を動作させるページに「戻る」ボタンでも遷移した時、どのページまで読み込んだかをそのページに記録しておき、1. で PageLess を再開させる際は、その記録を元に再開させる。
という方法をとる。
1 については app/assets/javascripts ディレクトリに .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 に追加する要素。
<!-- 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 では pageless
という Rails の helper メソッドを view に埋め込んでいるが、これに該当する処理は上記の application_global.js で実行されるので削除する。
これですっきりと PageLess を Turbolinks と組み合わせて使えるようになった。