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

Ps/frontend fixes #177

Draft
wants to merge 7 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
40 changes: 23 additions & 17 deletions advanced_filters/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from django.db.models.fields import DateField
from django.forms.formsets import formset_factory, BaseFormSet
from functools import reduce
from django.utils.functional import cached_property
from django.utils.text import capfirst
from django.utils.translation import gettext_lazy as _

Expand All @@ -25,8 +26,8 @@
logger = logging.getLogger('advanced_filters.forms')

# select2 location can be modified via settings
SELECT2_JS = getattr(settings, 'SELECT2_JS', 'select2/select2.min.js')
SELECT2_CSS = getattr(settings, 'SELECT2_CSS', 'select2/select2.min.css')
SELECT2_JS = getattr(settings, 'SELECT2_JS', 'admin/js/vendor/select2/select2.full.min.js')
SELECT2_CSS = getattr(settings, 'SELECT2_CSS', 'admin/css/vendor/select2/select2.min.css')


def date_to_string(timestamp):
Expand Down Expand Up @@ -62,7 +63,7 @@ class AdvancedFilterQueryForm(CleanWhiteSpacesMixin, forms.Form):
label=_('Operator'),
required=True, choices=OPERATORS, initial="iexact",
widget=forms.Select(attrs={'class': 'query-operator'}))
value = VaryingTypeCharField(required=True, widget=forms.TextInput(
value = VaryingTypeCharField(required=True, widget=forms.Select(
attrs={'class': 'query-value'}), label=_('Value'))
value_from = forms.DateTimeField(widget=forms.HiddenInput(
attrs={'class': 'query-dt-from'}), required=False)
Expand Down Expand Up @@ -199,6 +200,14 @@ def get_form_kwargs(self, index):
kwargs['model_fields'] = self.model_fields
return kwargs

@cached_property
def forms(self):
"""Instantiate forms at first property access."""
forms = super().forms
if self.extra > 0 and not self.data:
forms += [self.empty_form]
return forms


AFQFormSet = formset_factory(
AdvancedFilterQueryForm, formset=AdvancedFilterFormSet,
Expand All @@ -219,11 +228,12 @@ class Media:
required_js = [
'admin/js/vendor/jquery/jquery.min.js',
'advanced-filters/jquery_adder.js',
'orig_inlines%s.js' % ('' if settings.DEBUG else '.min'),
SELECT2_JS,
'magnific-popup/jquery.magnific-popup.js',
'admin/js/inlines.js',
'advanced-filters/advanced-filters.js',
]
js = required_js + [SELECT2_JS]
js = required_js
css = {'screen': [
SELECT2_CSS,
'advanced-filters/advanced-filters.css',
Expand Down Expand Up @@ -289,23 +299,18 @@ def __init__(self, *args, **kwargs):

def clean(self):
cleaned_data = super().clean()
if not self.fields_formset.is_valid():
logger.debug(
"Errors validating advanced query filters: %s",
pformat([(f.errors, f.non_field_errors())
for f in self.fields_formset.forms]))
raise forms.ValidationError("Error validating filter forms")
cleaned_data['model'] = "{}.{}".format(self._model._meta.app_label,
self._model._meta.object_name)
return cleaned_data

@property
def _non_deleted_forms(self):
forms = []
for form in self.fields_formset.forms:
if form in self.fields_formset.deleted_forms:
continue # skip deleted forms when generating query
forms.append(form)
if self.fields_formset.is_valid():
for form in self.fields_formset.forms:
if form in self.fields_formset.deleted_forms:
continue # skip deleted forms when generating query
forms.append(form)
return forms

def generate_query(self):
Expand Down Expand Up @@ -345,6 +350,7 @@ def initialize_form(self, instance, model, data=None, extra=None):
)

def save(self, commit=True):
self.instance.query = self.generate_query()
self.instance.model = self.cleaned_data.get('model')
if self.is_valid():
self.instance.query = self.generate_query()
self.instance.model = self.cleaned_data.get('model')
return super().save(commit)
70 changes: 51 additions & 19 deletions advanced_filters/static/advanced-filters/advanced-filters.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const $ = django.jQuery;
var _af_handlers = window._af_handlers || null;
var OperatorHandlers = function($) {
var self = this;
self.value = null;
self.val_input = null;
self.selected_field_elm = null;

Expand Down Expand Up @@ -53,27 +53,61 @@

self.modify_widget = function(elm) {
// pick a widget for the value field according to operator
self.value = $(elm).val();
self.val_input = $(elm).parents('tr').find('.query-value');
console.log("selected operator: " + self.value);
if (self.value == "range") {
let op = $(elm);
let op_value = $(elm).val();
let row = $(elm).parents('tr');
self.val_input = row.find('select.query-value');

console.log("selected operator: " + op_value);
if (op_value == "range") {
self.add_datepickers();
} else {
self.remove_datepickers();

if (op_value == "isnull") {
self.val_input.select2("destroy");

self.val_input.val("null").prop("disabled", true);
self.val_input.after(
'<input type="hidden" value="' + self.val_input.val() +
'" name="' + self.val_input.attr("name") + '">'
);
} else {
self.initialize_select2(row.find("select.query-field").first());

op.prop("disabled", false);
op.siblings('input[type="hidden"]').remove();
self.val_input.prop("disabled", false);
self.val_input.siblings('input[type="hidden"]').remove();

}
}
};

self.destroy_select2 = function(elm) {
if (elm.hasClass("select2-hidden-accessible")) {
elm.select2("destroy");
// options added from the backend need to be removed
elm.find("option").remove();
}
}

Check notice

Code scanning / CodeQL

Semicolon insertion Note

Avoid automated semicolon insertion (90% of all statements in
the enclosing function
have an explicit semicolon).

self.initialize_select2 = function(elm) {
// initialize select2 widget and populate field choices
var field = $(elm).val();
var choices_url = ADVANCED_FILTER_CHOICES_LOOKUP_URL + (FORM_MODEL ||
MODEL_LABEL) + '/' + field;
var input = $(elm).parents('tr').find('input.query-value');
input.select2("destroy");
var select = $(elm).parents('tr').find('select.query-value');
self.destroy_select2(select);
$.get(choices_url, function(data) {
input.select2({'data': data, 'createSearchChoice': function(term) {
return { 'id': term, 'text': term };
}});
const initialData = data.results.map(function(tag, index) {
let tag_id = typeof(tag.id) === "string" ? tag.id : tag.id + "";
return {id: tag_id, text: tag.text.toString()};
})
select.select2({
data: initialData,
tags: true,
});
});
};

Expand All @@ -94,9 +128,10 @@
op.siblings('input[type="hidden"]').remove();
value.prop("disabled", false);
value.siblings('input[type="hidden"]').remove();
if (!value.val() == "null") {
value.val("");
}
// DEPRECATED: Does this do anything?
// if (!value.val() == "null") {
// value.val("");
// }
op.val("iexact").change();
self.initialize_select2(elm);
}
Expand Down Expand Up @@ -127,8 +162,6 @@
$(this).data('pre_change', $(this).val());
}).change();
});
self.field_selected($('.form-row select.query-field').first());

};

self.destroy = function() {
Expand All @@ -138,13 +171,12 @@
$('.form-row select.query-field').each(function() {
$(this).off("change");
});
$('.form-row input.query-value').each(function() {
$(this).select2("destroy");
$('.form-row select.query-value').each(function() {
self.destroy_select2($(this));
});
};
};

// using Grappelli's jquery if available
(function($) {
$(document).ready(function() {
if (!_af_handlers) {
Expand All @@ -153,4 +185,4 @@
_af_handlers.init();
}
});
})(window._jq || jQuery);
})(django.jQuery);
5 changes: 3 additions & 2 deletions advanced_filters/static/advanced-filters/jquery_adder.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
(function($) {
if (!window.jQuery) window.jQuery = $;
})(window._jq || jQuery || grp.jQuery);
// overwrite whatever is set in global, to use in Magnific popup
window.jQuery = $
})(django.jQuery);
1,862 changes: 1,859 additions & 3 deletions advanced_filters/static/magnific-popup/jquery.magnific-popup.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading
Loading