Skip to content

Commit

Permalink
Merge pull request #32 from krejcar25/tabular-inline-template
Browse files Browse the repository at this point in the history
Tabular inline template
  • Loading branch information
d-demirci authored Mar 28, 2024
2 parents 36a2391 + f004263 commit 1d27a04
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 3 deletions.
4 changes: 4 additions & 0 deletions adminlte3_theme/static/admin/css/forms.css
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ label {
color: #333;
}

.custom-file label {
font-size: 16px;
}

/* RADIO BUTTONS */

form ul.radiolist li {
Expand Down
120 changes: 120 additions & 0 deletions adminlte3_theme/templates/admin/edit_inline/tabular.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
{% load i18n admin_urls static admin_modify bootstrap_forms %}
<div class="card card-primary" id="{{ inline_admin_formset.formset.prefix }}-group" data-inline-type="tabular" data-inline-formset="{{ inline_admin_formset.inline_formset_data }}">
{{ inline_admin_formset.formset.management_form }}
<div class="card-header">
<h2 class="card-title">
{% if inline_admin_formset.formset.max_num == 1 %}
{{ inline_admin_formset.opts.verbose_name|capfirst }}
{% else %}
{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}
{% endif %}
</h2>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-card-widget="collapse"><i class="fas fa-minus"></i></button>
</div>
</div>
<div class="card-body p-0">
{{ inline_admin_formset.formset.non_form_errors }}
<table class="table table-striped">
<thead>
<tr>
<td class="original" style="padding: 2px 0 0 0; width: 0; _position: relative;"></td>
{% for field in inline_admin_formset.fields %}
{% if not field.widget.is_hidden %}
<th class="column-{{ field.name }}{% if field.required %} required{% endif %}">
{{ field.label|capfirst }}
{% if field.help_text %}
<img src="{% static "admin/img/icon-unknown.svg" %}" class="help help-tooltip" width="10" height="10" alt="({{ field.help_text|striptags }})" title="{{ field.help_text|striptags }}"/>
{% endif %}
</th>
{% endif %}
{% endfor %}
{% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission %}
<th>{% translate "Delete?" %}</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for inline_admin_form in inline_admin_formset %}
{% if inline_admin_form.form.non_field_errors %}
<tr class="row-form-errors">
<td colspan="{{ inline_admin_form|cell_count }}">{{ inline_admin_form.form.non_field_errors }}
</td>
</tr>
{% endif %}
<tr class="{% if inline_admin_form.original or inline_admin_form.show_url %}has_original{% endif %}{% if forloop.last and inline_admin_formset.has_add_permission %} empty-form{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-{% if not forloop.last %}{{ forloop.counter0 }}{% else %}empty{% endif %}">
<td class="original" style="padding: 2px 0 0 0; width: 0; _position: relative;">
{% if inline_admin_form.original or inline_admin_form.show_url %}
<p style="position: absolute; left: 0; height: 1.5em; padding: 2px 9px; overflow: hidden; font-size: 9px; font-weight: bold; _width: 700px;">
{% if inline_admin_form.original %}
{{ inline_admin_form.original }}
{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %}
<a href="{% url inline_admin_form.model_admin.opts|admin_urlname:'change' inline_admin_form.original.pk|admin_urlquote %}" class="{% if inline_admin_formset.has_change_permission %}inlinechangelink{% else %}inlineviewlink{% endif %}">
{% if inline_admin_formset.has_change_permission %}
{% translate "Change" %}
{% else %}
{% translate "View" %}
{% endif %}
</a>
{% endif %}
{% endif %}
{% if inline_admin_form.show_url %}
<a href="{{ inline_admin_form.absolute_url }}">{% translate "View on site" %}</a>
{% endif %}
</p>
{% endif %}
{% if inline_admin_form.needs_explicit_pk_field %}
{{ inline_admin_form.pk_field.field|bootstrap_input }}
{% endif %}
{% if inline_admin_form.fk_field %}
{{ inline_admin_form.fk_field.field|bootstrap_input }}
{% endif %}
{% spaceless %}
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
{% if not field.is_readonly and field.field.is_hidden %}
{{ field.field }}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endspaceless %}
</td>
{% for fieldset in inline_admin_form %}
{% for line in fieldset %}
{% for field in line %}
{% if field.is_readonly or not field.field.is_hidden %}
<td {% if field.field.name %} class="field-{{ field.field.name }}" {% endif %} style="padding-top: 2em;">
{% if field.is_readonly %}
<p>{{ field.contents }}</p>
{% else %}
<div class="input-group">
{{ field.field|bootstrap_input }}
{% if field.field.errors %}
<div class="invalid-feedback">
{{ field.field.errors.as_ul }}
</div>
{% endif %}
</div>
{% endif %}
</td>
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission %}
<td class="delete" style="padding-top: 2em;">
{% if inline_admin_form.original %}
<div class="input-group">
{{ inline_admin_form.deletion_field.field|bootstrap_input }}
</div>
{% endif %}
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
7 changes: 4 additions & 3 deletions adminlte3_theme/templates/admin/includes/fieldset.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{% load bootstrap_forms %}
<div class="card card-info">
<div class="card-header bg-primary">
<h3 class="card-title">{% if fieldset.name %}{{ fieldset.name }}{% endif %}</h3>
Expand All @@ -18,13 +19,13 @@ <h3 class="card-title">{% if fieldset.name %}{{ fieldset.name }}{% endif %}</h3>
<label for="{{field.field.name}}" class="col-sm-2 col-form-label">{{ field.label_tag }}</label>
<div class="col-sm-10">
{% if field.is_checkbox %}
{{ field.field }}
{{ field.field|bootstrap_input }}
{% else %}

