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

Buttons and labels for complicated forms #4328

Merged
merged 9 commits into from
Aug 8, 2024
6 changes: 5 additions & 1 deletion src/copyediting/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ class CopyeditAssignment(models.Model):
date_decided = models.DateTimeField(null=True, blank=True)

files_for_copyediting = models.ManyToManyField('core.File', related_name='files_for_copyediting')
copyeditor_files = models.ManyToManyField('core.File', blank=True)
copyeditor_files = models.ManyToManyField(
'core.File',
blank=True,
related_name='copyeditor_files',
)
copyeditor_completed = models.DateTimeField(blank=True, null=True)

copyedit_reopened = models.DateTimeField(blank=True, null=True)
Expand Down
12 changes: 11 additions & 1 deletion src/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import statistics
import json
from datetime import timedelta
from django.utils.html import format_html
import pytz
from hijack.signals import hijack_started, hijack_ended
import warnings
Expand All @@ -32,7 +33,7 @@
from django.dispatch import receiver
from django.urls import reverse
from django.utils.functional import cached_property
from django.template.defaultfilters import linebreaksbr
from django.template.defaultfilters import date
import swapper

from core import files, validators
Expand Down Expand Up @@ -1225,6 +1226,15 @@ def unlink_files(self):
def __str__(self):
return "{0} ({1})".format(self.id, self.label)

def detail(self):
return format_html(
'{} galley linked to <a href="#file_{}">file {}: {}</a>',
self.label,
self.file.pk,
self.file.pk,
self.file.original_filename,
)

def render(self, recover=False):
return files.render_xml(
self.file, self.article,
Expand Down
30 changes: 30 additions & 0 deletions src/core/templatetags/dates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from django import template
from django.utils import timezone


register = template.Library()

@register.simple_tag
def offset_date(days=0, input_type="date"):
"""
Get a string representing today's date or the now datetime,
with an offset of X days.
:param days: number of days from now that the date should be set
:param date: date or datetime-local

Usage:

<input
id="due"
name="due"
type="{{ input_type }}"
value="{% offset_date days=3 input_type=input_type %}">

See admin.core.widgets.soon_date_buttons for a use case.

"""
due = timezone.now() + timezone.timedelta(days=days)
if input_type == "date":
return due.strftime("%Y-%m-%d")
elif input_type == "datetime-local":
return due.strftime("%Y-%m-%dT%H:%M")
8 changes: 8 additions & 0 deletions src/core/templatetags/uuid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django import template
from uuid import uuid4

register = template.Library()

@register.simple_tag
def get_uuid4():
return f'u{str(uuid4())}'
4 changes: 3 additions & 1 deletion src/static/admin/js/check_all.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Deprecated. Use select_all.html instead.

$("#checkall").click(function () {
$('input:checkbox').not(this).prop('checked', this.checked);
});
});
44 changes: 44 additions & 0 deletions src/templates/admin/core/widgets/select_all.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{% comment %}
Easily select or deselect all the checkboxes for a given field.

Make sure to wrap this widget and the checkboxes in fieldset.

Usage:

<fieldset>
<legend>Which colours?</legend>
{% include "admin/core/widgets/select_all.html" %}
<input id="red" name="red" type="checkbox"><label for="red">Red</label>
<input id="blue" name="blue" type="checkbox"><label for="blue">Blue</label>
</fieldset>

{% endcomment %}

{% load uuid %}

{% get_uuid4 as pid %}

<div id="{{ pid }}" style="button-group">
<button class="button selectall" type="button">
<span class="fa fa-check"></span>
Select all
</button>
<button class="button deselectall" type="button">
<span class="fa fa-close"></span>
Deselect all
</button>
</div>
<script defer type="module">
function toggleInputsInFieldset(event) {
const checked = event.currentTarget.classList.contains('selectall');
const fieldset = event.currentTarget.closest('fieldset');
const checkboxes = fieldset.querySelectorAll('input[type="checkbox"]');
Array.from(checkboxes).forEach(checkbox => {
checkbox.checked = checked;
});
}
const selectAll = document.querySelector('#{{ pid }} .selectall');
selectAll.addEventListener('click', toggleInputsInFieldset);
const deselectAll = document.querySelector('#{{ pid }} .deselectall');
deselectAll.addEventListener('click', toggleInputsInFieldset);
</script>
86 changes: 86 additions & 0 deletions src/templates/admin/core/widgets/soon_date_buttons.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{% comment %}
Easily fill in a date or datetime field.

