forms: add full date/time support for publication dates (#42252)
This commit is contained in:
parent
07617b5f1b
commit
0226e43616
|
@ -359,7 +359,7 @@ def test_forms_edit(pub):
|
|||
|
||||
resp = resp.click('Online Status')
|
||||
resp.forms[0]['disabled'].checked = False
|
||||
resp.forms[0]['expiration_date'] = '2000-01-01' # this is past(tm)
|
||||
resp.forms[0]['expiration_date$date'] = '2000-01-01' # this is past(tm)
|
||||
resp = resp.forms[0].submit()
|
||||
assert resp.location == 'http://example.net/backoffice/forms/1/'
|
||||
resp = resp.follow()
|
||||
|
@ -437,6 +437,41 @@ def test_form_title_change(pub):
|
|||
assert FormDef.get(formdef2.id).url_name == 'foobar'
|
||||
|
||||
|
||||
def test_forms_edit_publication_date(pub):
|
||||
create_superuser(pub)
|
||||
create_role()
|
||||
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
formdef.name = 'form title'
|
||||
formdef.fields = []
|
||||
formdef.store()
|
||||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('/backoffice/forms/1/options/online_status')
|
||||
resp.form['publication_date$date'] = '2020-01-01'
|
||||
resp = resp.form.submit()
|
||||
assert FormDef.get(formdef.id).publication_date == '2020-01-01 00:00'
|
||||
|
||||
resp = app.get('/backoffice/forms/1/options/online_status')
|
||||
assert resp.form['publication_date$date'].value == '2020-01-01'
|
||||
resp.form['publication_date$time'] = '12:00'
|
||||
resp = resp.form.submit()
|
||||
assert FormDef.get(formdef.id).publication_date == '2020-01-01 12:00'
|
||||
|
||||
resp = app.get('/backoffice/forms/1/options/online_status')
|
||||
assert resp.form['publication_date$date'].value == '2020-01-01'
|
||||
assert resp.form['publication_date$time'].value == '12:00'
|
||||
|
||||
formdef.publication_date = None
|
||||
formdef.store()
|
||||
|
||||
resp = app.get('/backoffice/forms/1/options/online_status')
|
||||
resp.form['publication_date$time'] = '12:00'
|
||||
resp = resp.form.submit()
|
||||
assert 'invalid value' in resp
|
||||
|
||||
|
||||
def test_form_category(pub):
|
||||
create_superuser(pub)
|
||||
create_role()
|
||||
|
|
|
@ -20,6 +20,7 @@ import glob
|
|||
import itertools
|
||||
import pickle
|
||||
import sys
|
||||
import time
|
||||
import types
|
||||
import json
|
||||
import xml.etree.ElementTree as ET
|
||||
|
|
|
@ -24,7 +24,6 @@ import re
|
|||
import socket
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import random
|
||||
import datetime
|
||||
import itertools
|
||||
|
@ -175,6 +174,15 @@ def render(self):
|
|||
template_names = get_template_names(self)
|
||||
return htmltext(render_template(template_names, context))
|
||||
|
||||
def render_widget_content(self):
|
||||
# widget content (without label, hint, etc.) is reused on status page;
|
||||
# render the appropriate block.
|
||||
self.add_media()
|
||||
template_names = get_template_names(self)
|
||||
context = {'widget': self}
|
||||
return htmltext(force_str(render_block_to_string(template_names, 'widget-content', context)))
|
||||
|
||||
|
||||
Widget.get_error = get_i18n_error
|
||||
Widget.render = render
|
||||
Widget.cleanup = None
|
||||
|
@ -182,6 +190,7 @@ Widget.render_error = render_error
|
|||
Widget.render_hint = render_hint
|
||||
Widget.render_title = render_title
|
||||
Widget.is_prefilled = is_prefilled
|
||||
Widget.render_widget_content = render_widget_content
|
||||
|
||||
|
||||
def string_render_content(self):
|
||||
|
@ -1126,17 +1135,55 @@ class DateWidget(StringWidget):
|
|||
'hh', '00').replace('ii', '00').replace('ss', '00')
|
||||
|
||||
|
||||
class DateTimeWidget(DateWidget):
|
||||
'''StringWidget which checks the value entered is a correct date/time'''
|
||||
content_extra_css_class = 'date'
|
||||
class TimeWidget(DateWidget):
|
||||
template_name = 'qommon/forms/widgets/time.html'
|
||||
|
||||
def _parse(self, request):
|
||||
StringWidget._parse(self, request)
|
||||
if self.value is not None:
|
||||
try:
|
||||
value = datetime.datetime.strptime(self.value, self.get_format_string())
|
||||
self.value = strftime(self.get_format_string(), value)
|
||||
except ValueError:
|
||||
self.error = _('invalid time')
|
||||
self.value = None
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def get_format_string(cls):
|
||||
return '%H:%M'
|
||||
|
||||
|
||||
class DateTimeWidget(CompositeWidget):
|
||||
def __init__(self, name, value=None, **kwargs):
|
||||
DateWidget.__init__(self, name, value=value, **kwargs)
|
||||
self.attrs['size'] = '16'
|
||||
self.attrs['maxlength'] = '16'
|
||||
super(DateTimeWidget, self).__init__(name, value=value, **kwargs)
|
||||
date_value = None
|
||||
time_value = None
|
||||
if value:
|
||||
date_value = misc.get_as_datetime(value).strftime(DateWidget.get_format_string())
|
||||
time_value = misc.get_as_datetime(value).strftime(TimeWidget.get_format_string())
|
||||
self.add(DateWidget, 'date', value=date_value, render_br=False)
|
||||
self.add(TimeWidget, 'time', value=time_value, render_br=False)
|
||||
|
||||
def get_format_string(self):
|
||||
return misc.datetime_format()
|
||||
def render_content(self):
|
||||
r = TemplateIO(html=True)
|
||||
for widget in self.get_widgets():
|
||||
r += widget.render_widget_content()
|
||||
return r.getvalue()
|
||||
|
||||
def _parse(self, request):
|
||||
date = self.get('date')
|
||||
time = self.get('time')
|
||||
if not date and not time:
|
||||
self.value = None
|
||||
return self.value
|
||||
time = time or '00:00'
|
||||
try:
|
||||
misc.get_as_datetime('%s %s' % (date, time))
|
||||
except ValueError:
|
||||
self.error = _('invalid value')
|
||||
self.value = '%s %s' % (date, time)
|
||||
return self.value
|
||||
|
||||
|
||||
class RegexStringWidget(StringWidget):
|
||||
|
@ -2248,14 +2295,6 @@ class MapWidget(CompositeWidget):
|
|||
def add_media(self):
|
||||
get_response().add_javascript(['qommon.map.js'])
|
||||
|
||||
def render_widget_content(self):
|
||||
# widget content (without label, hint, etc.) is reused on status page;
|
||||
# render the appropriate block.
|
||||
self.add_media()
|
||||
template_names = get_template_names(self)
|
||||
context = {'widget': self}
|
||||
return htmltext(force_str(render_block_to_string(template_names, 'widget-content', context)))
|
||||
|
||||
def _parse(self, request):
|
||||
CompositeWidget._parse(self, request)
|
||||
self.value = self.get('latlng')
|
||||
|
|
|
@ -659,6 +659,10 @@ div.SingleSelectHintWidget select {
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
div.DateTimeWidget .content .content {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
aside#sidebar input.inline-input {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,9 @@ $(function() {
|
|||
});
|
||||
}
|
||||
$('.date-pick').each(function() {
|
||||
if (this.type == "date") return; // prefer native date widget
|
||||
if (this.type == "date" || this.type == "time") {
|
||||
return; // prefer native date/time widgets
|
||||
}
|
||||
var $date_input = $(this);
|
||||
$date_input.attr('type', 'text');
|
||||
if ($date_input.data('formatted-value')) {
|
||||
|
@ -42,6 +44,7 @@ $(function() {
|
|||
options.weekStart = 1;
|
||||
options.format = $date_input.data('date-format');
|
||||
options.minView = $date_input.data('min-view');
|
||||
options.maxView = $date_input.data('max-view');
|
||||
options.startView = $date_input.data('start-view');
|
||||
if ($date_input.data('start-date')) options.startDate = $date_input.data('start-date');
|
||||
if ($date_input.data('end-date')) options.endDate = $date_input.data('end-date');
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
{% block widget-control %}
|
||||
<input id="form_{{widget.name}}" name="{{widget.name}}"
|
||||
type="{% if "readonly" in widget.attrs %}text{% else %}date{% endif %}"
|
||||
{% for attr in widget.attrs.items %}{{attr.0}}="{{attr.1}}"{% endfor %}
|
||||
{% for attr in widget.attrs.items %}{{attr.0}}="{{attr.1}}" {% endfor %}
|
||||
{% if widget.required %}aria-required="true"{% endif %}
|
||||
{% if "readonly" in widget.attrs %}
|
||||
{% if widget.value %}value="{{ widget.value }}"{% endif %}
|
||||
{% else %}
|
||||
|
||||
{% if widget.value %}value="{{ widget.value|date:"Y-m-d" }}" data-formatted-value="{{ widget.value }}"{% endif %}
|
||||
{% if widget.value %}value="{{ widget.value|date:"Y-m-d" }}" data-formatted-value="{{ widget.value|default:"" }}"{% endif %}
|
||||
class="date-pick"
|
||||
data-date-format="{{widget.date_format}}"
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
{% extends "qommon/forms/widget.html" %}
|
||||
|
||||
{% block widget-control %}
|
||||
<input id="form_{{widget.name}}" name="{{widget.name}}"
|
||||
type="{% if "readonly" in widget.attrs %}text{% else %}time{% endif %}"
|
||||
{% for attr in widget.attrs.items %}{{attr.0}}="{{attr.1}}" {% endfor %}
|
||||
{% if widget.required %}aria-required="true"{% endif %}
|
||||
{% if "readonly" in widget.attrs %}
|
||||
{% if widget.value %}value="{{ widget.value }}"{% endif %}
|
||||
{% else %}
|
||||
|
||||
value="{{ widget.value|default:"" }}" data-formatted-value="{{ widget.value|default:"" }}"
|
||||
class="date-pick"
|
||||
data-date-format="hh:ii"
|
||||
|
||||
data-min-view="0"
|
||||
data-max-view="0"
|
||||
data-start-view="0"
|
||||
|
||||
{% endif %}
|
||||
>
|
||||
{% endblock %}
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
import itertools
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
|
||||
from django.utils import six
|
||||
|
||||
|
|
Loading…
Reference in New Issue