+from django.conf import settings
from django.contrib import admin
from django.contrib.contenttypes import generic
from philo.models import Tag, Attribute
ct_fk_field = 'entity_object_id'
model = Attribute
extra = 1
- template = 'admin/philo/edit_inline/tabular_attribute.html'
allow_add = True
classes = COLLAPSE_CLASSES
form = AttributeForm
formset = AttributeInlineFormSet
- exclude = ['value_object_id']
+ fields = ['key', 'value_content_type']
+ if 'grappelli' in settings.INSTALLED_APPS:
+ template = 'admin/philo/edit_inline/grappelli_tabular_attribute.html'
+ else:
+ template = 'admin/philo/edit_inline/tabular_attribute.html'
class EntityAdmin(admin.ModelAdmin):
+from django.conf import settings
from django.contrib import admin
from django import forms
from philo.admin.base import COLLAPSE_CLASSES
formset = ContentletInlineFormSet
form = ContentletForm
can_delete = False
- template = 'admin/philo/edit_inline/tabular_container.html'
+ classes = ('collapse-open', 'collapse','open')
+ if 'grappelli' in settings.INSTALLED_APPS:
+ template = 'admin/philo/edit_inline/grappelli_tabular_container.html'
+ else:
+ template = 'admin/philo/edit_inline/tabular_container.html'
class ContentReferenceInline(admin.StackedInline):
formset = ContentReferenceInlineFormSet
form = ContentReferenceForm
can_delete = False
- template = 'admin/philo/edit_inline/tabular_container.html'
+ classes = ('collapse-open', 'collapse','open')
+ if 'grappelli' in settings.INSTALLED_APPS:
+ template = 'admin/philo/edit_inline/grappelli_tabular_container.html'
+ else:
+ template = 'admin/philo/edit_inline/tabular_container.html'
class PageAdmin(ViewAdmin):
def add_item(self, feed, obj, kwargs=None):
defaults = {
'title': obj.title,
- 'author_name': ', '.join(obj.authors),
+ 'author_name': ', '.join([author.get_full_name() for author in obj.authors.all()]),
'pubdate': obj.date,
'description': obj.lede or obj.full_text,
'categories': [tag.name for tag in obj.tags.all()]
return False
def get_path(self, root=None, pathsep='/', field='slug'):
- if root is not None:
- if not self.has_ancestor(root):
- raise AncestorDoesNotExist(root)
- path = ''
- parent = self
- while parent and parent != root:
- path = getattr(parent, field, '?') + pathsep + path
- parent = parent.parent
- return path
- else:
- path = getattr(self, field, '?')
- parent = self.parent
- while parent and parent != root:
- path = getattr(parent, field, '?') + pathsep + path
- parent = parent.parent
- return path
+ if root is not None and not self.has_ancestor(root):
+ raise AncestorDoesNotExist(root)
+
+ path = getattr(self, field, '?')
+ parent = self.parent
+ while parent and parent != root:
+ path = getattr(parent, field, '?') + pathsep + path
+ parent = parent.parent
+ return path
path = property(get_path)
def __unicode__(self):
from django.http import HttpResponse, HttpResponseServerError, HttpResponseRedirect
from django.core.exceptions import ViewDoesNotExist
from django.core.servers.basehttp import FileWrapper
-from django.core.urlresolvers import resolve, clear_url_caches, reverse
+from django.core.urlresolvers import resolve, clear_url_caches, reverse, NoReverseMatch
from django.template import add_to_builtins as register_templatetags
from inspect import getargspec
from philo.exceptions import MIDDLEWARE_NOT_CONFIGURED
from philo.models.base import TreeEntity, Entity, QuerySetMapper, register_value_model
from philo.utils import ContentTypeSubclassLimiter
from philo.validators import RedirectValidator
-from philo.exceptions import ViewDoesNotProvideSubpaths, AncestorDoesNotExist
+from philo.exceptions import ViewCanNotProvideSubpath, ViewDoesNotProvideSubpaths, AncestorDoesNotExist
from philo.signals import view_about_to_render, view_finished_rendering
accepts_subpath = False
def get_subpath(self, obj):
- raise ViewDoesNotProvideSubpaths
+ if not self.accepts_subpath:
+ raise ViewDoesNotProvideSubpaths
+
+ view_name, args, kwargs = self.get_reverse_params(obj)
+ try:
+ return reverse(view_name, args=args, kwargs=kwargs, urlconf=self)
+ except NoReverseMatch:
+ raise ViewCanNotProvideSubpath
+
+ def get_reverse_params(self, obj):
+ """This method should return a view_name, args, kwargs tuple suitable for reversing a url for the given obj using self as the urlconf."""
+ raise NotImplementedError("View subclasses must implement get_reverse_params to support subpaths.")
def attributes_with_node(self, node):
return QuerySetMapper(self.attribute_set, passthrough=node.attributes)
def urlpatterns(self, obj):
raise NotImplementedError("MultiView subclasses must implement urlpatterns.")
- def get_reverse_params(self, obj):
- """This method should return a view_name, args, kwargs tuple suitable for reversing a url for the given obj using self as the urlconf."""
- raise NotImplementedError("MultiView subclasses must implement get_subpath.")
-
def actually_render_to_response(self, request, extra_context=None):
clear_url_caches()
subpath = request.node.subpath
--- /dev/null
+{% load i18n adminmedia %}
+
+<!-- group -->
+<div class="group tabular{% if inline_admin_formset.opts.classes %} {{ inline_admin_formset.opts.classes|join:" " }}{% endif %}"
+ id="{{ inline_admin_formset.formset.prefix }}-group" >
+ <h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
+ <ul class="tools">
+ <li class="add-handler-container"><a href="javascript://" class="icon add-handler" title="{% trans 'Add Another' %}"> </a></li>
+ </ul>
+ {{ inline_admin_formset.formset.management_form }}
+ {{ inline_admin_formset.formset.non_form_errors }}
+ <!-- container -->
+ <div class="module table">
+ <div class="module thead">
+ <div class="tr">
+ {% for field in inline_admin_formset.fields %}
+ {% if not field.widget.is_hidden %}
+ <div class="th {{ field.label|lower }}{% if field.required %} required{% endif %}">{{ field.label|capfirst }}</div>
+ {% endif %}
+ {% endfor %}
+ <div class="th content_type">Content type</div>
+ <div class="th value">Value</div>
+ {% if inline_admin_formset.formset.can_delete %}<div class="th"> </div>{% endif %}
+ </div>
+ </div>
+ {% for inline_admin_form in inline_admin_formset %}
+ <!-- element -->
+ <div class="module tbody{% if inline_admin_form.original or inline_admin_form.show_url %} has_original{% endif %}{% if forloop.last %} empty-form{% endif %}"
+ id="{{ inline_admin_formset.formset.prefix }}{% if not forloop.last %}{{ forloop.counter0 }}{% else %}-empty{% endif %}">
+ {% if inline_admin_form.form.non_field_errors %}
+ <ul class="errorlist"><li>{{ inline_admin_form.form.non_field_errors }}</li></ul>
+ {% endif %}
+ <h3 style="display: none;"><b>{{ inline_admin_formset.opts.verbose_name|title }} #{{ forloop.counter }}</b> {% if inline_admin_form.original %} {{ inline_admin_form.original }}{% endif %}</h3>
+ {% spaceless %}
+ {% for fieldset in inline_admin_form %}
+ {% for line in fieldset %}
+ {% for field in line %}
+ {% if field.is_hidden %} {{ field.field }} {% endif %}
+ {% endfor %}
+ {% endfor %}
+ {% endfor %}
+ {% endspaceless %}
+ <div class="tr">
+ {% for fieldset in inline_admin_form %}
+ {% for line in fieldset %}
+ {% for field in line %}
+ <div class="td {{ field.field.name }} {% if field.field.errors %} error{% endif %}">
+ {% if field.is_readonly %}
+ <p>{{ field.contents }}</p>
+ {% else %}
+ {{ field.field }}
+ {{ field.field.errors.as_ul }}
+ {% endif %}
+ </div>
+ {% endfor %}
+ {% endfor %}
+ {% endfor %}
+ {% with inline_admin_form.form.content_type as field %}<div class="td {{ field.name }}{% if field.errors %} error{% endif %}">{{ field }}{{ field.errors.as_ul }}</div>{% endwith %}
+ {% with inline_admin_form.form.value as field %}<div class="td {{ field.name }}{% if field.errors %} error{% endif %}">{{ field }}{{ field.errors.as_ul }}</div>{% endwith %}
+ <div class="td tools">
+ {% spaceless %}
+ <ul class="tools">
+ {% if inline_admin_form.show_url %}<li class="viewsite-link-container"><a href="../../../r/{{ inline_admin_form.original_content_type_id }}/{{ inline_admin_form.original.id }}/" class="icon viewsite-link" title="{% trans 'View on Site' %}"> </a></li>{% endif %}
+ {% if inline_admin_formset.opts.sortable_field_name %}
+ <li class="drag-handler-container"><a href="javascript://" class="icon drag-handler" title="{% trans 'Move Item' %}"></a></li>
+ {% endif %}
+ {% if inline_admin_formset.formset.can_delete %}<li class="delete-handler-container">{{ inline_admin_form.deletion_field.field }}<a href="javascript://" class="icon {% if inline_admin_form.original %}delete-handler{% else %}remove-handler{% endif %}" title="{% trans 'Remove' %}"> </a>{% endif %}
+ </ul>
+ {% endspaceless %}
+ </div>
+ {{ inline_admin_form.fk_field.field }}
+ {% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
+ </div>
+ </div>
+ {% endfor %}
+ </div>
+ <div class="module add-item">
+ <a href="javascript://" class="add-handler">{% blocktrans with inline_admin_formset.opts.verbose_name|title as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}</a>
+ <ul class="tools">
+ <li class="add-handler-container"><a href="javascript://" class="icon add-handler" title="{% trans 'Add Item' %}"> </a></li>
+ </ul><br clear="all" />
+ </div>
+</div>
+
+<script type="text/javascript">
+(function($) {
+ $(document).ready(function($) {
+
+ $("#{{ inline_admin_formset.formset.prefix }}-group").inline({
+ prefix: "{{ inline_admin_formset.formset.prefix }}",
+ deleteCssClass: "delete-handler",
+ emptyCssClass: "empty-form",
+ onAdded: tabular_onAdded
+ });
+
+{% if inline_admin_formset.opts.sortable_field_name %}
+ /**
+ * sortable inlines
+ * uses onAdded() and onRemoved() of inline() call above
+ * uses sortable_updateFormIndex() and is_form_filled() from change_from.html
+ */
+
+ // hide sortable_field(_name) from form
+ // hide div.td.{{ field.name }}
+ var position_nodes = $("#{{ inline_admin_formset.formset.prefix }}-group").find("div.td.{{ inline_admin_formset.opts.sortable_field_name }}");
+ position_nodes.hide();
+
+ // hide its header (div.th) too (hard)
+ // "div.th.{{ inline_admin_formset.opts.sortable_field_name }}" is not correct because
+ // its div.th.<field.label> (and not name, see line#18).
+
+ // so let's get the "position/idx" the first position div
+ var tabular_row = position_nodes.first().parent().children("div.td");
+ // get the "position" (== i) in the "table"
+ for (var i = 0; i < tabular_row.length; i++) {
+ if ($(tabular_row[i]).hasClass("{{ inline_admin_formset.opts.sortable_field_name }}")) break;
+ }
+ // we have the same order in the header of the "table"
+ // so delete the div at the "position" (== i)
+ var position_header = $("#{{ inline_admin_formset.formset.prefix }}-group").find("div.th")[i];
+ // and hide
+ $(position_header).hide()
+
+ {% if errors %}
+ // sort inline
+ var container = $("#{{ inline_admin_formset.formset.prefix }}-group > div.table"),
+ dynamic_forms = container.find("div.dynamic-form"),
+ updated = false,
+ curr_form,
+ real_pos;
+
+ // loop thru all inline forms
+ for (var i = 0; i < dynamic_forms.length; i++) {
+ curr_form = $(dynamic_forms[i]);
+ // the real position according to the sort_field(_name)
+ real_pos = curr_form.find("div.{{ inline_admin_formset.opts.sortable_field_name }}").find("input").val();
+ // if there is none it's an empty inline (=> we are at the end)
+ // TODO: klemens: maybe buggy. try continue?
+ if (!real_pos) continue;
+
+ real_pos = parseInt(real_pos, 10);
+
+ // check if real position is not equal to the CURRENT position in the dom
+ if (real_pos != container.find("div.dynamic-form").index(curr_form)) {
+ // move to correct postition
+ curr_form.insertBefore(container.find("div.dynamic-form")[real_pos]);
+ // to update the inline lables
+ updated = true;
+ }
+ }
+
+ {% endif %}
+
+ $("#{{ inline_admin_formset.formset.prefix }}-group > div.table").sortable({
+ // drag&drop the inlines with the drag-handler only
+ handle: "a.drag-handler",
+ // very scary magic after drap&drop operations
+ // pretty similar to inline() widget's removeHandler()
+ // but removeHandler() can remove the current form and just reorder the rest
+ // if we would do the same after drag&drop we would loose some form values
+ // because while looping inputs would have the same names and maybe overwrite each other.
+ placeholder: 'ui-sortable-placeholder',
+ forcePlaceholderSize: true,
+ items: "div.dynamic-form",
+ axis: "y",
+ start: function(evt, ui) {
+ ui.item.hide()
+ ui.placeholder.height(ui.placeholder.height()-4);
+ //sadly we have to do this every time we start dragging
+ var template = "<div class='tr'>",
+ // minus 1 because we don't need the "sortable_field_name row"
+ len = ui.item.find("div.tr").children("div.td").length - 1;
+
+ for (var i = 0; i < len; i++) {
+ template += "<div class='td'></div>"
+ }
+
+ template += "</div>"
+ ui.placeholder.addClass("tbody module").append(template);
+ },
+ update: function(evt, ui) {
+ ui.item.show();
+ },
+ appendTo: 'body',
+ forceHelperSize: true,
+ containment: '#{{ inline_admin_formset.formset.prefix }}-group > div.table',
+ tolerance: 'pointer',
+ helper: function(evt, elem) {
+ var helper = $("<div class='module table' />");
+ helper.html(elem.clone());
+ return helper;
+ },
+ });
+
+ // sets the new positions onSubmit (0 - n)
+ $("#{{ opts.module_name }}_form").bind("submit", function(){
+ var forms = $("#{{ inline_admin_formset.formset.prefix }}-group").find("div.dynamic-form"),
+ form,
+ idx = 0;
+ for (var i = 0; i < forms.length; i++) {
+ form = $(forms[i]);
+
+ if (is_form_filled(form)) {
+ form.find("div.{{ inline_admin_formset.opts.sortable_field_name }}").find("input").val(idx);
+ idx++;
+ }
+ }
+ });
+
+{% endif %}
+
+ });
+})(django.jQuery);
+</script>
+
--- /dev/null
+{% load i18n adminmedia %}
+
+<!-- group -->
+{{ inline_admin_formset.formset.management_form }}
+{% comment %}Don't render the formset at all if there aren't any forms.{% endcomment %}
+{% if inline_admin_formset.formset.forms %}
+ <fieldset class="module{% if inline_admin_formset.opts.classes %} {{ inline_admin_formset.opts.classes|join:" " }}{% endif %}">
+ <h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2>
+ {{ inline_admin_formset.formset.non_form_errors }}
+ {% for inline_admin_form in inline_admin_formset %}
+ {% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
+ {{ inline_admin_form.fk_field.field }}
+ {% spaceless %}
+ {% for fieldset in inline_admin_form %}
+ {% for line in fieldset %}
+ {% for field in line %}
+ {% if field.is_hidden %} {{ field.field }} {% endif %}
+ {% endfor %}
+ {% endfor %}
+ {% endfor %}{% endspaceless %}
+ <div class="row cells-{{ inline_admin_form.fields|length }}{% if not inline_admin_form.fields|length_is:"2" %} cells{% endif %}{% if inline_admin_form.errors %} errors{% endif %} {% for field in inline_admin_form %}{{ field.field.name }} {% endfor %}{% if forloop.last %} empty-form{% endif %}">
+ <div{% if not inline_admin_form.fields|length_is:"2" %} class="cell"{% endif %}>
+ <div class="column span-4"><label class='required' for="{{ inline_admin_form.form.content.auto_id }}{{ inline_admin_form.form.content_id.auto_id }}">{{ inline_admin_form.form.verbose_name|capfirst }}:</label>{{ inline_admin_form.form.name.as_hidden }}</div>
+ {% for fieldset in inline_admin_form %}{% for line in fieldset %}{% for field in line %}
+ {% if field.field.name != 'name' %}
+ <div class="column span-flexible">
+ {% if field.is_readonly %}
+ <p class="readonly">{{ field.contents }}</p>
+ {% else %}
+ {{ field.field }}
+ {% endif %}
+ {{ inline_admin_form.errors }}
+ {% if field.field.field.help_text %}
+ <p class="help">{{ field.field.field.help_text|safe }}</p>
+ {% endif %}
+ </div>
+ {% endif %}
+ {% endfor %}{% endfor %}{% endfor %}
+ </div>
+ </div>
+ {% endfor %}
+ </fieldset>
+{% endif %}