Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

* made inlineform-ready

* default object result display now contains an admin-link to object
* readme-update
  • Loading branch information...
commit 39bb24e63c30354bd64e9de7c86005fe573b09d9 1 parent 7e692db
@schneck authored
View
22 README.md
@@ -41,25 +41,13 @@ You may pass gfkajax a whitelist containing allowed content types, in format "ap
You can tell gfkajax how to render selected objects. This is useful, if you offer e.g. images or videos as generic relations.
To do so, just add a "gfk_render()" method to your model, like:
-
- class MyModel(models.Model):
+
+
+
+ calss MyModel(models.Model):
def gfk_render(self):
return u'%s&nbsp;<img src="myimage.jpg" />&nbsp;' % self.mytitle
-
-
-If your form needs additional fields, you can pass them as.. "additional_fields":
-
- form = make_GfkAjaxForm(
- whitelist = [
- 'myapp.mymodel_lowercased'
- 'myappsecondapp.mysecondmodel_lowercased',
- ],
- additional_fields=[
- 'my_field': AutoCompleteSelectMultipleField('foo', required=False)
- ],
- )
- [..]
-
+
# Todo
* Related objects must be removable
View
16 forms.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+import uuid
from django import forms
from django.conf import settings
from django.contrib.contenttypes.generic import GenericForeignKey
@@ -13,6 +14,8 @@ def make_GfkAjaxForm(whitelist=None, additional_fields=None):
"""
class GfkAjaxForm(forms.ModelForm):
+ form_counter = 0
+
def __init__(self, *args, **kwargs):
super(GfkAjaxForm, self).__init__(*args, **kwargs)
@@ -24,9 +27,6 @@ def __init__(self, *args, **kwargs):
obj = getattr(self, 'instance', None)
-
- ATTRS_HIDDEN = {'class': 'gfkhidden'}
-
gfk_fields = []
virtual_fields = getattr(obj.__class__._meta, 'virtual_fields', [])
@@ -51,16 +51,22 @@ def __init__(self, *args, **kwargs):
self.gfk_fields = gfk_fields
+ # Generate unique id for this form
+ GfkAjaxForm.form_counter += 1
+ unique_form_id = 'form_%s' % GfkAjaxForm.form_counter
+
# Now replace widgets
for field in gfk_fields:
self.fields[field['ct_field']['name']].widget = GfkCtWidget(
- whitelist=whitelist
+ whitelist=whitelist,
+ unique_form_id = unique_form_id
)
+
self.fields[field['ct_field']['name']].label = field['verbose_name']
self.fields[field['fk_field']['name']].widget = GfkFkWidget(
- attrs=ATTRS_HIDDEN,
+ unique_form_id = unique_form_id,
append_input_name = u'%s_value' % field['ct_field']['name'],
append_input_value = field['fk_field']['name'],
)
View
83 templates/gfkajax/widget.js
@@ -1,76 +1,56 @@
$ = django.jQuery;
-var GFK_{{ name }} = {
+var GFK_{{ unique_form_id }} = {
init: function() {
// Hide original fields, and complete rows
- $(".form-row:has(.gfkhidden)").hide();
- $(".column").has(".gfkhidden").hide(); // For grappelli
- $(".column").has(".gfkhidden").prev().hide(); // For grappelli
- $("#id_{{ name }}").hide();
+ $(".form-row:has(.gfk_{{ unique_form_id }}_fk").hide();
+ $(".column").has(".gfk_{{ unique_form_id }}_fk").hide(); // For grappelli
+ $(".column").has(".gfk_{{ unique_form_id }}_fk").prev().hide(); // For grappelli
+ $(".gfk_{{ unique_form_id }}_lookup").attr('id', 'lookup_'+$('.gfk_{{ unique_form_id }}_fk').attr('id'));
- // Correct lookup node id
- $('#lookup_id_{{ name }}').attr('id', 'lookup_' + GFK_{{ name }}.get_fk_field().attr('id'));
+ old_fk_val_{{ unique_form_id}} = -1;
// If our widget changed the content type, copy new value to original value
- $(".gfk_widget_{{ name }}").change(function() {
+ $(".gfk_{{ unique_form_id }}_input").change(function() {
// Set original CT-field to valid value
- bits = GFK_{{ name }}.get_ct_split();
- $('#id_{{ name }}').val(bits[0]);
+ bits = GFK_{{ unique_form_id }}.get_ct_split();
+ $('.gfk_{{ unique_form_id }}_ct').val(bits[0]);
// Set FK-value to nothing
- GFK_{{ name }}.set_fk_value('');
+ $('.gfk_{{ unique_form_id }}_fk').val('');
// Set lookup-button to correct href
- GFK_{{ name }}.update_lookup_button();
+ GFK_{{ unique_form_id }}.update_lookup_button();
});
// Initially, retrieve object rendering and set lookup target
- GFK_{{ name }}.update_object();
- GFK_{{ name }}.update_lookup_button();
+ GFK_{{ unique_form_id }}.update_object();
+ GFK_{{ unique_form_id }}.update_lookup_button();
- window.setInterval("GFK_{{ name }}.monitor()", 2000);
+ window.setInterval("GFK_{{ unique_form_id }}.monitor()", 2000);
},
update_lookup_button: function() {
- bits = GFK_{{ name }}.get_ct_split();
+ bits = GFK_{{ unique_form_id }}.get_ct_split();
+ console.log(bits);
url = '/admin/' + bits[1] + '/' + bits[2] + '/?t=id';
- fk_field_id = GFK_{{ name }}.get_fk_field().attr('id');
- f = $('#lookup_'+fk_field_id);
- f.attr('href', url);
+ $('.gfk_{{ unique_form_id }}_lookup').attr('href', url);
},
monitor: function() {
- GFK_{{ name }}.update_object();
+ GFK_{{ unique_form_id }}.update_object();
},
- get_fk_field: function() {
- field_name = $('#id_{{ name }}_value');
- field_instance = $('#id_' + field_name.val());
- return field_instance;
- },
-
-
/*
* Since the ct-format is is_appname_model, return a splitted version
*/
get_ct_split: function() {
- return $(".gfk_widget_{{ name }}").val().split('_');
- },
-
- /*
- * Set hidden fk field and update object string
- */
- set_fk_value: function(v) {
-
- // Set value field to new value
- f = GFK_{{ name }}.get_fk_field();
- f.val(v);
- GFK_{{ name }}.update_object();
+ return $(".gfk_{{ unique_form_id }}_input").val().split('_');
},
/*
@@ -78,20 +58,25 @@ var GFK_{{ name }} = {
*/
update_object: function() {
- params = {
- 'ct': $('#id_{{ name }}').val(),
- 'fk': GFK_{{ name }}.get_fk_field().val()
- };
-
- $.post('/gfkajax/', params, function(data) {
- $('#gfk_{{ name }}_display').html(data);
- });
-
+ var ct_val = $('.gfk_{{ unique_form_id }}_ct').val();
+ var fk_val = $('.gfk_{{ unique_form_id }}_fk').val();
+
+ if ((old_fk_val_{{ unique_form_id }} == -1) || (old_fk_val_{{ unique_form_id }} != fk_val)) {
+ old_fk_val_{{ unique_form_id }} = fk_val;
+ params = {
+ 'ct': ct_val,
+ 'fk': fk_val
+ };
+ $('.gfk_{{ unique_form_id }}_display').html('Updating...')
+ $.post('/gfkajax/', params, function(data) {
+ $('.gfk_{{ unique_form_id }}_display').html(data);
+ });
+ }
}
};
$(document).ready(function() {
- GFK_{{ name }}.init();
+ GFK_{{ unique_form_id }}.init();
});
View
14 views.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+from django.core.urlresolvers import reverse
from django.http import HttpResponse
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.contenttypes.models import ContentType
@@ -20,6 +21,17 @@ def get_object(request):
return HttpResponse(mark_safe(fk_obj.gfk_render()))
else:
if hasattr(fk_obj, '__unicode__'):
- return HttpResponse(fk_obj.__unicode__())
+ try:
+ link_to_obj = u'<a target="_blank" href="%s">%s</a>' % (
+ reverse('admin:%s_%s_change' % (
+ ct_obj.app_label,
+ ct_obj.model_class().__name__.lower(),
+ ), args=(int(fk),)
+ ),
+ fk_obj.__unicode__()
+ )
+ except:
+ return fk_obj.__unicode__()
+ return HttpResponse(link_to_obj)
else:
return HttpResponse(str(fk_obj))
View
48 widgets.py
@@ -5,11 +5,21 @@
from django.utils.safestring import mark_safe
from django.contrib.contenttypes.models import ContentType
+def safe_int(i):
+ """
+ Take a parameter and try to convert it to an integer. Return a 0 if it's
+ not possible.
+ """
+ try:
+ return int(i)
+ except (ValueError, TypeError):
+ return 0
class GfkCtWidget(forms.TextInput):
def __init__(self, *args, **kwargs):
self.whitelist = kwargs.pop('whitelist', [])
+ self.unique_form_id = kwargs.pop('unique_form_id', '')
super(GfkCtWidget, self).__init__(*args, **kwargs)
@@ -19,7 +29,9 @@ def _get_js_code(self):
"""
t = loader.get_template('gfkajax/widget.js')
c = Context({
+ 'unique_form_id': self.unique_form_id,
'name': self.name,
+ 'name_clean': self.name.replace('-','_'),
'value': self.value,
})
return t.render(c)
@@ -39,6 +51,12 @@ def _get_ct_verbose_name(self, content_type):
def render(self, name, value, attrs=None):
+ style = attrs.get('style', '')
+ style += ' display:none;'
+
+ cls = attrs.get('class', '')
+ cls += ' gfk_%s_ct' % self.unique_form_id
+ attrs.update({'style': style, 'class': cls})
ret = super(GfkCtWidget, self).render(name, value, attrs)
self.name = name
@@ -55,7 +73,8 @@ def render(self, name, value, attrs=None):
continue
sel = u''
- if c.pk == value:
+
+ if safe_int(c.pk) == safe_int(value):
sel = u' selected'
if hasattr(c, 'model_class') and c.model_class() is not None:
@@ -67,22 +86,23 @@ def render(self, name, value, attrs=None):
options_str = ' \n'.join(options)
# Append Content-Type selectbox
- ret += u'<select class="gfk_widget_%(name)s" size="1" id="gfk_%(name)s">%(options)s</select>' % ({
- 'name': name,
+ ret += u'<select class="gfk_%(unique_form_id)s_input" size="1">%(options)s</select>' % ({
+ 'unique_form_id': self.unique_form_id,
'options': options_str
})
# Append lookup-button
- ret += u'<a href="%s" id="%s" onclick="return showRelatedObjectLookupPopup(this);"><img src="%simg/admin/selector-search.gif" style="margin-left:4px;" width="16" height="16"></a>' % (
+ ret += u'<a href="%s" class="%s" id="id_%s" onclick="return showRelatedObjectLookupPopup(this);"><img src="%simg/admin/selector-search.gif" style="margin-left:4px;" width="16" height="16"></a>' % (
'#',
- 'lookup_id_%s' % name,
+ 'gfk_%s_lookup' % self.unique_form_id,
+ 'lookup_gfk_%s_fk' % self.unique_form_id,
settings.ADMIN_MEDIA_PREFIX
)
# Append div for object display
- ret += u'<div class="gfk_display_object" id="gfk_%s_display" style="margin-left:8px;display: inline;"></div>' % (
- name,
+ ret += u'<div class="gfk_%s_display" style="margin-left:8px;display: inline;"></div>' % (
+ self.unique_form_id
)
# Append widget js-code
@@ -94,16 +114,22 @@ class GfkFkWidget(forms.TextInput):
def __init__(self, *args, **kwargs):
self.input_name = kwargs.pop('append_input_name', '')
self.input_value = kwargs.pop('append_input_value', '')
+ self.unique_form_id = kwargs.pop('unique_form_id', '')
+
super(GfkFkWidget, self).__init__(*args, **kwargs)
def render(self, name, value, attrs=None, **kwargs):
+ cls = attrs.get('class', '')
+ cls += ' gfk_%s_fk' % self.unique_form_id
+ attrs.update({'class': cls})
+
ret = super(GfkFkWidget, self).render(name, value, attrs)
# Append info field
- ret += u'<input type="hidden" name="%(name)s" id="id_%(name)s" value="%(value)s" />' % ({
- 'name': self.input_name,
- 'value': self.input_value
- })
+# ret += u'<input type="hidden" name="%(name)s" id="id_%(name)s" value="%(value)s" />' % ({
+# 'name': self.input_name,
+# 'value': self.input_value
+# })
return mark_safe(ret)#
Please sign in to comment.
Something went wrong with that request. Please try again.