PageRenderTime 70ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 1ms

/ella/ellaadmin/widgets.py

https://github.com/rpgplanet/ella
Python | 234 lines | 213 code | 18 blank | 3 comment | 7 complexity | 1bf48cafd335f3186eff1f5fee3c309a MD5 | raw file
  1. from django import forms
  2. from django.conf import settings
  3. from django.contrib.admin import widgets
  4. from django.utils.safestring import mark_safe
  5. from django.utils.text import truncate_words
  6. from django.template import Context
  7. from django.template.loader import get_template
  8. from djangomarkup.widgets import RichTextAreaWidget
  9. from ella.ellaadmin.utils import admin_url
  10. from ella.core.models import Listing
  11. JS_EDITOR = 'js/editor.js'
  12. JS_SHOWDOWN = 'js/showdown.js'
  13. CLASS_RICHTEXTAREA = 'rich_text_area'
  14. CSS_RICHTEXTAREA = 'css/editor.css'
  15. JS_GENERIC_LOOKUP = 'js/admin/GenericRelatedObjectLookups.js'
  16. CLASS_TARGECT = 'target_ct'
  17. CLASS_TARGEID = 'target_id'
  18. JS_LISTING_CATEGORY = 'js/listing.js'
  19. CLASS_LISTING_CATEGORY = 'listing_category'
  20. JS_PLACEMENT_CATEGORY = 'js/placement_category.js'
  21. CLASS_PLACEMENT_CATEGORY = 'placement_category'
  22. # Generic suggester media files
  23. JS_GENERIC_SUGGEST = 'js/generic.suggest.js'
  24. CSS_GENERIC_SUGGEST = 'css/generic.suggest.css'
  25. # Fake windows
  26. JS_JQUERY_UI = 'js/jquery-ui.js'
  27. class ContentTypeWidget(forms.Select):
  28. " Custom widget adding a class to attrs. "
  29. def __init__(self, attrs={}):
  30. super(ContentTypeWidget, self).__init__(attrs={'class': CLASS_TARGECT})
  31. class ForeignKeyGenericRawIdWidget(forms.TextInput):
  32. " Custom widget adding a class to attrs. "
  33. class Media:
  34. js = (
  35. settings.ADMIN_MEDIA_PREFIX + JS_GENERIC_LOOKUP,
  36. )
  37. def __init__(self, attrs={}):
  38. super(ForeignKeyGenericRawIdWidget, self).__init__(attrs={'class': CLASS_TARGEID})
  39. class ExtendedRelatedFieldWidgetWrapper(widgets.RelatedFieldWidgetWrapper):
  40. 'Custom widget to be used in admin that includes name and link to the target.'
  41. def __call__(self, name, value, *args, **kwargs):
  42. rel_to = self.rel.to
  43. related_url = '../../../%s/%s/%s/' % (rel_to._meta.app_label, rel_to._meta.object_name.lower(), value)
  44. output = [self.render_func(name, value, *args, **kwargs)]
  45. if value and rel_to in self.admin_site._registry: # If the related object has an admin interface:
  46. output.append(u'<a href="%s">%s</a>' % (related_url, rel_to.objects.get(pk=value)))
  47. return mark_safe(u''.join(output))
  48. class RichTextAreaWidget(RichTextAreaWidget):
  49. 'Widget representing the RichTextEditor. '
  50. class Media:
  51. js = (
  52. settings.ADMIN_MEDIA_PREFIX + JS_EDITOR,
  53. settings.ADMIN_MEDIA_PREFIX + JS_SHOWDOWN,
  54. # FIXME: i don't know why js is not loaded in ListingCategoryWidget
  55. settings.ADMIN_MEDIA_PREFIX + JS_PLACEMENT_CATEGORY,
  56. settings.ADMIN_MEDIA_PREFIX + JS_LISTING_CATEGORY,
  57. )
  58. css = {
  59. 'screen': (settings.ADMIN_MEDIA_PREFIX + CSS_RICHTEXTAREA,),
  60. }
  61. def __init__(self, height=None, attrs={}):
  62. css_class = CLASS_RICHTEXTAREA
  63. if height:
  64. css_class += ' %s' % height
  65. super(RichTextAreaWidget, self).__init__(attrs={'class': css_class})
  66. class GenericSuggestAdminWidget(forms.TextInput):
  67. class Media:
  68. js = (settings.ADMIN_MEDIA_PREFIX + JS_JQUERY_UI, settings.ADMIN_MEDIA_PREFIX + JS_GENERIC_SUGGEST,)
  69. css = {'screen': (settings.ADMIN_MEDIA_PREFIX + CSS_GENERIC_SUGGEST,),}
  70. def __init__(self, data, attrs={}, **kwargs):
  71. self.db_field, self.ownmodel, self.lookups = data
  72. self.model = self.db_field.rel.to
  73. self.is_hidden = True
  74. super(self.__class__, self).__init__(attrs)
  75. def render(self, name, value, attrs=None):
  76. # related_url for standard lookup and clreate suggest_url for JS suggest
  77. related_url = '../../../%s/%s/' % (self.model._meta.app_label, self.model._meta.object_name.lower())
  78. suggest_params = '&amp;'.join([ 'f=%s' % l for l in self.lookups ]) + '&amp;q='
  79. suggest_url = related_url + 'suggest/?' + suggest_params
  80. if self.db_field.rel.limit_choices_to:
  81. url = '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in self.db_field.rel.limit_choices_to.items()])
  82. else:
  83. url = ''
  84. attrs['class'] = 'vForeignKeyRawIdAdminField hidden'
  85. suggest_css_class = 'GenericSuggestField'
  86. if not value:
  87. suggest_item = ''
  88. else:
  89. try:
  90. suggest_item = '<li class="suggest-selected-item">%s <a class="suggest-delete-link">x</a></li>' % getattr(self.model.objects.get(pk=value), self.lookups[0])
  91. except self.model.DoesNotExist:
  92. suggest_item = ''
  93. output = [super(GenericSuggestAdminWidget, self).render(name, value, attrs)]
  94. output.append('<ul class="%s">%s<li><input type="text" id="id_%s_suggest" rel="%s" /></li></ul> ' \
  95. % (suggest_css_class, suggest_item, name, suggest_url))
  96. # TODO: "id_" is hard-coded here. This should instead use the correct
  97. # API to determine the ID dynamically.
  98. output.append('<a href="%s%s" class="suggest-related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \
  99. (related_url, url, name))
  100. output.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % settings.ADMIN_MEDIA_PREFIX)
  101. return mark_safe(u''.join(output))
  102. class GenericSuggestAdminWidgetMultiple(forms.TextInput):
  103. class Media:
  104. js = (settings.ADMIN_MEDIA_PREFIX + JS_JQUERY_UI, settings.ADMIN_MEDIA_PREFIX + JS_GENERIC_SUGGEST,)
  105. css = {'screen': (settings.ADMIN_MEDIA_PREFIX + CSS_GENERIC_SUGGEST,),}
  106. def __init__(self, data, attrs={}, **kwargs):
  107. self.db_field, self.ownmodel, self.lookups = data
  108. self.model = self.db_field.rel.to
  109. self.is_hidden = True
  110. super(self.__class__, self).__init__(attrs)
  111. def render(self, name, value, attrs=None):
  112. # related_url for standard lookup and clreate suggest_url for JS suggest
  113. related_url = '../../../%s/%s/' % (self.model._meta.app_label, self.model._meta.object_name.lower())
  114. suggest_params = '&amp;'.join([ 'f=%s' % l for l in self.lookups ]) + '&amp;q='
  115. suggest_url = related_url + 'suggest/?' + suggest_params
  116. if self.db_field.rel.limit_choices_to:
  117. url = '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in self.db_field.rel.limit_choices_to.items()])
  118. else:
  119. url = ''
  120. attrs['class'] = 'vManyToManyRawIdAdminField hidden'
  121. suggest_css_class = 'GenericSuggestFieldMultiple'
  122. if not value:
  123. suggest_items = ''
  124. else:
  125. if not isinstance(value, (list, tuple)):
  126. value = [int(v) for v in value.split(',')]
  127. try:
  128. suggest_items = ''.join('<li class="suggest-selected-item">%s <a class="suggest-delete-link">x</a></li>' % \
  129. getattr(i, self.lookups[0]) for i in self.model.objects.filter(pk__in=value))
  130. value = ','.join(["%s" % v for v in value])
  131. except self.model.DoesNotExist:
  132. suggest_items = ''
  133. output = [super(GenericSuggestAdminWidgetMultiple, self).render(name, value, attrs)]
  134. output.append('<ul class="%s">%s<li><input type="text" id="id_%s_suggest" rel="%s" /></li></ul> ' \
  135. % (suggest_css_class, suggest_items, name, suggest_url))
  136. # TODO: "id_" is hard-coded here. This should instead use the correct
  137. # API to determine the ID dynamically.
  138. output.append('<a href="%s%s" class="suggest-related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \
  139. (related_url, url, name))
  140. output.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % settings.ADMIN_MEDIA_PREFIX)
  141. return mark_safe(u''.join(output))
  142. class ListingCategoryWidget(forms.Select):
  143. """register javascript for duplicating main category to edit inline listing"""
  144. class Media:
  145. js = (
  146. settings.ADMIN_MEDIA_PREFIX + JS_LISTING_CATEGORY,
  147. )
  148. def __init__(self, attrs={}):
  149. super(ListingCategoryWidget, self).__init__(attrs={'class': CLASS_LISTING_CATEGORY})
  150. class IncrementWidget(forms.TextInput):
  151. 'Self incrementing widget.'
  152. class Media:
  153. js = (
  154. settings.ADMIN_MEDIA_PREFIX + 'js/increment.js',
  155. )
  156. def __init__(self, attrs={}):
  157. super(IncrementWidget, self).__init__(attrs={'class': 'increment'})
  158. class ParagraphInputWidget(forms.HiddenInput):
  159. """show value without simpe way editing it"""
  160. def render(self, name, value, attrs=None):
  161. return mark_safe(u'<p>%s</p>%s' % (value, super(ParagraphInputWidget, self).render(name, value, attrs)))
  162. class ForeignKeyRawIdWidget(widgets.ForeignKeyRawIdWidget):
  163. def label_for_value(self, value):
  164. obj = self.rel.to.objects.get(pk=value)
  165. label = truncate_words(obj, 14)
  166. adm = admin_url(obj)
  167. return '&nbsp;<a href="%s">%s</a>' % (adm, label)
  168. """ """
  169. class ListingCustomWidget(forms.SelectMultiple):
  170. def __init__(self, attrs=None, choices=(), *args, **kwargs):
  171. #attrs['class'] = 'listings'
  172. # TODO bug? Ask Honza, if selected choices should be provided in args, kwargs, somewhere..
  173. if not attrs or 'class' not in attrs:
  174. my_attrs = {'class': 'listings'}
  175. else:
  176. my_attrs = attrs
  177. super(ListingCustomWidget, self).__init__(attrs=my_attrs, choices=choices)
  178. def render(self, name, value, attrs=None, choices=()):
  179. cx = Context()
  180. cx['ADMIN_MEDIA_PREFIX'] = settings.ADMIN_MEDIA_PREFIX
  181. cx['id_prefix'] = name
  182. cx['verbose_name_publish_from'] = Listing._meta.get_field('publish_from').verbose_name.__unicode__()
  183. cx['choices'] = choices or self.choices
  184. if type(value) == dict:
  185. # modifying existing object, so value is dict containing Listings and selected category IDs
  186. # cx['selected'] = Category.objects.filter(pk__in=value['selected_categories']).values('id') or []
  187. cx['listings'] = list(value['listings']) or []
  188. tpl = get_template('admin/widget/listing_custom.html')
  189. return mark_safe(tpl.render(cx))
  190. """ """