# -*- coding: utf-8 -*- from __future__ import unicode_literals import datetime from json import dumps as json_dumps import logging from django import forms from django.forms.utils import flatatt from django.forms.widgets import DateTimeInput from django.utils.safestring import mark_safe from django.utils import translation from django.utils.html import conditional_escape from django.utils.encoding import force_text logger = logging.getLogger(__name__) DATE_FORMAT = { 'fr': "dd/mm/yyyy", 'en': "yyyy/mm/dd", } DATE_INPUT_FORMATS = ['%d/%m/%Y', '%Y/%m/%d', '%Y-%m-%d'] class DatePicker(DateTimeInput): class Media: class JSFiles(object): def __iter__(self): yield 'js/bootstrap-datepicker.js' lang = translation.get_language() if lang: lang = lang.lower() # language name with length > 2 or containing uppercase lang_map = { 'en-au': 'en-AU', 'en-gb': 'en-GB', 'en-us': 'en-us', 'fr-CH': 'fr-CH', 'it-ch': 'it-CH', 'nl-be': 'nl-BE', 'pt-br': 'pt-BR', 'rs-latin': 'rs-latin', 'sr-latin': 'sr-latin', 'zh-cn': 'zh-CN', 'zh-tw': 'zh-TW', } if len(lang) > 2: lang = lang_map.get(lang, 'en-us') if lang not in ('en', 'en-us'): yield 'js/locales/bootstrap-datepicker.%s.min.js' % ( lang) js = list(JSFiles()) css = {'all': ('css/bootstrap-datepicker3.standalone.min.css',), } # http://bootstrap-datepicker.readthedocs.org/en/stable/options.html#format # http://docs.python.org/2/library/datetime.html#strftime-strptime-behavior format_map = ( ('dd', r'%d'), ('DD', r'%A'), ('D', r'%a'), ('MM', r'%B'), ('M', r'%b'), ('mm', r'%m'), ('yyyy', r'%Y'), ('yy', r'%y'), ) @classmethod def conv_datetime_format_py2js(cls, format): for js, py in cls.format_map: format = format.replace(py, js) return format @classmethod def conv_datetime_format_js2py(cls, format): for js, py in cls.format_map: format = format.replace(js, py) return format html_template = """ """ js_template = ''' ''' def __init__(self, attrs=None, format=None, options=None, div_attrs=None, icon_attrs=None): if not icon_attrs: icon_attrs = {'class': 'fa fa-calendar fa-2'} if not div_attrs: div_attrs = {'class': 'input-group date'} if format is None and options and options.get('format'): format = self.conv_datetime_format_js2py(options.get('format')) super(DatePicker, self).__init__(attrs, format) if 'class' not in self.attrs: self.attrs['class'] = 'form-control' self.div_attrs = div_attrs and div_attrs.copy() or {} self.icon_attrs = icon_attrs and icon_attrs.copy() or {} self.picker_id = self.div_attrs.get('id') or None self.options = options and options.copy() or {} if format and not self.options.get('format') and not self.attrs.get( 'date-format'): self.options['format'] = self.conv_datetime_format_py2js(format) def format_value(self, value): if not self.options.get('format'): logger.debug('datepicker: format not defined') return str(value) py_format = self.conv_datetime_format_js2py(self.options['format']) if not hasattr(value, 'strftime'): value = str(value) try: value = datetime.datetime.strptime(value, '%Y-%m-%d') except ValueError: logger.debug('datepicker: cannot extract date from %s' % value) return str(value) value = value.strftime(py_format) return value def render(self, name, value, attrs=None, renderer=None): if value is None: value = '' extra_attrs = dict() extra_attrs['type'] = self.input_type extra_attrs['name'] = name input_attrs = self.build_attrs(attrs, extra_attrs) if value != '': # Only add the 'value' attribute if a value is non-empty. input_attrs['value'] = force_text(self.format_value(value)) input_attrs = {key: conditional_escape(val) for key, val in input_attrs.items()} if not self.picker_id: self.picker_id = ( input_attrs.get('id', '') + '_pickers' ).replace(' ', '_') self.div_attrs['id'] = self.picker_id picker_id = conditional_escape(self.picker_id) div_attrs = {key: conditional_escape(val) for key, val in self.div_attrs.items()} icon_attrs = {key: conditional_escape(val) for key, val in self.icon_attrs.items()} html = self.html_template % dict(div_attrs=flatatt(div_attrs), input_attrs=flatatt(input_attrs), icon_attrs=flatatt(icon_attrs)) js = self.js_template % dict( picker_id=picker_id, options=json_dumps(self.options or {})) return mark_safe(force_text(html + js)) class DateField(forms.DateField): widget = DatePicker input_formats = DATE_INPUT_FORMATS