|
1 |
# Bootstrap django-datetime-widget is a simple and clean widget for DateField,
|
|
2 |
# Timefiled and DateTimeField in Django framework. It is based on Bootstrap
|
|
3 |
# datetime picker, supports Bootstrap 2
|
|
4 |
#
|
|
5 |
# https://github.com/asaglimbeni/django-datetime-widget
|
|
6 |
#
|
|
7 |
# License: BSD
|
|
8 |
# Initial Author: Alfredo Saglimbeni
|
|
9 |
|
|
10 |
import json
|
|
11 |
import re
|
|
12 |
import uuid
|
|
13 |
|
|
14 |
from django.forms.widgets import DateTimeInput, DateInput, TimeInput
|
|
15 |
from django.utils.formats import get_language
|
|
16 |
from django.utils.safestring import mark_safe
|
|
17 |
|
|
18 |
DATE_FORMAT_JS_PY_MAPPING = {
|
|
19 |
'P': '%p',
|
|
20 |
'ss': '%S',
|
|
21 |
'ii': '%M',
|
|
22 |
'hh': '%H',
|
|
23 |
'HH': '%I',
|
|
24 |
'dd': '%d',
|
|
25 |
'mm': '%m',
|
|
26 |
'yy': '%y',
|
|
27 |
'yyyy': '%Y',
|
|
28 |
}
|
|
29 |
|
|
30 |
DATE_FORMAT_TO_PYTHON_REGEX = re.compile(r'\b(' + '|'.join(DATE_FORMAT_JS_PY_MAPPING.keys()) + r')\b')
|
|
31 |
|
|
32 |
|
|
33 |
DATE_FORMAT_PY_JS_MAPPING = {
|
|
34 |
'%M': 'ii',
|
|
35 |
'%m': 'mm',
|
|
36 |
'%I': 'HH',
|
|
37 |
'%H': 'hh',
|
|
38 |
'%d': 'dd',
|
|
39 |
'%Y': 'yyyy',
|
|
40 |
'%y': 'yy',
|
|
41 |
'%p': 'P',
|
|
42 |
'%S': 'ss'
|
|
43 |
}
|
|
44 |
|
|
45 |
DATE_FORMAT_TO_JS_REGEX = re.compile(r'(?<!\w)(' + '|'.join(DATE_FORMAT_PY_JS_MAPPING.keys()) + r')\b')
|
|
46 |
|
|
47 |
|
|
48 |
BOOTSTRAP_INPUT_TEMPLATE = """
|
|
49 |
<div id="%(id)s" class="controls input-append date">
|
|
50 |
%(rendered_widget)s
|
|
51 |
%(clear_button)s
|
|
52 |
<span class="add-on"><i class="icon-th"></i></span>
|
|
53 |
</div>
|
|
54 |
<script type="text/javascript">
|
|
55 |
$("#%(id)s").datetimepicker({%(options)s});
|
|
56 |
</script>
|
|
57 |
"""
|
|
58 |
|
|
59 |
CLEAR_BTN_TEMPLATE = """<span class="add-on"><i class="icon-remove"></i></span>"""
|
|
60 |
|
|
61 |
|
|
62 |
class PickerWidgetMixin(object):
|
|
63 |
|
|
64 |
format_name = None
|
|
65 |
glyphicon = None
|
|
66 |
|
|
67 |
def __init__(self, attrs=None, options=None, usel10n=None):
|
|
68 |
|
|
69 |
if attrs is None:
|
|
70 |
attrs = {'readonly': ''}
|
|
71 |
|
|
72 |
self.options = options
|
|
73 |
self.options['language'] = get_language().split('-')[0]
|
|
74 |
|
|
75 |
# We're not doing localisation, get the Javascript date format provided by the user,
|
|
76 |
# with a default, and convert it to a Python data format for later string parsing
|
|
77 |
date_format = self.options['format']
|
|
78 |
self.format = DATE_FORMAT_TO_PYTHON_REGEX.sub(
|
|
79 |
lambda x: DATE_FORMAT_JS_PY_MAPPING[x.group()],
|
|
80 |
date_format
|
|
81 |
)
|
|
82 |
|
|
83 |
super(PickerWidgetMixin, self).__init__(attrs, format=self.format)
|
|
84 |
|
|
85 |
def render(self, name, value, attrs=None):
|
|
86 |
final_attrs = self.build_attrs(attrs)
|
|
87 |
rendered_widget = super(PickerWidgetMixin, self).render(name, value, final_attrs)
|
|
88 |
|
|
89 |
#if not set, autoclose have to be true.
|
|
90 |
self.options.setdefault('autoclose', True)
|
|
91 |
|
|
92 |
# Build javascript options out of python dictionary
|
|
93 |
options_list = []
|
|
94 |
for key, value in iter(self.options.items()):
|
|
95 |
options_list.append("%s: %s" % (key, json.dumps(value)))
|
|
96 |
|
|
97 |
js_options = ",\n".join(options_list)
|
|
98 |
|
|
99 |
# Use provided id or generate hex to avoid collisions in document
|
|
100 |
id = final_attrs.get('id', uuid.uuid4().hex)
|
|
101 |
|
|
102 |
return mark_safe(BOOTSTRAP_INPUT_TEMPLATE % dict(
|
|
103 |
id=id,
|
|
104 |
rendered_widget=rendered_widget,
|
|
105 |
clear_button=CLEAR_BTN_TEMPLATE if self.options.get('clearBtn') else '',
|
|
106 |
glyphicon=self.glyphicon,
|
|
107 |
options=js_options
|
|
108 |
)
|
|
109 |
)
|
|
110 |
|
|
111 |
|
|
112 |
class DateTimeWidget(PickerWidgetMixin, DateTimeInput):
|
|
113 |
"""
|
|
114 |
DateTimeWidget is the corresponding widget for Datetime field, it renders both the date and time
|
|
115 |
sections of the datetime picker.
|
|
116 |
"""
|
|
117 |
|
|
118 |
format_name = 'DATETIME_INPUT_FORMATS'
|
|
119 |
glyphicon = 'glyphicon-th'
|
|
120 |
|
|
121 |
def __init__(self, attrs=None, options=None, usel10n=None):
|
|
122 |
|
|
123 |
if options is None:
|
|
124 |
options = {}
|
|
125 |
|
|
126 |
# Set the default options to show only the datepicker object
|
|
127 |
options['format'] = options.get('format', 'dd/mm/yyyy hh:ii')
|
|
128 |
|
|
129 |
super(DateTimeWidget, self).__init__(attrs, options, usel10n)
|
|
130 |
|
|
131 |
|
|
132 |
class DateWidget(PickerWidgetMixin, DateInput):
|
|
133 |
"""
|
|
134 |
DateWidget is the corresponding widget for Date field, it renders only the date section of
|
|
135 |
datetime picker.
|
|
136 |
"""
|
|
137 |
|
|
138 |
format_name = 'DATE_INPUT_FORMATS'
|
|
139 |
glyphicon = 'glyphicon-calendar'
|
|
140 |
|
|
141 |
def __init__(self, attrs=None, options=None, usel10n=None):
|
|
142 |
|
|
143 |
if options is None:
|
|
144 |
options = {}
|
|
145 |
|
|
146 |
# Set the default options to show only the datepicker object
|
|
147 |
options['startView'] = options.get('startView', 2)
|
|
148 |
options['minView'] = options.get('minView', 2)
|
|
149 |
options['format'] = options.get('format', 'dd/mm/yyyy')
|
|
150 |
|
|
151 |
super(DateWidget, self).__init__(attrs, options, usel10n)
|
|
152 |
|
|
153 |
|
|
154 |
class TimeWidget(PickerWidgetMixin, TimeInput):
|
|
155 |
"""
|
|
156 |
TimeWidget is the corresponding widget for Time field, it renders only the time section of
|
|
157 |
datetime picker.
|
|
158 |
"""
|
|
159 |
|
|
160 |
format_name = 'TIME_INPUT_FORMATS'
|
|
161 |
glyphicon = 'glyphicon-time'
|
|
162 |
|
|
163 |
def __init__(self, attrs=None, options=None, usel10n=None):
|
|
164 |
|
|
165 |
if options is None:
|
|
166 |
options = {}
|
|
167 |
|
|
168 |
# Set the default options to show only the timepicker object
|
|
169 |
options['startView'] = options.get('startView', 1)
|
|
170 |
options['minView'] = options.get('minView', 0)
|
|
171 |
options['maxView'] = options.get('maxView', 1)
|
|
172 |
options['format'] = options.get('format', 'hh:ii')
|
|
173 |
|
|
174 |
super(TimeWidget, self).__init__(attrs, options, usel10n)
|
use specialized widgets for datetimes (#15087)