diff --git a/bootstrap_pagination/templates/bootstrap_pagination/pager.html b/bootstrap_pagination/templates/bootstrap_pagination/pager-bs3.html similarity index 79% rename from bootstrap_pagination/templates/bootstrap_pagination/pager.html rename to bootstrap_pagination/templates/bootstrap_pagination/pager-bs3.html index 4fbcf9b..f7e49e4 100644 --- a/bootstrap_pagination/templates/bootstrap_pagination/pager.html +++ b/bootstrap_pagination/templates/bootstrap_pagination/pager-bs3.html @@ -4,7 +4,7 @@ {{ previous_label }} {% else %} -
  • +
  • {{ previous_label }}
  • {% endif %} @@ -14,8 +14,8 @@ {{ next_label }} {% else %} -
  • +
  • {{ next_label }}
  • {% endif %} - + diff --git a/bootstrap_pagination/templates/bootstrap_pagination/pager-bs4.html b/bootstrap_pagination/templates/bootstrap_pagination/pager-bs4.html new file mode 100644 index 0000000..28073fb --- /dev/null +++ b/bootstrap_pagination/templates/bootstrap_pagination/pager-bs4.html @@ -0,0 +1,23 @@ + \ No newline at end of file diff --git a/bootstrap_pagination/templates/bootstrap_pagination/pagination.html b/bootstrap_pagination/templates/bootstrap_pagination/pagination-bs3.html similarity index 100% rename from bootstrap_pagination/templates/bootstrap_pagination/pagination.html rename to bootstrap_pagination/templates/bootstrap_pagination/pagination-bs3.html diff --git a/bootstrap_pagination/templates/bootstrap_pagination/pagination-bs4.html b/bootstrap_pagination/templates/bootstrap_pagination/pagination-bs4.html new file mode 100644 index 0000000..3260525 --- /dev/null +++ b/bootstrap_pagination/templates/bootstrap_pagination/pagination-bs4.html @@ -0,0 +1,76 @@ +{% load bootstrap_pagination %} + diff --git a/bootstrap_pagination/templatetags/bootstrap_pagination.py b/bootstrap_pagination/templatetags/bootstrap_pagination.py index 157db36..49d7255 100755 --- a/bootstrap_pagination/templatetags/bootstrap_pagination.py +++ b/bootstrap_pagination/templatetags/bootstrap_pagination.py @@ -64,6 +64,15 @@ def get_page_url(page_num, current_app, url_view_name, url_extra_args, url_extra return url +def get_bootstrap_version(): + """Helper version to determine the configured version of bootstrap.""" + version = getattr(settings, 'BOOTSTRAP_VERSION', 3) + version = int(version) + + # Clap version between supported versions + return max(3, min(version, 4)) + + class BootstrapPagerNode(Node): def __init__(self, page, kwargs): self.page = page @@ -105,7 +114,9 @@ def render(self, context): if page.has_next(): next_page_url = get_page_url(page.next_page_number(), context.current_app, url_view_name, url_extra_args, url_extra_kwargs, url_param_name, url_get_params, url_anchor) - return get_template("bootstrap_pagination/pager.html").render( + template = "bootstrap_pagination/pager-bs%i.html" % get_bootstrap_version() + + return get_template(template).render( Context({ 'page': page, 'previous_label': previous_label, @@ -220,7 +231,9 @@ def render(self, context): if page.has_next(): next_page_url = get_page_url(page.next_page_number(), context.current_app, url_view_name, url_extra_args, url_extra_kwargs, url_param_name, url_get_params, url_anchor) - return get_template("bootstrap_pagination/pagination.html").render( + template = "bootstrap_pagination/pagination-bs%i.html" % get_bootstrap_version() + + return get_template(template).render( Context({ 'page': page, 'size': size, diff --git a/setup.py b/setup.py index 76d395a..cc4c1b6 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setup( name='django-bootstrap-pagination', - version='1.5.2', + version='1.6.0', keywords="django bootstrap pagination templatetag", author=u'Jason McClellan', author_email='jason@jasonmccllelan.net', @@ -20,9 +20,21 @@ zip_safe=False, include_package_data=True, classifiers=[ - "Development Status :: 3 - Alpha", - "Framework :: Django", + "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", + "Framework :: Django", + "Framework :: Django :: 1.4", + "Framework :: Django :: 1.5", + "Framework :: Django :: 1.6", + "Framework :: Django :: 1.7", + "Framework :: Django :: 1.8", + "Framework :: Django :: 1.9", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.2", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", ] ) diff --git a/tests/test_pager.py b/tests/test_pager.py index 6cb784c..40aff9d 100644 --- a/tests/test_pager.py +++ b/tests/test_pager.py @@ -12,6 +12,8 @@ import django.http from django.core.paginator import Paginator +from tests.utils import override_settings + class PagerTestCase(unittest.TestCase): def test_example(self): @@ -29,3 +31,23 @@ def test_example(self): 'request': django.http.HttpRequest()}) html = lxml.html.fragment_fromstring(template.render(c)) self.assertEqual(html.get('class'), 'pager') + + @override_settings(BOOTSTRAP_VERSION=4) + def test_bs4(self): + template = get_template_from_string(""" + {% load bootstrap_pagination %} + {% bootstrap_pager page_obj %} + """) + + objects = ["obj%02x" % idx + for idx in range(30)] + + paginator = Paginator(objects, 10) + + c = Context({'page_obj': paginator.page(2), + 'request': django.http.HttpRequest()}) + html = lxml.html.fragment_fromstring(template.render(c)) + + self.assertEqual( + html.cssselect('nav>ul.pager>li>a')[0].text.strip(), + 'Previous Page') diff --git a/tests/test_paginate.py b/tests/test_paginate.py index dcdd590..66ae991 100644 --- a/tests/test_paginate.py +++ b/tests/test_paginate.py @@ -12,8 +12,11 @@ import django.http from django.core.paginator import Paginator +from tests.utils import override_settings + class PaginateTestCase(unittest.TestCase): + def test_example(self): template = get_template_from_string(""" {% load bootstrap_pagination %} @@ -32,3 +35,23 @@ def test_example(self): self.assertEqual( html.cssselect('[title=\"Current Page\"]')[0].text.strip(), '2') + + @override_settings(BOOTSTRAP_VERSION=4) + def test_bs4(self): + template = get_template_from_string(""" + {% load bootstrap_pagination %} + {% bootstrap_paginate page_obj range=10 %} + """) + + objects = ["obj%02x" % idx + for idx in range(30)] + + paginator = Paginator(objects, 10) + + c = Context({'page_obj': paginator.page(2), + 'request': django.http.HttpRequest()}) + html = lxml.html.fragment_fromstring(template.render(c)) + + self.assertEqual( + html.cssselect('nav>ul.pagination>li>span[title=\"Current Page\"]')[0].text.strip(), + '2') diff --git a/tests/test_settings.py b/tests/test_settings.py index 968e0ad..82c3dae 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -8,7 +8,12 @@ 'bootstrap_pagination', ) -DATABASES = {} +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': ':memory:', + } +} MIDDLEWARE_CLASSES = () ROOT_URLCONF = 'tests.test_settings.urls' diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 0000000..a256a56 --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,64 @@ +from functools import wraps + +from django.conf import UserSettingsHolder, settings +try: + from django.test.signals import setting_changed +except ImportError: + setting_changed = None + + +# This was taken from django 1.9 django.tests.utils, and adapted to be +# compatible with a wider range of django versions. +class override_settings(object): + """ + Acts as either a decorator, or a context manager. If it's a decorator it + takes a function and returns a wrapped function. If it's a contextmanager + it's used with the ``with`` statement. In either event entering/exiting + are called before and after, respectively, the function/block is executed. + """ + def __init__(self, **kwargs): + self.options = kwargs + + def __enter__(self): + self.enable() + + def __exit__(self, exc_type, exc_value, traceback): + self.disable() + + def __call__(self, test_func): + @wraps(test_func) + def inner(*args, **kwargs): + with self: + return test_func(*args, **kwargs) + return inner + + def save_options(self, test_func): + if test_func._overridden_settings is None: + test_func._overridden_settings = self.options + else: + # Duplicate dict to prevent subclasses from altering their parent. + test_func._overridden_settings = dict( + test_func._overridden_settings, **self.options) + + def enable(self): + # Changing installed apps cannot be done in a backward-compatible way + assert 'INSTALLED_APPS' not in self.options + + override = UserSettingsHolder(settings._wrapped) + for key, new_value in self.options.items(): + setattr(override, key, new_value) + self.wrapped = settings._wrapped + settings._wrapped = override + for key, new_value in self.options.items(): + if setting_changed: + setting_changed.send(sender=settings._wrapped.__class__, + setting=key, value=new_value, enter=True) + + def disable(self): + settings._wrapped = self.wrapped + del self.wrapped + for key in self.options: + new_value = getattr(settings, key, None) + if setting_changed: + setting_changed.send(sender=settings._wrapped.__class__, + setting=key, value=new_value, enter=False)