Flickrのようなページ切り替えメニューをRubyやJavaScriptで生成する

デザイン的にカッコイイページ送りを組み込みたいと思って、以下のページを参考にしたのだけど、プログラムで利用したいので、RubyJavaScriptで汎用的に使えるように作ってみました。
DiggとかFlickrのようなページ切り替えメニュー(Pagination)を実現するCSS | IDEA*IDEA

Ruby

PaginationはRails2.0では無くなるらしいが、まだ使われていると思うので有用じゃないかな。

@foo_pages, @foos = paginate(...)

なんかで取得できる@foo_pagesを引数に渡します。

  def paginate_flickr(pages)
    i = 0
    result = '<ul id="pagination-flickr">'
    
    if (pages.current.previous)
      result << '<li class="previous">'
      result << link_to('&#171;Previous', { :page => pages.current.previous })
    else
      result << '<li class="previous-off">'
      result << '&#171;Previous'
    end
    result << '</li>'
    
    pages.last.to_i.times {
      i = i+1
      if (i == pages.current.number)
        result << '<li class="active">'
        result << i.to_s
      else
        result << '<li>';
        result << link_to(i, :page => i)
      end
      result << '</li>'
    }

    if (pages.current.next)
      result << '<li class="next">'
      result << link_to('Next &#187;', { :page => pages.current.next })
    else
      result << '<li class="next-off">'
      result << 'Next &#187;'
    end
    result << '</li>'
    
    result << '</ul>'
    return result
  end

JavaScript

不要な箇所が入っちゃってるかもだけど、基本は実データを配列やオブジェクトとしてdataで渡します。

/**
	@param	data	実データの配列
	@param	items	1ページに表示する項目数
	@param	pages	前後に表示させるページネーション数
	@param	now_page	現在のページ番号
*/
function make_pagination(data, items, pages, now_page)
{
	//最後のページ
	var last_page = parseInt(data.length / items);
	if ((data.length % items) != 0) {
		last_page++;
	}
	var ulObj = document.getElementById('pagination-flickr');

	//前へ
	var prevLiObj = document.createElement("li");
	if (now_page == 1) {
		prevLiObj.className = 'previous-off';
		prevLiObj.innerHTML = 'Previous';
	} else {
		prevLiObj.className = 'previous';
		var aObj = document.createElement("a");
		var prev_page = now_page - 1;
		aObj.href = "?page=" + prev_page;
		aObj.innerHTML = '&#171;Previous';
		prevLiObj.appendChild(aObj);
	}
	ulObj.appendChild(prevLiObj);

	//次へ
	nextLiObj = document.createElement("li");
	if (now_page < last_page) {
		nextLiObj.className = 'next';
		var aObj = document.createElement("a");
		var next_page = now_page + 1;
		aObj.href = "?page=" + next_page;
		aObj.innerHTML = 'Next &#187;';
		nextLiObj.appendChild(aObj);
	} else {
		nextLiObj.className = 'next-off';
		nextLiObj.innerHTML = 'Next &#187;';
	}

	for (var i=1; i < last_page + 1; i++) {
		if (now_page - pages > i && last_page - ((pages * 2)) > i ) {
			continue;
		}
		if (now_page + pages < i && (pages * 2) +1 < i) {
			continue;
		}
		
		var liObj = document.createElement("li");
		var aObj = document.createElement("a");
		aObj.href = "?page=" + i;
		aObj.innerHTML = i;
		if (now_page == i) {
			aObj.className = 'active';
		}
		liObj.appendChild(aObj);
		ulObj.appendChild(liObj);
	}
	ulObj.appendChild(nextLiObj);

}

ここではa hrefとしてリンクしてるけど、ページ遷移でなく、DHTML/Ajax的に処理したいなら、

aObj.href = "javascript:void(0);";
addEventListener(aObj, 'click', change_page);

などとして、イベントを付加してあげればOKです。なお、イベントの追加はブラウザによって違うので、

function addEventListener(target, type, func) {
	if(target.attachEvent) {
		target.attachEvent("on" + type, func);
	} else if(target.addEventListener) {
		target.addEventListener(type, func, false);
	} else {
		target["on" + type] = func;
	}
}

でラッピングしてます。