date_input_id - str: the id of the input these buttons should control.

Usage:

{% include "admin/core/widgets/soon_date_buttons.html" with date_input_id="due" %}
<label for="due">Due date</label>
<input id="due" name="due" type="date">

{% endcomment %}

{% load uuid %}
{% load dates %}

{% get_uuid4 as pid %}

<div id="{{ pid }}" style="button-group">
<button
class="button set-date"
type="button"
aria-controls="{{ date_input_id }}"
value="{% offset_date days=0 input_type=input_type %}">
{% if input_type == "datetime-local" %}Now{% else %}Today{% endif %}
</button>
<button
class="button set-date"
type="button"
aria-controls="{{ date_input_id }}"
value="{% offset_date days=1 input_type=input_type %}">
1 day
</button>
<button
class="button set-date"
type="button"
aria-controls="{{ date_input_id }}"
value="{% offset_date days=2 input_type=input_type %}">
2 days
</button>
<button
class="button set-date"
type="button"
aria-controls="{{ date_input_id }}"
value="{% offset_date days=3 input_type=input_type %}">
3 days
</button>
<button
class="button set-date"
type="button"
aria-controls="{{ date_input_id }}"
value="{% offset_date days=5 input_type=input_type %}">
5 days
</button>
<button
class="button set-date"
type="button"
aria-controls="{{ date_input_id }}"
value="{% offset_date days=7 input_type=input_type %}">
1 week
</button>
<button
class="button set-date"
type="button"
aria-controls="{{ date_input_id }}"
value="{% offset_date days=14 input_type=input_type %}">
2 weeks
</button>
<button
class="button set-date"
type="button"
aria-controls="{{ date_input_id }}"
value="{% offset_date days=28 input_type=input_type %}">
4 weeks
</button>
</div>
<script defer type="module">
function setDate(event) {
const dateInput = document.querySelector('#{{ date_input_id }}');
dateInput.value = event.currentTarget.value;
}
const setDateButtons = document.querySelectorAll('#{{ pid }} .set-date');
Array.from(setDateButtons).forEach(dateButton => {
dateButton.addEventListener('click', setDate);
});
</script>
22 changes: 12 additions & 10 deletions src/templates/admin/elements/datatables.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@
<script type="text/javascript">

$(document).ready(function() {
$('{{target}}').DataTable({
"lengthMenu": [[25, 50, 10, 5, -1], [25, 50, 10, 5, "All"]],
{% if hide_length %}"bLengthChange": false,{% endif %}
{% if hide_page %}"bPaginate": false,{% endif %}
{% if sort and order %}"order": [[ {{ sort }}, "{{ order }}" ]],{% endif %}
{% if sort_list %}"order": [{{ sort_list }}],{% endif %}
{% if disable_ordering %}"ordering": false,{% endif %}
{% if page_length %}"pageLength": {{ page_length }},{% endif %}
'{{ target }}'.split(' ').forEach(target => {
$(target).DataTable({
"lengthMenu": [[25, 50, 10, 5, -1], [25, 50, 10, 5, "All"]],
{% if hide_length %}"bLengthChange": false,{% endif %}
{% if hide_page %}"bPaginate": false,{% endif %}
{% if sort and order %}"order": [[ {{ sort }}, "{{ order }}" ]],{% endif %}
{% if sort_list %}"order": [{{ sort_list }}],{% endif %}
{% if disable_ordering %}"ordering": false,{% endif %}
{% if page_length %}"pageLength": {{ page_length }},{% endif %}
});
} );
});
});

</script>
</script>
1 change: 1 addition & 0 deletions src/templates/admin/elements/publish/pubdate.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ <h5>Publication Date/Time</h5>
{% endif %}
<form method="POST">
{% csrf_token %}
{% include "admin/core/widgets/soon_date_buttons.html" with date_input_id=pub_date_form.date_published.id_for_label input_type="datetime-local" %}
{{ pub_date_form|foundation }}
<button type="submit" name="pubdate" class="small success button">Set Publication Date</button>
</form>
Expand Down