Anonymous avatar Anonymous committed 386afa3

First commit.

Comments (0)

Files changed (23)

+\.pyc$
+.DS_Store
+~$
+Francesco Banconi <francesco.banconi@gmail.com>
+To install django-endless-pagination, run the following command 
+inside this directory:
+
+    python setup.py install
+
+Or if you'd prefer you can simply place the included ``endless_pagination``
+package on your Python path.
+Copyright (c) 2009 Francesco Banconi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+include AUTHORS
+include INSTALL
+include LICENSE
+include MANIFEST.in
+recursive-include doc *
+recursive-include media *
+recursive-include endless_pagination/locale *
+recursive-include endless_pagination/templates *

doc/docutils.conf

+[general]
+language_code: it
+input_encoding: utf-8
+output_encoding: utf-8
+toc_backlinks: entry
+generator: no
+source_link: no
+
+[html4css1 writer]
+cloak_email_addresses: no
+embed_stylesheet: yes
+stylesheet_path: local.css
+field_name_limit: 0
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Date: $Date: 2005-05-26 12:51:39 +0200 (Thu, 26 May 2005) $
+:Version: $Revision: 3368 $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+*/
+
+/* "! important" is used here to override other ``margin-top`` and
+   ``margin-bottom`` styles that are later in the stylesheet or 
+   more specific.  See http://www.w3.org/TR/CSS1#the-cascade */
+.first {
+  margin-top: 0 ! important }
+
+.last, .with-subtitle {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+a[href]:hover {
+  text-decoration: underline;
+  color: blue;
+}
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+  font-weight: bold }
+*/
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em }
+
+div.footer, div.header {
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin-left: 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em }
+
+h1.title {
+  text-align: center }
+
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.line-block {
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+span.section-subtitle {
+  /* font-size relative to parent (<h#> element) */
+  font-size: 80% }
+
+table.citation {
+  border-left: solid thin gray }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+/*
+tt.docutils {
+  background-color: #eeeeee }
+*/
+
+ul.auto-toc {
+  list-style-type: none }
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="it" lang="it">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" />
+<title>Endless Pagination</title>
+<style type="text/css">
+
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Date: $Date: 2005-05-26 12:51:39 +0200 (Thu, 26 May 2005) $
+:Version: $Revision: 3368 $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+*/
+
+/* "! important" is used here to override other ``margin-top`` and
+   ``margin-bottom`` styles that are later in the stylesheet or 
+   more specific.  See http://www.w3.org/TR/CSS1#the-cascade */
+.first {
+  margin-top: 0 ! important }
+
+.last, .with-subtitle {
+  margin-bottom: 0 ! important }
+
+.hidden {
+  display: none }
+
+a.toc-backref {
+  text-decoration: none ;
+  color: black }
+
+a[href]:hover {
+  text-decoration: underline;
+  color: blue;
+}
+
+blockquote.epigraph {
+  margin: 2em 5em ; }
+
+dl.docutils dd {
+  margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+  font-weight: bold }
+*/
+
+div.abstract {
+  margin: 2em 5em }
+
+div.abstract p.topic-title {
+  font-weight: bold ;
+  text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+  margin: 2em ;
+  border: medium outset ;
+  padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+  font-weight: bold ;
+  font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+  color: red ;
+  font-weight: bold ;
+  font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+   compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+  margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+  margin-top: 0.5em }
+*/
+
+div.dedication {
+  margin: 2em 5em ;
+  text-align: center ;
+  font-style: italic }
+
+div.dedication p.topic-title {
+  font-weight: bold ;
+  font-style: normal }
+
+div.figure {
+  margin-left: 2em }
+
+div.footer, div.header {
+  font-size: smaller }
+
+div.line-block {
+  display: block ;
+  margin-top: 1em ;
+  margin-bottom: 1em }
+
+div.line-block div.line-block {
+  margin-top: 0 ;
+  margin-bottom: 0 ;
+  margin-left: 1.5em }
+
+div.sidebar {
+  margin-left: 1em ;
+  border: medium outset ;
+  padding: 1em ;
+  background-color: #ffffee ;
+  width: 40% ;
+  float: right ;
+  clear: right }
+
+div.sidebar p.rubric {
+  font-family: sans-serif ;
+  font-size: medium }
+
+div.system-messages {
+  margin: 5em }
+
+div.system-messages h1 {
+  color: red }
+
+div.system-message {
+  border: medium outset ;
+  padding: 1em }
+
+div.system-message p.system-message-title {
+  color: red ;
+  font-weight: bold }
+
+div.topic {
+  margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+  margin-top: 0.4em }
+
+h1.title {
+  text-align: center }
+
+h2.subtitle {
+  text-align: center }
+
+hr.docutils {
+  width: 75% }
+
+ol.simple, ul.simple {
+  margin-bottom: 1em }
+
+ol.arabic {
+  list-style: decimal }
+
+ol.loweralpha {
+  list-style: lower-alpha }
+
+ol.upperalpha {
+  list-style: upper-alpha }
+
+ol.lowerroman {
+  list-style: lower-roman }
+
+ol.upperroman {
+  list-style: upper-roman }
+
+p.attribution {
+  text-align: right ;
+  margin-left: 50% }
+
+p.caption {
+  font-style: italic }
+
+p.credits {
+  font-style: italic ;
+  font-size: smaller }
+
+p.label {
+  white-space: nowrap }
+
+p.rubric {
+  font-weight: bold ;
+  font-size: larger ;
+  color: maroon ;
+  text-align: center }
+
+p.sidebar-title {
+  font-family: sans-serif ;
+  font-weight: bold ;
+  font-size: larger }
+
+p.sidebar-subtitle {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+p.topic-title {
+  font-weight: bold }
+
+pre.address {
+  margin-bottom: 0 ;
+  margin-top: 0 ;
+  font-family: serif ;
+  font-size: 100% }
+
+pre.line-block {
+  font-family: serif ;
+  font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+  margin-left: 2em ;
+  margin-right: 2em ;
+  background-color: #eeeeee }
+
+span.classifier {
+  font-family: sans-serif ;
+  font-style: oblique }
+
+span.classifier-delimiter {
+  font-family: sans-serif ;
+  font-weight: bold }
+
+span.interpreted {
+  font-family: sans-serif }
+
+span.option {
+  white-space: nowrap }
+
+span.pre {
+  white-space: pre }
+
+span.problematic {
+  color: red }
+
+span.section-subtitle {
+  /* font-size relative to parent (<h#> element) */
+  font-size: 80% }
+
+table.citation {
+  border-left: solid thin gray }
+
+table.docinfo {
+  margin: 2em 4em }
+
+table.docutils {
+  margin-top: 0.5em ;
+  margin-bottom: 0.5em }
+
+table.footnote {
+  border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+  padding-left: 0.5em ;
+  padding-right: 0.5em ;
+  vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+  font-weight: bold ;
+  text-align: left ;
+  white-space: nowrap ;
+  padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+  font-size: 100% }
+
+/*
+tt.docutils {
+  background-color: #eeeeee }
+*/
+
+ul.auto-toc {
+  list-style-type: none }
+
+</style>
+</head>
+<body>
+<div class="document" id="endless-pagination">
+<h1 class="title">Endless Pagination</h1>
+<table class="docinfo" frame="void" rules="none">
+<col class="docinfo-name" />
+<col class="docinfo-content" />
+<tbody valign="top">
+<tr class="field"><th class="docinfo-name">Author:</th><td class="field-body">Francesco Banconi &lt;<a class="reference external" href="mailto:francesco.banconi&#64;gmail.com">francesco.banconi&#64;gmail.com</a>&gt;</td>
+</tr>
+</tbody>
+</table>
+<div class="contents topic" id="index">
+<p class="topic-title first">Index</p>
+<ul class="auto-toc simple">
+<li><a class="reference internal" href="#introduction" id="id1">1&nbsp;&nbsp;&nbsp;Introduction</a></li>
+<li><a class="reference internal" href="#installation" id="id2">2&nbsp;&nbsp;&nbsp;Installation</a><ul class="auto-toc">
+<li><a class="reference internal" href="#requirements" id="id3">2.1&nbsp;&nbsp;&nbsp;Requirements</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#usage" id="id4">3&nbsp;&nbsp;&nbsp;Usage</a><ul class="auto-toc">
+<li><a class="reference internal" href="#settings" id="id5">3.1&nbsp;&nbsp;&nbsp;Settings</a></li>
+<li><a class="reference internal" href="#let-s-start" id="id6">3.2&nbsp;&nbsp;&nbsp;Let's start</a></li>
+<li><a class="reference internal" href="#split-the-template" id="id7">3.3&nbsp;&nbsp;&nbsp;Split the template</a></li>
+<li><a class="reference internal" href="#a-shortcut-for-ajaxed-views" id="id8">3.4&nbsp;&nbsp;&nbsp;A shortcut for ajaxed views</a></li>
+<li><a class="reference internal" href="#pagination" id="id9">3.5&nbsp;&nbsp;&nbsp;Pagination</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#templatetags-reference" id="id10">4&nbsp;&nbsp;&nbsp;Templatetags reference</a><ul class="auto-toc">
+<li><a class="reference internal" href="#paginate" id="id11">4.1&nbsp;&nbsp;&nbsp;paginate</a></li>
+<li><a class="reference internal" href="#show-more" id="id12">4.2&nbsp;&nbsp;&nbsp;show_more</a></li>
+</ul>
+</li>
+<li><a class="reference internal" href="#customization" id="id13">5&nbsp;&nbsp;&nbsp;Customization</a></li>
+</ul>
+</div>
+<div class="section" id="introduction">
+<h1><a class="toc-backref" href="#id1">1&nbsp;&nbsp;&nbsp;Introduction</a></h1>
+<p>This app may be used to provide Twitter-style ajaxed pagination. Future
+developments will add support for normal Digg-style pagination.</p>
+<p>The initial idea, which has guided the development of this application,
+is to allow ajax pagination of web contents in very few steps, as done by
+the excellent tool <em>django-pagination</em>
+(see <a class="reference external" href="http://github.com/ericflo/django-pagination/tree/master">http://github.com/ericflo/django-pagination/tree/master</a>).</p>
+</div>
+<div class="section" id="installation">
+<h1><a class="toc-backref" href="#id2">2&nbsp;&nbsp;&nbsp;Installation</a></h1>
+<p>The <tt class="docutils literal"><span class="pre">endless_pagination</span></tt> package, included in the distribution, should be
+placed on the <em>Python path</em>.</p>
+<p>Or just <tt class="docutils literal"><span class="pre">easy_install</span> <span class="pre">django-endless-pagination</span></tt>.</p>
+<div class="section" id="requirements">
+<h2><a class="toc-backref" href="#id3">2.1&nbsp;&nbsp;&nbsp;Requirements</a></h2>
+<ul class="simple">
+<li>Python &gt;= 2.5</li>
+<li>Django &gt;= 1.0</li>
+<li>jQuery &gt;= 1.3</li>
+</ul>
+</div>
+</div>
+<div class="section" id="usage">
+<h1><a class="toc-backref" href="#id4">3&nbsp;&nbsp;&nbsp;Usage</a></h1>
+<div class="section" id="settings">
+<h2><a class="toc-backref" href="#id5">3.1&nbsp;&nbsp;&nbsp;Settings</a></h2>
+<p>Add the request context processor in your <em>settings.py</em>, e.g.:</p>
+<pre class="literal-block">
+from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS
+TEMPLATE_CONTEXT_PROCESSORS += (
+     'django.core.context_processors.request',
+)
+</pre>
+<p>Add <tt class="docutils literal"><span class="pre">'endless_pagination'</span></tt> to the <tt class="docutils literal"><span class="pre">INSTALLED_APPS</span></tt> in your <em>settings.py</em>.</p>
+<p>See <em>Customization</em> section of this documentation for other settings options.</p>
+</div>
+<div class="section" id="let-s-start">
+<h2><a class="toc-backref" href="#id6">3.2&nbsp;&nbsp;&nbsp;Let's start</a></h2>
+<p>As creative example, the developer wants pagination of entries of a blog post.</p>
+<p>In <em>views.py</em> we have:</p>
+<pre class="literal-block">
+def entry_index(request, template=&quot;myapp/entry_index.html&quot;):
+    context = {
+        'objects': Entry.objects.all(),
+    }
+    return render_to_response(template, context,
+        context_instance=RequestContext(request))
+</pre>
+<p>In <em>myapp/entry_index.html</em>:</p>
+<pre class="literal-block">
+&lt;h2&gt;Entries:&lt;/h2&gt;
+{% for object in objects %}
+    {# your code to show the entry #}
+{% endfor %}
+</pre>
+</div>
+<div class="section" id="split-the-template">
+<h2><a class="toc-backref" href="#id7">3.3&nbsp;&nbsp;&nbsp;Split the template</a></h2>
+<p>A response to an AJAX request should not return the entire template,
+but only the portion of the page to update or add.
+So it is convenient to extrapolate from the template the part containing entries
+and use the new one to render the context if the request is AJAX.
+The main template will include the other, so it is convenient to put
+the page template in the context.</p>
+<p><em>views.py</em> becomes:</p>
+<pre class="literal-block">
+def entry_index(request,
+    template=&quot;myapp/entry_index.html&quot;,
+    page_template=&quot;myapp/entry_index_page.html&quot;):
+    context = {
+        'objects': Entry.objects.all(),
+        'page_template': page_template,
+    }
+    if request.is_ajax():
+        template = page_template
+    return render_to_response(template, context,
+        context_instance=RequestContext(request))
+</pre>
+<p>See below how to obtain the same result <strong>just decorating the view</strong>
+(in a way compatible with generic views too).</p>
+<p><em>myapp/entry_index.html</em> becomes:</p>
+<pre class="literal-block">
+&lt;h2&gt;Entries:&lt;/h2&gt;
+{% include page_template %}
+</pre>
+<p><em>myapp/entry_index_page.html</em> becomes:</p>
+<pre class="literal-block">
+{% for object in objects %}
+    {# your code to show the entry #}
+{% endfor %}
+</pre>
+</div>
+<div class="section" id="a-shortcut-for-ajaxed-views">
+<h2><a class="toc-backref" href="#id8">3.4&nbsp;&nbsp;&nbsp;A shortcut for ajaxed views</a></h2>
+<p>A good practice in writing views is to allow other developers to inject
+the template name and extra data to be added to the context.
+This allows the view to be easily reused. Let's resume the original view
+with extra context injection:</p>
+<p><em>views.py</em>:</p>
+<pre class="literal-block">
+def entry_index(request, template=&quot;myapp/entry_index.html&quot;,
+    extra_context={}):
+    context = {
+        'objects': Entry.objects.all(),
+    }
+    context.upgrade(extra_context)
+    return render_to_response(template, context,
+        context_instance=RequestContext(request))
+</pre>
+<p>Splitting templates and putting the ajax template name in the context
+is easily achievable at this point (using a builtin decorator).</p>
+<p><em>views.py</em> becomes:</p>
+<pre class="literal-block">
+from endless_pagination.decorators import page_template
+
+&#64;page_template(&quot;myapp/entry_index_page.html&quot;) # just add this decorator
+def entry_index(request, template=&quot;myapp/entry_index.html&quot;,
+    extra_context={}):
+    context = {
+        'objects': Entry.objects.all(),
+    }
+    context.upgrade(extra_context)
+    return render_to_response(template, context,
+        context_instance=RequestContext(request))
+</pre>
+<p>This way, <em>endless-pagination</em> can be included in <strong>generic views</strong> too.</p>
+</div>
+<div class="section" id="pagination">
+<h2><a class="toc-backref" href="#id9">3.5&nbsp;&nbsp;&nbsp;Pagination</a></h2>
+<p>Nothing remains but to change the page template, loading endless templatetags and
+the javascript file <em>endless.js</em> included in the distribution under <tt class="docutils literal"><span class="pre">/media/js/</span></tt>.</p>
+<p><em>myapp/entry_index.html</em> becomes:</p>
+<pre class="literal-block">
+{% block js %}
+    {{ block.super }}
+    &lt;script src=&quot;/path/to/endless.js&quot; type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
+{% endblock %}
+
+&lt;h2&gt;Entries:&lt;/h2&gt;
+{% include page_template %}
+</pre>
+<p><em>myapp/entry_index_page.html</em> becomes:</p>
+<pre class="literal-block">
+{% load endless %}
+
+{% paginate objects %}
+{% for object in objects %}
+    {# your code to show the entry #}
+{% endfor %}
+{% show_more %}
+</pre>
+<p>That's all. Read the next section of the documentation to improve the use of
+included templatetags.</p>
+</div>
+</div>
+<div class="section" id="templatetags-reference">
+<h1><a class="toc-backref" href="#id10">4&nbsp;&nbsp;&nbsp;Templatetags reference</a></h1>
+<div class="section" id="paginate">
+<h2><a class="toc-backref" href="#id11">4.1&nbsp;&nbsp;&nbsp;paginate</a></h2>
+<p>Usage:</p>
+<pre class="literal-block">
+{% paginate objects %}
+</pre>
+<p>After this call, in the template context the <em>objects</em> variable is replaced
+with only the objects of the current page.</p>
+<p>You can also mantain your <em>objects</em> original variable (commonly a queryset)
+and add to context another name referring to objects of the current page,
+e.g.:</p>
+<pre class="literal-block">
+{% paginate objects as page_objects %}
+</pre>
+<p>The number of paginated object is taken from settings, but you can
+override the default, e.g.:</p>
+<pre class="literal-block">
+{% paginate 20 objects %}
+</pre>
+<p>Of course you can mix it all:</p>
+<pre class="literal-block">
+{% paginate 20 objects as paginated_objects %}
+</pre>
+<p>You must use this tag before calling the <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">show_more</span> <span class="pre">%}</span></tt> one.</p>
+</div>
+<div class="section" id="show-more">
+<h2><a class="toc-backref" href="#id12">4.2&nbsp;&nbsp;&nbsp;show_more</a></h2>
+<p>Show the link to get the next page in a Twitter-like pagination.
+Usage:</p>
+<pre class="literal-block">
+{% show_more %}
+</pre>
+<p>Must be called after <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">paginate</span> <span class="pre">objects</span> <span class="pre">%}</span></tt>.</p>
+</div>
+</div>
+<div class="section" id="customization">
+<h1><a class="toc-backref" href="#id13">5&nbsp;&nbsp;&nbsp;Customization</a></h1>
+<p>You can customize the application using <tt class="docutils literal"><span class="pre">settings.py</span></tt>.</p>
+<ul>
+<li><p class="first"><em>ENDLESS_PAGINATION_PER_PAGE</em> (default=10):
+How many objects are normally displayed in a page (overwriteable by templatetag).</p>
+</li>
+<li><p class="first"><em>ENDLESS_PAGINATION_PAGE_LABEL</em> (default=&quot;page&quot;):
+The querystring key of the page number (e.g. <tt class="docutils literal"><span class="pre">http://example.com?page=2</span></tt>)</p>
+</li>
+<li><p class="first"><em>ENDLESS_PAGINATION_ORPHANS</em> (default=0):
+See django <em>Paginator</em> definition of orphans.</p>
+</li>
+<li><p class="first"><em>ENDLESS_PAGINATION_SHOW_MORE_TEMPLATE</em> (default=&quot;endless/show_more.html&quot;):
+The template used by <em>show_more</em> templatetag.
+You can provide your customized template that must meet the following rules:
+- <em>more</em> link is showed only if variable &quot;querystring&quot; is not False
+- the container (most external html element) class is <em>endless_container</em>
+- the <em>more</em> link and the loader hidden element live inside the container
+- the <em>more</em> link class is <em>endless_more</em>
+- the loader hidden element class is <em>endless_loading</em></p>
+</li>
+<li><p class="first"><em>ENDLESS_PAGINATION_LOADING</em> (default=&quot;loading&quot;):
+If you use the default <em>show_more</em> template, here you can customize
+the content of the loader hidden element
+Html is safe here, e.g. you can show your pretty animated gif:</p>
+<pre class="literal-block">
+ENDLESS_PAGINATION_LOADING = &quot;&quot;&quot;
+    &lt;img src=&quot;/site_media/img/loader.gif&quot; alt=&quot;loading&quot; /&gt;
+&quot;&quot;&quot;
+</pre>
+</li>
+</ul>
+</div>
+</div>
+</body>
+</html>
+==================
+Endless Pagination
+==================
+
+:Author: Francesco Banconi <francesco.banconi@gmail.com>
+
+.. contents:: Index
+
+.. sectnum::
+
+Introduction
+============
+
+This app may be used to provide Twitter-style ajaxed pagination. Future
+developments will add support for normal Digg-style pagination.
+
+The initial idea, which has guided the development of this application, 
+is to allow ajax pagination of web contents in very few steps, as done by 
+the excellent tool *django-pagination* 
+(see http://github.com/ericflo/django-pagination/tree/master).
+
+
+Installation
+============
+
+The ``endless_pagination`` package, included in the distribution, should be
+placed on the *Python path*.
+
+Or just ``easy_install django-endless-pagination``.
+
+Requirements
+~~~~~~~~~~~~
+
+- Python >= 2.5
+- Django >= 1.0
+- jQuery >= 1.3
+
+
+Usage
+=====
+
+Settings 
+~~~~~~~~
+
+Add the request context processor in your *settings.py*, e.g.::
+    
+    from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS
+    TEMPLATE_CONTEXT_PROCESSORS += (
+         'django.core.context_processors.request',
+    )
+    
+Add ``'endless_pagination'`` to the ``INSTALLED_APPS`` in your *settings.py*.
+
+See *Customization* section of this documentation for other settings options.
+
+Let's start
+~~~~~~~~~~~
+
+As creative example, the developer wants pagination of entries of a blog post.
+
+In *views.py* we have::
+
+    def entry_index(request, template="myapp/entry_index.html"):
+        context = {
+            'objects': Entry.objects.all(),
+        }
+        return render_to_response(template, context, 
+            context_instance=RequestContext(request))
+
+In *myapp/entry_index.html*::
+
+    <h2>Entries:</h2>
+    {% for object in objects %}
+        {# your code to show the entry #}
+    {% endfor %}
+
+Split the template
+~~~~~~~~~~~~~~~~~~
+
+A response to an AJAX request should not return the entire template, 
+but only the portion of the page to update or add. 
+So it is convenient to extrapolate from the template the part containing entries 
+and use the new one to render the context if the request is AJAX.
+The main template will include the other, so it is convenient to put
+the page template in the context.
+
+*views.py* becomes::
+    
+    def entry_index(request, 
+        template="myapp/entry_index.html", 
+        page_template="myapp/entry_index_page.html"):
+        context = {
+            'objects': Entry.objects.all(),
+            'page_template': page_template,
+        }
+        if request.is_ajax(): 
+            template = page_template
+        return render_to_response(template, context, 
+            context_instance=RequestContext(request))
+            
+See below how to obtain the same result **just decorating the view**
+(in a way compatible with generic views too).
+            
+*myapp/entry_index.html* becomes::
+
+    <h2>Entries:</h2>
+    {% include page_template %}
+    
+*myapp/entry_index_page.html* becomes::
+
+    {% for object in objects %}
+        {# your code to show the entry #}
+    {% endfor %}
+
+A shortcut for ajaxed views
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A good practice in writing views is to allow other developers to inject
+the template name and extra data to be added to the context.
+This allows the view to be easily reused. Let's resume the original view
+with extra context injection:
+
+*views.py*::
+
+    def entry_index(request, template="myapp/entry_index.html", 
+        extra_context={}):
+        context = {
+            'objects': Entry.objects.all(),
+        }
+        context.upgrade(extra_context)
+        return render_to_response(template, context, 
+            context_instance=RequestContext(request))
+
+Splitting templates and putting the ajax template name in the context 
+is easily achievable at this point (using a builtin decorator).
+
+*views.py* becomes::
+
+    from endless_pagination.decorators import page_template
+    
+    @page_template("myapp/entry_index_page.html") # just add this decorator
+    def entry_index(request, template="myapp/entry_index.html", 
+        extra_context={}):
+        context = {
+            'objects': Entry.objects.all(),
+        }
+        context.upgrade(extra_context)
+        return render_to_response(template, context, 
+            context_instance=RequestContext(request))
+
+This way, *endless-pagination* can be included in **generic views** too.
+
+Pagination
+~~~~~~~~~~
+
+Nothing remains but to change the page template, loading endless templatetags and
+the javascript file *endless.js* included in the distribution under ``/media/js/``.
+
+*myapp/entry_index.html* becomes::
+
+    {% block js %}
+        {{ block.super }}
+        <script src="/path/to/endless.js" type="text/javascript" charset="utf-8"></script>
+    {% endblock %}
+    
+    <h2>Entries:</h2>
+    {% include page_template %}
+
+*myapp/entry_index_page.html* becomes::
+
+    {% load endless %}
+    
+    {% paginate objects %}
+    {% for object in objects %}
+        {# your code to show the entry #}
+    {% endfor %}
+    {% show_more %}
+
+That's all. Read the next section of the documentation to improve the use of 
+included templatetags.
+
+
+Templatetags reference
+======================
+
+paginate
+~~~~~~~~
+
+Usage::
+
+    {% paginate objects %}
+
+After this call, in the template context the *objects* variable is replaced
+with only the objects of the current page.
+
+You can also mantain your *objects* original variable (commonly a queryset)
+and add to context another name referring to objects of the current page, 
+e.g.::
+
+    {% paginate objects as page_objects %}
+    
+The number of paginated object is taken from settings, but you can
+override the default, e.g.::
+
+    {% paginate 20 objects %}
+    
+Of course you can mix it all::
+
+    {% paginate 20 objects as paginated_objects %}
+    
+You must use this tag before calling the ``{% show_more %}`` one.
+
+show_more
+~~~~~~~~~
+
+Show the link to get the next page in a Twitter-like pagination.
+Usage::
+
+    {% show_more %}
+    
+Must be called after ``{% paginate objects %}``.
+
+
+Customization
+=============
+
+You can customize the application using ``settings.py``.
+
+- *ENDLESS_PAGINATION_PER_PAGE* (default=10): 
+  How many objects are normally displayed in a page (overwriteable by templatetag).
+
+- *ENDLESS_PAGINATION_PAGE_LABEL* (default="page"):
+  The querystring key of the page number (e.g. ``http://example.com?page=2``)
+
+- *ENDLESS_PAGINATION_ORPHANS* (default=0):
+  See django *Paginator* definition of orphans.
+
+- *ENDLESS_PAGINATION_SHOW_MORE_TEMPLATE* (default="endless/show_more.html"):
+  The template used by *show_more* templatetag.
+  You can provide your customized template that must meet the following rules:
+  - *more* link is showed only if variable "querystring" is not False
+  - the container (most external html element) class is *endless_container*
+  - the *more* link and the loader hidden element live inside the container
+  - the *more* link class is *endless_more*
+  - the loader hidden element class is *endless_loading*
+  
+- *ENDLESS_PAGINATION_LOADING* (default="loading"):
+  If you use the default *show_more* template, here you can customize
+  the content of the loader hidden element
+  Html is safe here, e.g. you can show your pretty animated gif::
+  
+     ENDLESS_PAGINATION_LOADING = """
+         <img src="/site_media/img/loader.gif" alt="loading" />
+     """
+
+== Endless Pagination ==
+
+Author: Francesco Banconi <[mailto:francesco.banconi@gmail.com francesco.banconi@gmail.com]>
+
+
+== 1   Introduction ==
+
+This app may be used to provide Twitter-style ajaxed pagination. Future developments will add support for normal Digg-style pagination.
+
+The initial idea, which has guided the development of this application, is to allow ajax pagination of web contents in very few steps, as done by the excellent tool *django-pagination*(see [http://github.com/ericflo/django-pagination/tree/master http://github.com/ericflo/django-pagination/tree/master]).
+
+== 2   Installation ==
+
+The `endless_pagination` package, included in the distribution, should be placed on the *Python path*.
+
+Or just `easy_install django-endless-pagination`.
+
+== 2.1   Requirements ==
+
+ * Python >= 2.5
+
+ * Django >= 1.0
+
+ * jQuery >= 1.3
+
+
+
+== 3   Usage ==
+
+== 3.1   Settings ==
+
+Add the request context processor in your *settings.py*, e.g.:
+
+{{{
+from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS
+TEMPLATE_CONTEXT_PROCESSORS += (
+     'django.core.context_processors.request',
+)
+}}}
+
+Add `'endless_pagination'` to the `INSTALLED_APPS` in your *settings.py*.
+
+See *Customization* section of this documentation for other settings options.
+
+== 3.2   Let's start ==
+
+As creative example, the developer wants pagination of entries of a blog post.
+
+In *views.py* we have:
+
+{{{
+def entry_index(request, template="myapp/entry_index.html"):
+    context = {
+        'objects': Entry.objects.all(),
+    }
+    return render_to_response(template, context,
+        context_instance=RequestContext(request))
+}}}
+
+In *myapp/entry_index.html*:
+
+{{{
+<h2>Entries:</h2>
+{% for object in objects %}
+    {# your code to show the entry #}
+{% endfor %}
+}}}
+
+== 3.3   Split the template ==
+
+A response to an AJAX request should not return the entire template, but only the portion of the page to update or add. So it is convenient to extrapolate from the template the part containing entries and use the new one to render the context if the request is AJAX. The main template will include the other, so it is convenient to put the page template in the context.
+
+*views.py* becomes:
+
+{{{
+def entry_index(request,
+    template="myapp/entry_index.html",
+    page_template="myapp/entry_index_page.html"):
+    context = {
+        'objects': Entry.objects.all(),
+        'page_template': page_template,
+    }
+    if request.is_ajax():
+        template = page_template
+    return render_to_response(template, context,
+        context_instance=RequestContext(request))
+}}}
+
+See below how to obtain the same result just decorating the view(in a way compatible with generic views too).
+
+*myapp/entry_index.html* becomes:
+
+{{{
+<h2>Entries:</h2>
+{% include page_template %}
+}}}
+
+*myapp/entry_index_page.html* becomes:
+
+{{{
+{% for object in objects %}
+    {# your code to show the entry #}
+{% endfor %}
+}}}
+
+== 3.4   A shortcut for ajaxed views ==
+
+A good practice in writing views is to allow other developers to inject the template name and extra data to be added to the context. This allows the view to be easily reused. Let's resume the original view with extra context injection:
+
+*views.py*:
+
+{{{
+def entry_index(request, template="myapp/entry_index.html",
+    extra_context={}):
+    context = {
+        'objects': Entry.objects.all(),
+    }
+    context.upgrade(extra_context)
+    return render_to_response(template, context,
+        context_instance=RequestContext(request))
+}}}
+
+Splitting templates and putting the ajax template name in the context is easily achievable at this point (using a builtin decorator).
+
+*views.py* becomes:
+
+{{{
+from endless_pagination.decorators import page_template
+
+@page_template("myapp/entry_index_page.html") # just add this decorator
+def entry_index(request, template="myapp/entry_index.html",
+    extra_context={}):
+    context = {
+        'objects': Entry.objects.all(),
+    }
+    context.upgrade(extra_context)
+    return render_to_response(template, context,
+        context_instance=RequestContext(request))
+}}}
+
+This way, *endless-pagination* can be included in generic views too.
+
+== 3.5   Pagination ==
+
+Nothing remains but to change the page template, loading endless templatetags and the javascript file *endless.js* included in the distribution under `/media/js/`.
+
+*myapp/entry_index.html* becomes:
+
+{{{
+{% block js %}
+    {{ block.super }}
+    <script src="/path/to/endless.js" type="text/javascript" charset="utf-8"></script>
+{% endblock %}
+
+<h2>Entries:</h2>
+{% include page_template %}
+}}}
+
+*myapp/entry_index_page.html* becomes:
+
+{{{
+{% load endless %}
+
+{% paginate objects %}
+{% for object in objects %}
+    {# your code to show the entry #}
+{% endfor %}
+{% show_more %}
+}}}
+
+That's all. Read the next section of the documentation to improve the use of included templatetags.
+
+== 4   Templatetags reference ==
+
+== 4.1   paginate ==
+
+Usage:
+
+{{{
+{% paginate objects %}
+}}}
+
+After this call, in the template context the *objects* variable is replaced with only the objects of the current page.
+
+You can also mantain your *objects* original variable (commonly a queryset) and add to context another name referring to objects of the current page, e.g.:
+
+{{{
+{% paginate objects as page_objects %}
+}}}
+
+The number of paginated object is taken from settings, but you can override the default, e.g.:
+
+{{{
+{% paginate 20 objects %}
+}}}
+
+Of course you can mix it all:
+
+{{{
+{% paginate 20 objects as paginated_objects %}
+}}}
+
+You must use this tag before calling the `{% show_more %}` one.
+
+== 4.2   show_more ==
+
+Show the link to get the next page in a Twitter-like pagination. Usage:
+
+{{{
+{% show_more %}
+}}}
+
+Must be called after `{% paginate objects %}`.
+
+== 5   Customization ==
+
+You can customize the application using `settings.py`.
+
+ * *ENDLESS_PAGINATION_PER_PAGE* (default=10): How many objects are normally displayed in a page (overwriteable by templatetag).
+
+ * *ENDLESS_PAGINATION_PAGE_LABEL* (default="page"): The querystring key of the page number (e.g. `http://example.com?page=2`)
+
+ * *ENDLESS_PAGINATION_ORPHANS* (default=0): See django *Paginator* definition of orphans.
+
+ * *ENDLESS_PAGINATION_SHOW_MORE_TEMPLATE* (default="endless/show_more.html"): The template used by *show_more* templatetag. You can provide your customized template that must meet the following rules: - *more* link is showed only if variable "querystring" is not False - the container (most external html element) class is *endless_container*- the *more* link and the loader hidden element live inside the container - the *more* link class is *endless_more*- the loader hidden element class is *endless_loading*
+
+ * *ENDLESS_PAGINATION_LOADING* (default="loading"): If you use the default *show_more* template, here you can customize the content of the loader hidden element Html is safe here, e.g. you can show your pretty animated gif:
+
+{{{
+ENDLESS_PAGINATION_LOADING = """
+    <img src="/site_media/img/loader.gif" alt="loading" />
+"""
+}}}
+
+
+
+

endless_pagination/__init__.py

+VERSION = (0, 1)

endless_pagination/decorators.py

+def page_template(template):
+    """
+    Decorate a view that takes a *template* and *extra_context* keyword
+    arguments (like generic views).
+    The template is switched to *page_template* if request is ajax.
+    The name of the page template is given as *page_template* in the
+    extra context.
+    """
+    def decorator(view):
+        # decorator with arguments wrap      
+        def decorated(request, *args, **kwargs):
+            # trust the developer: he wrote context.update(extra_context) in his view
+            extra_context = kwargs.setdefault("extra_context", {})
+            extra_context['page_template'] = template
+            # switch template on ajax requests
+            if request.is_ajax():
+                kwargs['template'] = template
+            return view(request, *args, **kwargs)
+        return decorated
+    return decorator

endless_pagination/endless_pagination

+/Users/frankban/Sviluppo/django-apps-stable/django-endless-pagination/endless_pagination

endless_pagination/exceptions.py

+class PaginationError(Exception): pass
Add a comment to this file

endless_pagination/locale/it/LC_MESSAGES/django.mo

Binary file added.

endless_pagination/locale/it/LC_MESSAGES/django.po

+# Django Endless Pagination Locale
+# Copyright (C) 2009
+# This file is distributed under the same license as the django-endless-pagination package.
+# Francesco Banconi <francesco.banconi@gmail.com>, 2009.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2009-08-22 19:21+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: templates/endless/show_more.html:4
+msgid "more"
+msgstr "mostra altri"

endless_pagination/settings.py

+from django.conf import settings
+
+# How many objects are normally displayed in a page 
+# (overwriteable by templatetag)
+PER_PAGE = getattr(settings, "ENDLESS_PAGINATION_PER_PAGE", 10)
+# The querystring key of the page number.
+PAGE_LABEL = getattr(settings, "ENDLESS_PAGINATION_PAGE_LABEL", "page")
+# See django *Paginator* definition of orphans.
+ORPHANS = getattr(settings, "ENDLESS_PAGINATION_ORPHANS", 0)
+
+# The template used by *show_more* templatetag.
+# You can provide your customized template that must meet the following rules:
+# - *more* link is showed only if variable "querystring" is not False
+# - the container (most external html element) class is *endless_container*
+# - the *more* link and the loader hidden element live inside the container
+# - the *more* link class is *endless_more*
+# - the loader hidden element class is *endless_loading*
+SHOW_MORE_TEMPLATE = getattr(settings, 
+    "ENDLESS_PAGINATION_SHOW_MORE_TEMPLATE", "endless/show_more.html")
+    
+# If you use the default *show_more* template, here you can customize
+# the content of the loader hidden element
+# Html is safe here, e.g. you can show your pretty animated gif:
+#    ENDLESS_PAGINATION_LOADING = """
+#        <img src="/site_media/img/loader.gif" alt="loading" />
+#    """
+LOADING = getattr(settings, 
+    "ENDLESS_PAGINATION_LOADING", "loading")

endless_pagination/templates/endless/show_more.html

+{% load i18n %}
+{% if querystring %}
+    <div class="endless_container">
+        <a class="endless_more" href="{{ path }}{{ querystring }}">{% trans "more" %}</a>
+        <div class="endless_loading" style="display: none;">{{ loading|safe }}</div>
+    </div>
+{% endif %}
Add a comment to this file

endless_pagination/templatetags/__init__.py

Empty file added.

endless_pagination/templatetags/endless.py

+import re
+
+from django import template
+from django.core.paginator import Paginator, EmptyPage
+from django.http import Http404
+
+from endless_pagination import settings, utils
+
+register = template.Library()
+
+@register.tag
+def paginate(parser, token):
+    """
+    Usage::
+    
+        {% paginate objects %}
+    
+    After this call, in the template context the *objects* variable is replaced
+    with only the objects of the current page.
+    
+    You can also mantain your *objects* original variable (commonly a queryset)
+    and add to context another name referring to objects of the current page, 
+    e.g.::
+    
+        {% paginate objects as page_objects %}
+        
+    The number of paginated object is taken from settings, but you can
+    override the default, e.g.::
+    
+        {% paginate 20 objects %}
+        
+    Of course you can mix it all::
+    
+        {% paginate 20 objects as paginated_objects %}
+        
+    You must use this tag before calling the {% show_more %} one.
+    """
+    # args validation
+    try:
+        tag_name, args = token.contents.split(None, 1)
+    except ValueError:
+        message = "%r tag requires arguments" % token.contents.split()[0]
+        raise template.TemplateSyntaxError, message
+        
+    # use regexp to catch args    
+    p = r'^\s*((?P<per_page>\d+)\s+)?(?P<objects>\w+)(\s+as\s+(?P<var_name>\w+))?\s*$'
+    e = re.compile(p)
+    
+    match = e.match(args)
+    if match is None:
+        message = "Invalid arguments for %r tag" % token.contents.split()[0]
+        raise template.TemplateSyntaxError, message
+    
+    # get objects
+    kwargs = match.groupdict()
+    objects = kwargs.pop("objects")
+    
+    # call the node
+    return PaginateNode(objects, **kwargs)
+    
+class PaginateNode(template.Node):
+    """
+    Insert into context the objects of the current page and
+    the django paginator's *page* object.
+    """
+    def __init__(self, objects, per_page=None, var_name=None):
+        self.objects = template.Variable(objects)
+        # if var_name is not passed then will be queryset name
+        self.var_name = objects if var_name is None else var_name
+        # if per_page is not passed then is taken from settings
+        self.per_page = settings.PER_PAGE if per_page is None else int(per_page)
+    
+    def render(self, context):
+        # request is used to get requested page number
+        page_number = utils.get_page_number_from_request(context["request"])
+        
+        objects = self.objects.resolve(context)
+        paginator = Paginator(objects, self.per_page, orphans=settings.ORPHANS)
+        
+        # get the page, user in settings can manage the case it is empty
+        try:
+            page = paginator.page(page_number)
+        except EmptyPage:
+            page = paginator.page(1)
+        
+        # populate context with new data
+        context["endless_page"] = page
+        context[self.var_name] = page.object_list
+        return ""
+
+    
+@register.inclusion_tag(settings.SHOW_MORE_TEMPLATE, takes_context=True)
+def show_more(context):
+    """
+    Show the link to get the next page in a Twitter-like pagination.
+    Usage::
+    
+        {% show_more %}
+        
+    Must be called after {% paginate objects %}.
+    """
+    # this can raise a PaginationError 
+    # (you have to call paginate before including the show more template)
+    page = utils.get_page_from_context(context)
+    # show the template only if there is a next page
+    if page.has_next():
+        request = context["request"]
+        page_number = page.next_page_number()
+        # querystring
+        querystring = utils.get_querystring_for_page(request, page_number)
+        return {
+            'path': request.path,
+            'querystring': querystring,
+            'loading': settings.LOADING,
+        }
+    # no next page, nothing to see
+    return {}

endless_pagination/utils.py

+from endless_pagination.settings import PAGE_LABEL
+from endless_pagination import exceptions
+
+def get_page_number_from_request(request, page_label=PAGE_LABEL):
+    """
+    Get page number from *GET* or *POST* data.
+    If the page dows not exists in *request*, or is not a number
+    then 1 is returned.
+    """
+    try:
+        return int(request.REQUEST[PAGE_LABEL])
+    except (KeyError, TypeError, ValueError):
+        return 1
+        
+def get_page_from_context(context):
+    """
+    Get the django paginator page object from a *context* (a dict like object).
+    If the context key "endless_page" is not found, a PaginationError
+    is raised.
+    """
+    try:
+        return context["endless_page"]
+    except KeyError:
+        raise exceptions.PaginationError("Cannot find endless page in context.")
+
+def get_querystring_for_page(request, page_number, prefix="?"):
+    """
+    Return a querystring pointing to *page_number*.
+    The querystring is prefixed by *prefix* (e.g.: "?page=2").
+    """
+    querydict = request.GET.copy()
+    querydict[PAGE_LABEL] = page_number
+    # for page number 1 there is no need for querystring
+    if page_number == 1:
+        del querydict[PAGE_LABEL]
+    if querydict:
+        return "%s%s" % (prefix, querydict.urlencode())
+    return ""
+        
+    

media/js/endless.js

+$(document).ready(function(){
+    // initializes links for ajax requests
+    $(".endless_more").live("click", function(){
+        var container = $(this).closest(".endless_container");
+        var loading = container.find(".endless_loading");
+        $(this).hide();
+        loading.show();
+        $.get($(this).attr("href"), function(data){
+            container.before(data);
+            container.remove();
+        });
+        return false;
+    });
+});
+from distutils.core import setup
+import os
+
+root_dir = os.path.dirname(__file__)
+if root_dir:
+    os.chdir(root_dir)
+
+data_files = []
+for dirpath, dirnames, filenames in os.walk('endless_pagination'):
+    for i, dirname in enumerate(dirnames):
+        if dirname.startswith('.'): del dirnames[i]
+    if '__init__.py' in filenames:
+        continue
+    elif filenames:
+        for f in filenames:
+            data_files.append(os.path.join(dirpath[len("endless_pagination")+1:], f))
+            
+version = "%s.%s" % __import__('endless_pagination').VERSION[:2]
+
+setup(name='django-endless-pagination',
+    version=version,
+    description='Ajax pagination tools for Django.',
+    author='Francesco Banconi',
+    author_email='francesco.banconi@gmail.com',
+    url='http://code.google.com/p/django-endless-pagination/',
+    package_dir={'endless_pagination': 'endless_pagination'},
+    packages=[
+        'endless_pagination', 
+        'endless_pagination.templatetags',
+    ],
+    package_data={'endless_pagination': data_files},
+    classifiers=[
+        'Development Status :: 5 - Production/Stable',
+        'Environment :: Web Environment',
+        'Framework :: Django',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: MIT License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        'Topic :: Utilities'
+    ],
+)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.