Skip to content

Commit

Permalink
Fixing the #9 by ensuring the DateTimeShortcuts.js is loaded exactly …
Browse files Browse the repository at this point in the history
…once (#11)
  • Loading branch information
marcinowski authored and silentsokolov committed Apr 9, 2018
1 parent e45ec65 commit 9e6c189
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 4 deletions.
19 changes: 17 additions & 2 deletions rangefilter/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from django.utils.html import format_html
from django.utils import timezone
from django.template.defaultfilters import slugify
from django.templatetags.static import StaticNode
from django.utils.translation import ugettext as _
from django.contrib.admin.widgets import AdminDateWidget, AdminSplitDateTime as BaseAdminSplitDateTime

Expand All @@ -35,7 +36,7 @@ def __init__(self, field, request, params, model, model_admin, field_path):
self.lookup_kwarg_lte = '{}__lte'.format(field_path)

super(DateRangeFilter, self).__init__(field, request, params, model, model_admin, field_path)

self.request = request
self.form = self.get_form(request)

def get_timezone(self, request):
Expand Down Expand Up @@ -112,7 +113,14 @@ def _get_form_class(self):
{'base_fields': fields}
)
form_class.media = self._get_media()

# lines below ensure that the js static files are loaded just once
# even if there is more than one DateRangeFilter in use
request_key = 'DJANGO_RANGEFILTER_ADMIN_JS_SET'
if (getattr(self.request, request_key, False)):
form_class.js = []
else:
setattr(self.request, request_key, True)
form_class.js = self.get_js()
return form_class

def _get_form_fields(self):
Expand All @@ -131,6 +139,13 @@ def _get_form_fields(self):
)),
))

@staticmethod
def get_js():
return [
StaticNode.handle_simple('admin/js/calendar.js'),
StaticNode.handle_simple('admin/js/admin/DateTimeShortcuts.js'),
]

@staticmethod
def _get_media():
js = [
Expand Down
37 changes: 36 additions & 1 deletion rangefilter/templates/rangefilter/date_filter.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% load i18n admin_static %}
<h3>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %}</h3>
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/widgets.css' %}">
<style>
.button, input[type=reset] {
background: #79aec8;
Expand Down Expand Up @@ -68,9 +69,43 @@ <h3>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktr
window.location = window.location.pathname + query_string;
}
</script>
<script>
// Code below makes sure that the DateTimeShortcuts.js is loaded exactly once
// regardless the presence of AdminDateWidget
// How it worked:
// - First Django loads the model formset with predefined widgets for different
// field types. If there's a date based field, then it loads the AdminDateWidget
// and it's required media to context under {{media.js}} in admin/change_list.html.
// (Note: it accumulates media in django.forms.widgets.Media object,
// which prevents duplicates, but the DateRangeFilter is not included yet
// since it's not model field related.
// List of predefined widgets is in django.contrib.admin.options.FORMFIELD_FOR_DBFIELD_DEFAULTS)
// - After that Django starts rendering forms, which have the {{form.media}}
// tag. Only then the DjangoRangeFilter.get_media is called and rendered,
// which creates the duplicates.
// How it works:
// - first step is the same, if there's a AdminDateWidget to be loaded then
// nothing changes
// - DOM gets rendered and if the AdminDateWidget was rendered then
// the DateTimeShortcuts.js is initiated which sets the window.DateTimeShortcuts.
// Otherwise, the window.DateTimeShortcuts is undefined.
// - The lines below check if the DateTimeShortcuts has been set and if not
// then the DateTimeShortcuts.js and calendar.js is rendered
//
// https://github.com/silentsokolov/django-admin-rangefilter/issues/9
//
django.jQuery('document').ready(function () {
if (!('DateTimeShortcuts' in window)) {
{% for m in spec.form.js %}
var script = document.createElement('script');
script.src = '{{m}}';
document.head.appendChild(script);
{% endfor %}
}
})
</script>
<div class="admindatefilter">
<form method="GET" action="." id="{{ choices.0.system_name }}-form">
{{ spec.form.media }}
{{ spec.form.as_p }}
{% for choice in choices %}
<input type="hidden" id="{{ choice.system_name }}-query-string" value="{{ choice.query_string }}">
Expand Down
13 changes: 12 additions & 1 deletion rangefilter/templates/rangefilter/date_filter_1_8.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{% load i18n admin_static %}
<h3>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %}</h3>
<link rel="stylesheet" type="text/css" href="{% static 'admin/css/widgets.css' %}">
<style>
.button, input[type=reset] {
padding: 3px 5px;
Expand Down Expand Up @@ -67,9 +68,19 @@ <h3>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktr
window.location = window.location.pathname + query_string;
}
</script>
<script>
django.jQuery('document').ready(function () {
if (!('DateTimeShortcuts' in window)) {
{% for m in spec.form.js %}
var script = document.createElement('script');
script.src = '{{m}}';
document.head.appendChild(script);
{% endfor %}
}
})
</script>
<div class="admindatefilter">
<form method="GET" action="." id="{{ choices.0.system_name }}-form">
{{ spec.form.media }}
{{ spec.form }}
{% for choice in choices %}
<input type="hidden" id="{{ choice.system_name }}-query-string" value="{{ choice.query_string }}">
Expand Down

0 comments on commit 9e6c189

Please sign in to comment.