Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0.2.1 #129

Merged
merged 8 commits into from
Jun 8, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
History
-------

0.2.1 (2024-06-07)
+++++++++++++++++
Important changes

* inactive_class renamed to css_inactive_class.

0.2.0 (2024-06-06)
+++++++++++++++++
Breaking changes

* Update build tools to be using Poetry.
* Dropped support for old Django versions, now officially supporting only: Django 4.0, 4.1, 4.2, 5.0.
Expand Down
29 changes: 21 additions & 8 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ or:

<a href="{% url 'view-name' %}" class="{% active_link 'view-name' css_class='custom-class' %}">Menu item</a>

You can also define an inactive custom css class, that is triggered when a link is deemed not active:

.. code-block:: html

<a href="{% url 'view-name' %}" class="{% active_link 'view-name' 'custom-class' 'not-active' %}">Menu item</a>

or:

.. code-block:: html

<a href="{% url 'view-name' %}" class="{% active_link 'view-name' css_class='custom-class' css_inactive_class='not-active' %}">Menu item</a>

By default ``active_link`` will not perform a strict match. If you want to add the ``active`` class only in case of a strict match pass the ``strict`` argument to the tag:

.. code-block:: html
Expand All @@ -79,14 +91,15 @@ Replace ``view-name`` with the name of your view (including namespaces).

Settings
--------
You can override the default active class and strict mode with the settings ``ACTIVE_LINK_CSS_CLASS`` and ``ACTIVE_LINK_STRICT``.

===================== ==================================================== =============
Key Description Default Value
===================== ==================================================== =============
ACTIVE_LINK_CSS_CLASS Active class to use. `active`
ACTIVE_LINK_STRICT Designates whether to perform a strict match or not. `False`
===================== ==================================================== =============
You can override the default active class and strict mode with the settings ``ACTIVE_LINK_CSS_CLASS``, ``ACTIVE_LINK_CSS_INACTIVE_CLASS`` and ``ACTIVE_LINK_STRICT``.

============================== ==================================================== =============
Key Description Default Value
============================== ==================================================== =============
ACTIVE_LINK_CSS_CLASS Active class to use. `active`
ACTIVE_LINK_CSS_INACTIVE_CLASS Inactive class to use.
ACTIVE_LINK_STRICT Designates whether to perform a strict match or not. `False`
============================== ==================================================== =============

For more usage examples, please check the full documentation at https://django-active-link.readthedocs.io.

Expand Down
22 changes: 15 additions & 7 deletions active_link/templatetags/active_link_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,40 @@

@register.simple_tag(takes_context=True)
def active_link(
context, viewnames, css_class=None, inactive_class="", strict=None, *args, **kwargs
context,
viewnames,
css_class=None,
css_inactive_class="",
strict=None,
*args,
**kwargs
):
"""
Renders the given CSS class if the request path matches the path of the view.
:param context: The context where the tag was called. Used to access the request object.
:param viewnames: The name of the view or views separated by || (include namespaces if any).
:param css_class: The CSS class to render.
:param inactive_class: The CSS class to render if the views is not active.
:param css_inactive_class: The CSS class to render if the views is not active.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a small grammar error here: if the view

:param strict: If True, the tag will perform an exact match with the request path.
:return:
"""
if css_class is None:
css_class = getattr(settings, "ACTIVE_LINK_CSS_CLASS", "active")

if css_inactive_class == "":
css_inactive_class = getattr(settings, "ACTIVE_LINK_CSS_INACTIVE_CLASS", "")

if strict is None:
strict = getattr(settings, "ACTIVE_LINK_STRICT", False)

request = context.get("request")
if request is None:
# Can't work without the request object.
return inactive_class
return css_inactive_class

if request.resolver_match is not None:
if request.resolver_match.kwargs != {}:
# Capture the url kwargs to reverse against
request_kwargs = request.resolver_match.kwargs
kwargs.update(request_kwargs)
kwargs.update(request.resolver_match.kwargs)

active = False
views = viewnames.split("||")
Expand All @@ -54,4 +62,4 @@ def active_link(
if active:
return css_class

return inactive_class
return css_inactive_class
7 changes: 6 additions & 1 deletion docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ To use Django Active Link in a project, add it to your `INSTALLED_APPS`:
...
)

