diff options
-rw-r--r-- | .themes/classic/source/index.html | 39 | ||||
-rw-r--r-- | _config.yml | 5 | ||||
-rw-r--r-- | plugins/pagination.rb | 121 |
3 files changed, 162 insertions, 3 deletions
diff --git a/.themes/classic/source/index.html b/.themes/classic/source/index.html index fa5310a9..e7e96956 100644 --- a/.themes/classic/source/index.html +++ b/.themes/classic/source/index.html @@ -2,4 +2,41 @@ layout: default --- -{% include blog_index.html %} +<div class="blog-index"> +{% assign index = true %} +{% for post in paginator.posts %} +{% assign content = post.content %} + <article> + {% include article.html %} + </article> +{% endfor %} +<nav role="pagination"> + <div> + {% if paginator.next_page %} + <a class="prev" href="{{paginator.next_page}}">← Older</a> + {% endif %} + <a href="/blog/archives">Blog Archives</a> + {% if paginator.previous_page %} + <a class="next" href="{{paginator.previous_page}}">Newer →</a> + {% endif %} + </div> +</nav> +{% if site.disqus_short_name %} +<script type="text/javascript"> + var disqus_shortname = '{{ site.disqus_short_name }}'; + (function () { + var s = document.createElement('script'); s.async = true; + s.type = 'text/javascript'; + s.src = 'http://' + disqus_shortname + '.disqus.com/count.js'; + (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s); + }()); +</script> +{% endif %} +</div> +<aside role=sidebar> + {% if site.blog_index_asides.size %} + {% include_array blog_index_asides %} + {% else %} + {% include_array default_asides %} + {% endif %} +</aside> diff --git a/_config.yml b/_config.yml index 3d6fee89..403f9ba8 100644 --- a/_config.yml +++ b/_config.yml @@ -29,8 +29,9 @@ category_dir: blog/categories markdown: rdiscount pygments: false # default python pygments have been replaced by pygments.rb -paginate: 10 # Posts per page on the blog index -recent_posts: 5 # Posts in the sidebar Recent Posts section +paginate: 10 # Posts per page on the blog index +pagination_dir: blog # Directory base for pagination URLs eg. /blog/page/2/ +recent_posts: 5 # Posts in the sidebar Recent Posts section # list each of the sidebar modules you want to include, in the order you want them to appear. # To add custom asides, create files in /source/_includes/custom/asides/ and add them to the list like 'custom/asides/custom_aside_name.html' diff --git a/plugins/pagination.rb b/plugins/pagination.rb new file mode 100644 index 00000000..001ddd47 --- /dev/null +++ b/plugins/pagination.rb @@ -0,0 +1,121 @@ +module Jekyll + + class Pagination < Generator + # This generator is safe from arbitrary code execution. + safe true + + # Generate paginated pages if necessary. + # + # site - The Site. + # + # Returns nothing. + def generate(site) + site.pages.dup.each do |page| + paginate(site, page) if Pager.pagination_enabled?(site.config, page) + end + end + + # Paginates the blog's posts. Renders the index.html file into paginated + # directories, e.g.: page2/index.html, page3/index.html, etc and adds more + # site-wide data. + # + # site - The Site. + # page - The index.html Page that requires pagination. + # + # {"paginator" => { "page" => <Number>, + # "per_page" => <Number>, + # "posts" => [<Post>], + # "total_posts" => <Number>, + # "total_pages" => <Number>, + # "previous_page" => <Number>, + # "next_page" => <Number> }} + def paginate(site, page) + all_posts = site.site_payload['site']['posts'] + pages = Pager.calculate_pages(all_posts, site.config['paginate'].to_i) + page_dir = page.destination('').sub(/\/[^\/]+$/, '') + page_dir_config = site.config['pagination_dir'] + dir = ((page_dir_config || page_dir) + '/').sub(/^\/+/, '') + + (1..pages).each do |num_page| + pager = Pager.new(site.config, num_page, all_posts, pages, page_dir+'/', '/'+dir) + if num_page > 1 + newpage = Page.new(site, site.source, page_dir, page.name) + newpage.pager = pager + newpage.dir = File.join(page.dir, "#{dir}page/#{num_page}") + site.pages << newpage + else + page.pager = pager + end + end + end + end + + class Pager + attr_reader :page, :per_page, :posts, :total_posts, :total_pages, :previous_page, :next_page + + # Calculate the number of pages. + # + # all_posts - The Array of all Posts. + # per_page - The Integer of entries per page. + # + # Returns the Integer number of pages. + def self.calculate_pages(all_posts, per_page) + (all_posts.size.to_f / per_page.to_i).ceil + end + + # Determine if pagination is enabled for a given file. + # + # config - The configuration Hash. + # file - The String filename of the file. + # + # Returns true if pagination is enabled, false otherwise. + def self.pagination_enabled?(config, file) + file.name == 'index.html' && !config['paginate'].nil? && file.content =~ /paginator\./ + end + + # Initialize a new Pager. + # + # config - The Hash configuration of the site. + # page - The Integer page number. + # all_posts - The Array of all the site's Posts. + # num_pages - The Integer number of pages or nil if you'd like the number + # of pages calculated. + def initialize(config, page, all_posts, num_pages = nil, index_dir, pagination_dir) + @page = page + @per_page = config['paginate'].to_i + @page_dir = pagination_dir + 'page/' + @total_pages = num_pages || Pager.calculate_pages(all_posts, @per_page) + @previous_page = nil + + if @page > @total_pages + raise RuntimeError, "page number can't be greater than total pages: #{@page} > #{@total_pages}" + end + + init = (@page - 1) * @per_page + offset = (init + @per_page - 1) >= all_posts.size ? all_posts.size : (init + @per_page - 1) + + @total_posts = all_posts.size + @posts = all_posts[init..offset] + @previous_page = @page != 1 ? @page_dir + (@page - 1).to_s + '/' : nil + @previous_page = index_dir if @page - 1 == 1 + @next_page = @page != @total_pages ? @page_dir + (@page + 1).to_s + '/' : nil + end + + # Convert this Pager's data to a Hash suitable for use by Liquid. + # + # Returns the Hash representation of this Pager. + def to_liquid + { + 'page' => page, + 'per_page' => per_page, + 'posts' => posts, + 'total_posts' => total_posts, + 'total_pages' => total_pages, + 'previous_page' => previous_page, + 'next_page' => next_page + } + end + end + +end + |