-
-
Notifications
You must be signed in to change notification settings - Fork 193
Tabbed changeform #211
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
Tabbed changeform #211
Changes from 19 commits
4d10e0b
d610dd2
5abb1e4
4c5b829
d2c488d
5a4231c
f0af446
8d55d39
a81e08a
39f7067
e94a322
102171c
0e04ddb
a4c32d8
f9c6154
0686c1e
2cd5181
9e0a410
5171d9e
0e71a30
4df8f05
c6e6200
18e63db
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Generated by Django 4.1.3 on 2022-11-23 11:01 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("admin_interface", "0027_theme_list_filter_removal_links"), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name="theme", | ||
name="show_fieldsets_as_tabs", | ||
field=models.BooleanField(default=False, verbose_name="fieldsets as tabs"), | ||
), | ||
migrations.AddField( | ||
model_name="theme", | ||
name="show_inlines_as_tabs", | ||
field=models.BooleanField(default=True, verbose_name="inlines as tabs"), | ||
), | ||
] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
.admin-interface .tabbed-changeform-tab { | ||
display: flex; | ||
flex-direction: row; | ||
gap: 0.75em; | ||
flex-wrap: wrap; | ||
} | ||
|
||
.admin-interface .tabbed-changeform-tab button { | ||
border: none; | ||
cursor: pointer; | ||
padding: 8px 12px; | ||
transition: 0.3s; | ||
border-radius: var(--admin-interface-module-border-radius); | ||
} | ||
|
||
.admin-interface .tabbed-changeform-tab button.active { | ||
background-color: var(--admin-interface-module-background-color); | ||
color: var(--admin-interface-module-text-color); | ||
} | ||
|
||
.admin-interface .tabbed-changeform-tabcontent { | ||
display: none; | ||
padding: 1em 0; | ||
} | ||
|
||
.admin-interface .tabbed-changeform-tabcontent.active { | ||
display: block; | ||
} | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
|
||
function openTab(evt, tabName) { | ||
var tabcontents, tablinks; | ||
tabcontents = document.getElementsByClassName("tabbed-changeform-tabcontent"); | ||
for (let tabcontent of tabcontents) { | ||
tabcontent.classList.remove("active"); | ||
} | ||
tablinks = document.getElementsByClassName("tabbed-changeform-tablinks"); | ||
for (let tablink of tablinks) { | ||
tablink.classList.remove("active"); | ||
} | ||
document.getElementById(tabName).classList.add("active"); | ||
evt.currentTarget.classList.add("active"); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -114,7 +114,8 @@ | |
href="{% static 'admin_interface/css/import-export.css' %}?v={{ version_md5_cache }}"/> | ||
<link rel="stylesheet" type="text/css" | ||
href="{% static 'admin_interface/css/rtl.css' %}?v={{ version_md5_cache }}"/> | ||
|
||
<link rel="stylesheet" type="text/css" | ||
href="{% static 'admin_interface/css/tabbed-changeform.css' %}?v={{ version_md5_cache }}"> | ||
|
||
{% if current_lang == 'fa' %} | ||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/rastikerdar/[email protected]/dist/font-face.css" /> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
{% extends "admin/change_form.html" %} | ||
{% load static admin_interface_tags %} | ||
|
||
|
||
{% block field_sets %} | ||
|
||
{% get_admin_interface_setting "show_fieldsets_as_tabs" as show_fieldsets_as_tabs %} | ||
{% get_admin_interface_setting "show_inlines_as_tabs" as show_inlines_as_tabs %} | ||
|
||
{% if not show_fieldsets_as_tabs and not show_inlines_as_tabs %} | ||
|
||
fabiocaccamo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{{block.super}} | ||
|
||
{% else %} | ||
|
||
<div class="tabbed-changeform-tab"> | ||
|
||
{% if show_fieldsets_as_tabs %} | ||
{% for fieldset in adminform %} | ||
<button type="button" class="tabbed-changeform-tablinks {{ forloop.counter0|default:"active" }}" onclick="openTab(event, '{{fieldset.name}}')"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any appetite for making the tabs work purely with CSS? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoiding JavaScript at all for this feature would be great! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find that using JS is the most readable way to handle the logic. Most CSS-only solutions I've come across are not easy to implement to be responsive and handle a dynamic no of tabs 😓 You're welcome to change it up though. 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally I have not any experience with CSS only tabs, I can't evaluate implementation complexity. |
||
{{ fieldset.name|default_if_none:opts.verbose_name|capfirst}} | ||
</button> | ||
{% endfor %} | ||
{% else %} | ||
<button type="button" class="tabbed-changeform-tablinks active" onclick="openTab(event, 'general')"> | ||
{{ opts.verbose_name|capfirst }} | ||
</button> | ||
{% endif %} | ||
|
||
{% if show_inlines_as_tabs %} | ||
{% for inline_admin_formset in inline_admin_formsets %} | ||
<button type="button" class="tabbed-changeform-tablinks" onclick="openTab(event, '{{inline_admin_formset.opts.verbose_name_plural|capfirst}}')"> | ||
{{inline_admin_formset.opts.verbose_name_plural|capfirst}} | ||
</button> | ||
{% endfor %} | ||
{% endif %} | ||
</div> | ||
|
||
{% if show_fieldsets_as_tabs %} | ||
{% for fieldset in adminform %} | ||
<div id="{{fieldset.name}}" class="tabbed-changeform-tabcontent {{ forloop.counter0|default:"active" }}"> | ||
{% include "admin/includes/headerless_fieldset.html" %} | ||
</div> | ||
{% endfor %} | ||
{% else %} | ||
<div id="general" class="tabbed-changeform-tabcontent active"> | ||
{% for fieldset in adminform %} | ||
{% include "admin/includes/fieldset.html" %} | ||
{% endfor %} | ||
</div> | ||
{% endif %} | ||
|
||
{% for inline_admin_formset in inline_admin_formsets %} | ||
<div id="{{inline_admin_formset.opts.verbose_name_plural|capfirst}}" class="tabbed-changeform-tabcontent"> | ||
{% get_admin_interface_inline_template inline_admin_formset.opts.template as inline_template %} | ||
{% include inline_template %} | ||
</div> | ||
{% endfor %} | ||
<script | ||
type="text/javascript" | ||
id="tabbed-changeform-script" | ||
src="{% static "admin_interface/js/tabbed_changeform.js" %}" | ||
> | ||
</script> | ||
{% endif %} | ||
{% endblock %} | ||
|
||
{% block inline_field_sets %} | ||
fabiocaccamo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{% get_admin_interface_setting "show_inlines_as_tabs" as show_inlines_as_tabs %} | ||
{% if not show_inlines_as_tabs %} | ||
{{block.super}} | ||
{% endif %} | ||
{% endblock %} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{% load i18n admin_urls %} | ||
<div class="js-inline-admin-formset inline-group" | ||
id="{{ inline_admin_formset.formset.prefix }}-group" | ||
data-inline-type="stacked" | ||
data-inline-formset="{{ inline_admin_formset.inline_formset_data }}"> | ||
<fieldset class="module {{ inline_admin_formset.classes }}"> | ||
{{ inline_admin_formset.formset.management_form }} | ||
{{ inline_admin_formset.formset.non_form_errors }} | ||
|
||
{% for inline_admin_form in inline_admin_formset %}<div class="inline-related{% 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 last-related{% endif %}" id="{{ inline_admin_formset.formset.prefix }}-{% if forloop.last and inline_admin_formset.has_add_permission %}empty{% else %}{{ forloop.counter0 }}{% endif %}"> | ||
<h3><b>{{ inline_admin_formset.opts.verbose_name|capfirst }}:</b> <span class="inline_label">{% 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="{{ inline_admin_formset.has_change_permission|yesno:'inlinechangelink,inlineviewlink' }}">{% if inline_admin_formset.has_change_permission %}{% translate "Change" %}{% else %}{% translate "View" %}{% endif %}</a>{% endif %} | ||
{% else %}#{{ forloop.counter }}{% endif %}</span> | ||
{% if inline_admin_form.show_url %}<a href="{{ inline_admin_form.absolute_url }}">{% translate "View on site" %}</a>{% endif %} | ||
{% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission and inline_admin_form.original %}<span class="delete">{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}</span>{% endif %} | ||
</h3> | ||
{% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %} | ||
{% for fieldset in inline_admin_form %} | ||
{% include "admin/includes/fieldset.html" %} | ||
{% endfor %} | ||
{% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} | ||
{% if inline_admin_form.fk_field %}{{ inline_admin_form.fk_field.field }}{% endif %} | ||
</div>{% endfor %} | ||
</fieldset> | ||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
{% load i18n admin_urls static admin_modify %} | ||
<div class="js-inline-admin-formset inline-group" id="{{ inline_admin_formset.formset.prefix }}-group" | ||
data-inline-type="tabular" | ||
data-inline-formset="{{ inline_admin_formset.inline_formset_data }}"> | ||
<div class="tabular inline-related {% if forloop.last %}last-related{% endif %}"> | ||
{{ inline_admin_formset.formset.management_form }} | ||
<fieldset class="module {{ inline_admin_formset.classes }}"> | ||
{{ inline_admin_formset.formset.non_form_errors }} | ||
<table> | ||
<thead><tr> | ||
<th class="original"></th> | ||
{% for field in inline_admin_formset.fields %} | ||
<th class="column-{{ field.name }}{% if field.required %} required{% endif %}{% if field.widget.is_hidden %} hidden{% 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> | ||
{% 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="form-row {% 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 forloop.last and inline_admin_formset.has_add_permission %}empty{% else %}{{ forloop.counter0 }}{% endif %}"> | ||
<td class="original"> | ||
{% if inline_admin_form.original or inline_admin_form.show_url %}<p> | ||
{% 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="{{ inline_admin_formset.has_change_permission|yesno:'inlinechangelink,inlineviewlink' }}">{% 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 }}{% endif %} | ||
{% if inline_admin_form.fk_field %}{{ inline_admin_form.fk_field.field }}{% endif %} | ||
</td> | ||
{% for fieldset in inline_admin_form %} | ||
{% for line in fieldset %} | ||
{% for field in line %} | ||
<td class="{% if field.field.name %}field-{{ field.field.name }}{% endif %}{% if field.field.is_hidden %} hidden{% endif %}"> | ||
{% if field.is_readonly %} | ||
<p>{{ field.contents }}</p> | ||
{% else %} | ||
{{ field.field.errors.as_ul }} | ||
{{ field.field }} | ||
{% endif %} | ||
</td> | ||
{% endfor %} | ||
{% endfor %} | ||
{% endfor %} | ||
{% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission %} | ||
<td class="delete">{% if inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }}{% endif %}</td> | ||
{% endif %} | ||
</tr> | ||
{% endfor %} | ||
</tbody> | ||
</table> | ||
</fieldset> | ||
</div> | ||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<fieldset class="module aligned {{ fieldset.classes }}"> | ||
{% if fieldset.description %} | ||
<div class="description">{{ fieldset.description|safe }}</div> | ||
{% endif %} | ||
{% for line in fieldset %} | ||
<div class="form-row{% if line.fields|length == 1 and line.errors %} errors{% endif %}{% if not line.has_visible_field %} hidden{% endif %}{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}"> | ||
{% if line.fields|length == 1 %}{{ line.errors }}{% endif %} | ||
{% for field in line %} | ||
<div{% if not line.fields|length == 1 %} class="fieldBox{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% if not field.is_readonly and field.errors %} errors{% endif %}{% if field.field.is_hidden %} hidden{% endif %}"{% elif field.is_checkbox %} class="checkbox-row"{% endif %}> | ||
{% if not line.fields|length == 1 and not field.is_readonly %}{{ field.errors }}{% endif %} | ||
{% if field.is_checkbox %} | ||
{{ field.field }}{{ field.label_tag }} | ||
{% else %} | ||
{{ field.label_tag }} | ||
{% if field.is_readonly %} | ||
<div class="readonly">{{ field.contents }}</div> | ||
{% else %} | ||
{{ field.field }} | ||
{% endif %} | ||
{% endif %} | ||
</div> | ||
{% if field.field.help_text %} | ||
<div class="help"{% if field.field.id_for_label %} id="{{ field.field.id_for_label }}_helptext"{% endif %}> | ||
{{ field.field.help_text|safe }} | ||
</div> | ||
{% endif %} | ||
{% endfor %} | ||
</div> | ||
{% endfor %} | ||
</fieldset> |
Uh oh!
There was an error while loading. Please reload this page.