import re from django import forms from django.core.files.uploadedfile import InMemoryUploadedFile from django.forms.utils import flatatt from django.forms.widgets import FileInput from django.template.loader import render_to_string from django.utils import formats, six from django.utils.encoding import force_text from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.six.moves import filter, map class ImageInput(FileInput): """ Widget providing a input element for file uploads based on the Django ``FileInput`` element. It hides the actual browser-specific input element and shows the available image for images that have been previously uploaded. Selecting the image will open the file dialog and allow for selecting a new or replacing image file. """ template_name = 'partials/image_input_widget.html' attrs = {'accept': 'image/*'} def render(self, name, value, attrs=None): """ Render the ``input`` field based on the defined ``template_name``. The image URL is take from *value* and is provided to the template as ``image_url`` context variable relative to ``MEDIA_URL``. Further attributes for the ``input`` element are provide in ``input_attrs`` and contain parameters specified in *attrs* and *name*. If *value* contains no valid image URL an empty string will be provided in the context. """ final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) if not value or isinstance(value, InMemoryUploadedFile): # can't display images that aren't stored image_url = '' else: image_url = final_attrs['value'] = force_text( self._format_value(value)) return render_to_string(self.template_name, { 'input_attrs': flatatt(final_attrs), 'image_url': image_url, 'image_id': "%s-image" % final_attrs['id'], }) class WYSIWYGTextArea(forms.Textarea): def __init__(self, *args, **kwargs): kwargs.setdefault('attrs', {}) kwargs['attrs'].setdefault('class', '') kwargs['attrs']['class'] += ' wysiwyg' super(WYSIWYGTextArea, self).__init__(*args, **kwargs) def datetime_format_to_js_date_format(format): """ Convert a Python datetime format to a date format suitable for use with the JS date picker we use. """ format = format.split()[0] return datetime_format_to_js_datetime_format(format) def datetime_format_to_js_time_format(format): """ Convert a Python datetime format to a time format suitable for use with the JS time picker we use. """ try: format = format.split()[1] except IndexError: pass converted = format replacements = { '%H': 'hh', '%I': 'HH', '%M': 'ii', '%S': 'ss', } for search, replace in replacements.items(): converted = converted.replace(search, replace) return converted.strip() def datetime_format_to_js_datetime_format(format): """ Convert a Python datetime format to a time format suitable for use with the datetime picker we use, http://www.malot.fr/bootstrap-datetimepicker/. """ converted = format replacements = { '%Y': 'yyyy', '%y': 'yy', '%m': 'mm', '%d': 'dd', '%H': 'hh', '%I': 'HH', '%M': 'ii', '%S': 'ss', } for search, replace in replacements.items(): converted = converted.replace(search, replace) return converted.strip() def datetime_format_to_js_input_mask(format): # taken from # http://stackoverflow.com/questions/15175142/how-can-i-do-multiple-substitutions-using-regex-in-python # noqa def multiple_replace(dict, text): # Create a regular expression from the dictionary keys regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys()))) # For each match, look-up corresponding value in dictionary return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text) replacements = { '%Y': 'y', '%y': '99', '%m': 'm', '%d': 'd', '%H': 'h', '%I': 'h', '%M': 's', '%S': 's', } return multiple_replace(replacements, format).strip() class DateTimeWidgetMixin(object): def get_format(self): format = self.format if hasattr(self, 'manual_format'): # For django <= 1.6.5, see # https://code.djangoproject.com/ticket/21173 if self.is_localized and not self.manual_format: format = force_text(formats.get_format(self.format_key)[0]) else: # For django >= 1.7 format = format or formats.get_format(self.format_key)[0] return format def gett_attrs(self, attrs, format): if not attrs: attrs = {} attrs['data-inputmask'] = "'mask': '{mask}'".format( mask=datetime_format_to_js_input_mask(format)) return attrs class TimePickerInput(DateTimeWidgetMixin, forms.TimeInput): """ A widget that passes the date format to the JS date picker in a data attribute. """ format_key = 'TIME_INPUT_FORMATS' def render(self, name, value, attrs=None): format = self.get_format() input = super(TimePickerInput, self).render( name, value, self.gett_attrs(attrs, format)) attrs = {'data-oscarWidget': 'time', 'data-timeFormat': datetime_format_to_js_time_format(format), } div = format_html('