**IMPORTANT**: Django Active Link requires that the current request object is available in your template's context. This means you must be using a `RequestContext` when rendering your template, and `django.core.context_processors.request` must be in your `TEMPLATE_CONTEXT_PROCESSORS` setting. See [the documentation](https://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing-context-requestcontext) for more information.
**IMPORTANT**: Django Active Link requires that the current request object is available in your template's context. This means you must be using a `RequestContext` when rendering your template, and `django.template.context_processors.request` must be in your `TEMPLATE_CONTEXT_PROCESSORS` setting. See [the documentation](https://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing-context-requestcontext) for more information.

To use the `active_link` template tag you need to load `active_link_tags` templatetags library:

Expand All @@ -30,4 +30,9 @@ You can also match views that take arguments. For example:

<a href="{% url 'view-name' %}" class="{% active_link 'view-name-with-args' pk=12 slug='simple-slug' %}">Menu item</a>

You can also define an inactive custom css class, that is triggered when a link is deemed not active:

.. code-block:: html
<a href="{% url 'view-name' %}" class="{% active_link 'view-name' 'custom-class' 'not-active' %}">Menu item</a>

Replace `view-name` with the name of your view (including namespaces).
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "django-active-link"
version = "0.2.0"
version = "0.2.1"
description = "The best and simplest way to highlight active links in your Django app."
license = "BSD-3-Clause"
authors = [
Expand Down
14 changes: 14 additions & 0 deletions tests/templates/detailed_action_kwargs_not_active.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{% load active_link_tags %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple test</title>
</head>
<body>
<div class="{% active_link 'detailed-action' css_inactive_class='not-active' %}">

</div>
</body>
</html>
2 changes: 1 addition & 1 deletion tests/templates/simple.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<title>Simple test</title>
</head>
<body>
<div class="{% active_link 'simple' %}">
<div class="{% active_link 'simple' css_inactive_class='not-active' %}">

</div>
</body>
Expand Down
23 changes: 17 additions & 6 deletions tests/test_tags.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from django.template import Context, Template
from django.template.loader import render_to_string
from django.test import Client, TestCase, override_settings
from django.urls import reverse

Expand All @@ -17,10 +17,12 @@ def reverse_helper(self, reverse_url_string, kwargs=None):
return content

def test_no_request(self):
template = Template("simple.html")
context = Context({"request": None})
html = template.render(context)
self.assertNotIn("active", html)
html = render_to_string("simple.html")
self.assertNotIn('<div class="active">', html)

def test_no_request_inactive_class(self):
html = render_to_string("simple.html")
self.assertInHTML('<div class="not-active">', html)

def test_match_defaults(self):
content = self.reverse_helper("simple")
Expand All @@ -39,10 +41,15 @@ def test_custom_class(self):
self.assertInHTML('<div class="my-active-class">', content)

@override_settings(ACTIVE_LINK_CSS_CLASS="my-active-class")
def test_settings_css_class(self):
def test_settings_css_active_class(self):
content = self.reverse_helper("simple")
self.assertInHTML('<div class="my-active-class">', content)

@override_settings(ACTIVE_LINK_CSS_INACTIVE_CLASS="my-not-active-class")
def test_settings_css_not_active_class(self):
content = self.reverse_helper("simple-strict-no-match")
self.assertInHTML('<div class="my-not-active-class">', content)

@override_settings(ACTIVE_LINK_STRICT=True)
def test_settings_strict(self):
content = self.reverse_helper("simple-settings-strict")
Expand All @@ -55,3 +62,7 @@ def test_match_url_with_kwargs(self):
def test_match_url_with_kwargs_with_multiple(self):
content = self.reverse_helper("detailed-action-multiple", {"pk": 12})
self.assertInHTML('<div class="active">', content)

def test_match_url_with_kwargs_with_multiple_not_active(self):
content = self.reverse_helper("detailed-action-not-active", {"pk": 12})
self.assertInHTML('<div class="not-active">', content)
5 changes: 5 additions & 0 deletions tests/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
TemplateView.as_view(template_name="detailed_action_kwargs.html"),
name="detailed-action",
),
path(
r"detailed/action/not-active/<int:pk>/",
TemplateView.as_view(template_name="detailed_action_kwargs_not_active.html"),
name="detailed-action-not-active",
),
path(
r"detailed/action/multiple/<int:pk>/",
TemplateView.as_view(template_name="detailed_action_kwargs_multiple.html"),
Expand Down
Loading