Source code for pythia.widgets

from __future__ import unicode_literals

from itertools import chain

from django.forms.widgets import SelectMultiple, CheckboxInput
from django.core.urlresolvers import reverse
from django.utils.html import format_html
from django.utils.encoding import force_text
from django.utils.safestring import mark_safe
from django.contrib.admin.util import quote
from django.forms import widgets
from django import forms

# import json

import copy

# from pythia.utils import text2html, html2text


[docs]class ArrayFieldWidget(widgets.TextInput):
[docs] def render(self, name, value, *args, **kwargs): html = super(ArrayFieldWidget, self).render( name, value, *args, **kwargs) tag = ('dataTable%s' % kwargs['attrs'].get('id', '')) html += '<div id="{0}"></div><div>&nbsp;</div>'.format(tag) return mark_safe(html)
[docs] def value_from_datadict(self, data, files, name): output = '[[""]]' try: output = data[unicode(name)] except: pass return output
[docs]class AreasWidgetWrapper(widgets.Widget): def __init__(self, widget): self.widget = widget self.attrs = widget.attrs @property def media(self): return self.widget.media def __deepcopy__(self, memo): obj = copy.copy(self) obj.widget = copy.deepcopy(self.widget, memo) obj.attrs = self.widget.attrs memo[id(self)] = obj return obj
[docs] def render(self, name, value, *args, **kwargs): output = [self.widget.render(name, value, *args, **kwargs)] output.append('<script type="text/javascript">') output.append(' pythia.areasWidgetWrapper("{0}");'.format( kwargs['attrs'].get('id', ''))) output.append('</script>') return mark_safe(''.join(output))
[docs] def build_attrs(self, extra_attrs=None, **kwargs): "Helper function for building an attribute dictionary." self.attrs = self.widget.build_attrs(extra_attrs=None, **kwargs) return self.attrs
[docs] def value_from_datadict(self, data, files, name): return self.widget.value_from_datadict(data, files, name)
[docs] def id_for_label(self, id_): return self.widget.id_for_label(id_)
[docs]class InlineEditWidgetWrapper(widgets.Widget): """Custom InlineEditWidgetWrapper. Adapted from ``django.contrib.admin.widgets.RelatedFieldWidgetWrapper``. Changes 2014: We reverted to store HTML, not Markdown in ``pythia.fields.Html2TextField``. Enable lines with "MARKDOWN" comments to convert HTML edited in the widget to Markdown in the db field. """ widget_overrides = ( (ArrayFieldWidget, 'pythia.handsontable("%s", "%s");'), (widgets.TextInput, 'pythia.inlineEditTextInput("%s", "%s");'), (widgets.Textarea, 'pythia.inlineEditTextarea("%s", "%s");'), (widgets.Select, 'pythia.inlineEditSelect("%s", "%s");'), (widgets.Widget, 'pythia.inlineEditWidget("%s", "%s");'), ) def __init__(self, widget): self.widget = widget self.attrs = widget.attrs # @property # def media(self): # """Load custom static assets depending on widget class.""" # if isinstance(self.widget, widgets.Textarea): # cdn = 'https://static.dpaw.wa.gov.au/static/libs/' # return forms.Media( # js=[cdn + 'tinymce/4.3.12/tinymce.min.js', # cdn + 'tinymce/4.3.12/jquery.tinymce.min.js' # ]) + self.widget.media # else: # return self.widget.media def __deepcopy__(self, memo): obj = copy.copy(self) obj.widget = copy.deepcopy(self.widget, memo) obj.attrs = self.widget.attrs memo[id(self)] = obj return obj
[docs] def render(self, name, value, *args, **kwargs): """Custom render method. If the form has not been injected to the widget, failover to the original widget. ``url`` refers to the ``POST`` location used by TinyMCE's AJAX save function. If we're on an add page, we don't want to POST save anything. """ if not hasattr(self, 'form'): # the form has not been injected to the widget, failover to the # original widget return mark_safe(self.widget.render(name, value, *args, **kwargs)) opts = self.form.instance._meta # url refers to the POST location used by TinyMCE's AJAX save function. # If we're on an add page, we don't want to POST save anything. url = None if self.form.instance.pk: url = reverse('admin:%s_%s_change' % ( opts.app_label, opts.model_name), args=(quote(self.form.instance.pk),)) output = [self.widget.render(name, value, *args, **kwargs)] # name - input name, value, kwargs['attrs']['id'] input id for klass, js in self.widget_overrides: if isinstance(self.widget, klass): output.append('<script type="text/javascript">') output.append(js % (kwargs['attrs'].get('id', ''), url)) output.append('</script>') break return mark_safe(''.join(output))
[docs] def build_attrs(self, extra_attrs=None, **kwargs): "Helper function for building an attribute dictionary." self.attrs = self.widget.build_attrs(extra_attrs=None, **kwargs) return self.attrs
[docs] def value_from_datadict(self, data, files, name): value = self.widget.value_from_datadict(data, files, name) # MARKDOWN: enable next two lines to store markdown # if value and isinstance(self.widget, widgets.Textarea): # value = html2text(value) return value
[docs] def id_for_label(self, id_): return self.widget.id_for_label(id_)
[docs]class NumberInput(widgets.TextInput): input_type = 'number'
[docs]class LocationWidget(widgets.MultiWidget): DIRECTION_CHOICES = ( ('', '---'), ('N', 'N'), ('NNE', 'NNE'), ('NE', 'NE'), ('ENE', 'ENE'), ('E', 'E'), ('ESE', 'ESE'), ('SE', 'SE'), ('SSE', 'SSE'), ('S', 'S'), ('SSW', 'SSW'), ('SW', 'SW'), ('WSW', 'WSW'), ('W', 'W'), ('WNW', 'WNW'), ('NW', 'NW'), ('NNW', 'NNW'), ) def __init__(self, attrs=None): _widgets = ( widgets.TextInput(attrs={'class': 'locn_locality'}), NumberInput(attrs={'class': 'locn_distance', 'maxlength': '4'}), widgets.Select(attrs={'class': 'locn_direction'}, choices=LocationWidget.DIRECTION_CHOICES), widgets.TextInput(attrs={'class': 'locn_town'}), ) super(LocationWidget, self).__init__(_widgets, attrs)
[docs] def decompress(self, value): if value: value = value.split('|') if len(value) > 1: return [value[0] or None, value[1] or None, value[2] or None, value[3] or None] else: try: value[0].split("Within the locality of ")[1] return [value[0].split("Within the locality of ")[1], None, None, None] except IndexError: # Can't parse the string correctly, fall back to just using # the value. return [value[0], None, None, None] return [None, None, None, None]
[docs] def format_output(self, rendered_widgets): return rendered_widgets[0] + ' - ' + rendered_widgets[1] + 'km(s) ' +\ rendered_widgets[2] + ' of ' + rendered_widgets[3]
# TODO: this code should work for Django 1.6 # # class CheckboxFieldRenderer(widgets.CheckboxFieldRenderer): # def render(self): # output = [] # for widget in self: # output.append(format_html(force_text(widget))) # return mark_safe('\n'.join(output)) # # # class CheckboxSelectMultiple(widgets.CheckboxSelectMultiple): # renderer = CheckboxFieldRenderer # This code is from Django 1.5
[docs]class CheckboxSelectMultiple(SelectMultiple):
[docs] def render(self, name, value, attrs=None, choices=()): if value is None: value = [] has_id = attrs and 'id' in attrs final_attrs = self.build_attrs(attrs, name=name) output = [] # Normalize to strings str_values = set([force_text(v) for v in value]) for i, (option_value, option_label) in enumerate(chain(self.choices, choices)): # If an ID attribute was given, add a numeric index as a suffix, # so that the checkboxes don't all have the same ID attribute. if has_id: final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i)) label_for = format_html(' for="{0}"', final_attrs['id']) else: label_for = '' cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values) option_value = force_text(option_value) rendered_cb = cb.render(name, option_value) option_label = force_text(option_label) output.append(format_html('<label{0} class="checkbox">{1} {2}</label>', label_for, rendered_cb, option_label)) return mark_safe('\n'.join(output))
[docs] def id_for_label(self, id_): # See the comment for RadioSelect.id_for_label() if id_: id_ += '_0' return id_