{% if field.is_readonly %}
<div class="readonly">{{ field.contents }}</div>
{% else %}
{{ field.field }}
{{ field.field|bootstrap_input }}
{% endif %}
{% endif %}
{% if field.field.help_text %}
Expand All @@ -37,4 +38,4 @@ <h3 class="card-title">{% if fieldset.name %}{{ fieldset.name }}{% endif %}</h3>
</div>
{% endfor %}
</div>
</div>
</div>
12 changes: 12 additions & 0 deletions adminlte3_theme/templates/admin/widgets/clearable_file_input.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% if widget.is_initial %}<p class="file-upload">{{ widget.initial_text }}: <a href="{{ widget.value.url }}">{{ widget.value }}</a>{% if not widget.required %}
<span class="clearable-file-input">
<input type="checkbox" name="{{ widget.checkbox_name }}" id="{{ widget.checkbox_id }}"{% if widget.attrs.disabled %} disabled{% endif %}>
<label for="{{ widget.checkbox_id }}">{{ widget.clear_checkbox_label }}</label></span>{% endif %}<br>
{{ widget.input_text }}:{% endif %}
<div class="input-group">
<div class="custom-file">
<input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}>
<label class="custom-file-label" for="{{ widget.attrs.id }}">Choose file</label>
</div>
</div>
{% if widget.is_initial %}</p>{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{% load i18n static %}
<div class="input-group">
{{ rendered_widget }}
{% block links %}
{% spaceless %}
{% if not is_hidden %}
{% if can_change_related %}
<div class="input-group-append">
<a class="change-related btn btn-outline-warning d-flex flex-row align-items-center" id="change_id_{{ name }}" data-href-template="{{ change_related_template_url }}?{{ url_params }}" title="{% blocktranslate %}Change selected {{ model }}{% endblocktranslate %}">
<i class="fas fa-edit"></i>
</a>
</div>
{% endif %}
{% if can_add_related %}
<div class="input-group-append">
<a class="add-related btn btn-outline-success d-flex flex-row align-items-center" id="add_id_{{ name }}" href="{{ add_related_url }}?{{ url_params }}" title="{% blocktranslate %}Add another {{ model }}{% endblocktranslate %}">
<i class="fas fa-plus"></i>
</a>
</div>
{% endif %}
{% if can_delete_related %}
<div class="input-group-append">
<a class="delete-related btn btn-outline-danger d-flex flex-row align-items-center" id="delete_id_{{ name }}" data-href-template="{{ delete_related_template_url }}?{{ url_params }}" title="{% blocktranslate %}Delete selected {{ model }}{% endblocktranslate %}">
<i class="fas fa-times"></i>
</a>
</div>
{% endif %}
{% endif %}
{% endspaceless %}
{% endblock %}
</div>
43 changes: 43 additions & 0 deletions adminlte3_theme/templatetags/bootstrap_forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from django.contrib.admin.widgets import RelatedFieldWidgetWrapper, AdminSplitDateTime, AdminFileWidget
from django.template import Library
from django.utils.safestring import mark_safe

register = Library()


@register.filter(is_safe=True)
def bootstrap_input(value):
"""Adds appropriate bootstrap CSS classes to widgets so that they are rendered bootstrap-ish"""
current_classes = value.field.widget.attrs.get("class", "").strip().split(" ")
field_type = value.field.widget.attrs.get("type", "text")

print(type(value.field.widget))

if field_type == "range":
bootstrap_class = "form-control-range"
elif field_type == "checkbox" or field_type == "radio":
bootstrap_class = "form-check-input"
elif field_type == "file":
bootstrap_class = "custom-file-input"
elif isinstance(value.field.widget, RelatedFieldWidgetWrapper):
bootstrap_class = "custom-select" # For wrapped widgets (those with edit, add and delete icons)
elif isinstance(value.field.widget, AdminFileWidget):
bootstrap_class = "custom-file-input"
elif isinstance(value.field.widget, AdminSplitDateTime):
return value # We don't want to style the date time field (for now)
else:
bootstrap_class = "form-control"

# We always have a list. This checks if first item contains something (list is not [''], meaning the attribute
# contained something) and then adds the bootstrap_class if it is not already there. If the list is "empty" then we create
# a new one that contains only the bootstrap_class we want.
if current_classes[0] and bootstrap_class not in current_classes:
current_classes.append(bootstrap_class)
else:
current_classes = [bootstrap_class]

# Also add the is-invalid class to render the field with a red border if there are any errors.
if value.errors:
current_classes.append("is-invalid")

return value.as_widget(attrs={"class": " ".join(current_classes)})

0 comments on commit 1d27a04

Please sign in to comment.