Code

AJAXForeignKey: forms.py

File forms.py, 5.0 KB (added by Michael Axiak <axiak@…>, 7 years ago)

form field definition

Line 
1from django import oldforms
2from django.template.defaultfilters import addslashes
3import re
4
5get_id_re = re.compile('\D*(\d+)\D$')
6
7class AjaxForeignKeyFormField(oldforms.FormField):
8    def __init__(self, field_name, field,
9                 is_required=False, validator_list=None,
10                 member_name=None, ajax_func = None, width=None,
11                 help_text = None):
12
13        self.field_name  = field_name
14        self.field       = field
15        self.is_required = is_required
16        self.help_text   = help_text
17
18        if width is None:
19            self.width = '25em'
20        else:
21            self.width = width
22
23        if ajax_func is None:
24            self.ajax_func = 'ajax_autocomplete'
25        else:
26            self.ajax_func = ajax_func
27       
28        if validator_list is None:
29            validator_list = []
30
31        self.validator_list = validator_list
32
33    def extract_data(self, data):
34        return data.get(self.field.attname, '')
35
36
37    def render(self, data):
38        """
39        Renders the actual ajax widget.
40        """
41
42        init_val = data
43
44        if data:
45            objects = self.field.rel.to.objects.filter(pk = data)
46            if objects.count() == 1:
47                obj = objects[0]
48                if hasattr(obj, 'ajax_str'):
49                    init_val = obj.ajax_str() + " (%s)" % data
50                else:
51                    init_val = obj.__str__() + " (%s)" % data
52        else:
53            data = init_val = ''
54
55
56        fn = self.field_name
57        related_model = self.field.rel.to
58
59        model_module = related_model.__module__
60        model_name   = related_model.__name__
61       
62        javascript = """
63<script type="text/javascript">
64<!--
65
66document.getElementById("id_%s").value = "%s";
67
68var %s_data = new YAHOO.widget.DS_XHR("/admin/ajax_autocomplete/",
69                                      ['result','ajax_str','id']);
70
71%s_data.scriptQueryParam  = "ajax_data";
72%s_data.scriptQueryAppend = "model_module=%s&model_name=%s&ajax_func=%s";
73%s_data.connTimeout = 3000;
74
75var autocomp__%s = new YAHOO.widget.AutoComplete("id_%s","id_%s__container",%s_data);
76
77autocomp__%s.allowBrowserAutocomplete = false;
78//autocomp__%s.typeAhead = true;
79autocomp__%s.animVert = true;
80autocomp__%s.queryDelay = .2;
81autocomp__%s.maxCacheEntries = 60;
82autocomp__%s.animSpeed = .5;
83autocomp__%s.useShadow = true;
84autocomp__%s.useIFrame = true;
85
86
87YAHOO.util.Event.addListener(window, "load", function (e) {
88  var elements = YAHOO.util.Dom.getElementsByClassName('add-another', 'a');
89  for (var i=0; i<elements.length; i++) {
90    elements[i].style.display = 'none';
91  }
92  var elements = YAHOO.util.Dom.getElementsByClassName('form-row', 'div');
93  for (var i=0; i< elements.length; i++) {
94    elements[i].style.overflow = 'visible';
95    if (YAHOO.util.Dom.getElementsByClassName('yui_autocomplete','div', elements[i]).length > 0) {
96        elements[i].style.paddingBottom = '12.5em';
97    }
98  }
99});
100
101//-->
102</script>""" % \
103         (fn, addslashes(init_val),
104          fn, fn, fn, model_module, model_name, self.ajax_func,
105          fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn, fn)
106
107        css = """
108<style type="text/css">
109    /* Taken from Yahoo... */
110    #id_%s__yui_autocomplete {position:relative;width:%s;margin-bottom:1em;}/* set width of widget here*/
111    #id_%s__yui_autocomplete {z-index:0} /* for IE z-index of absolute divs inside relative divs issue */
112    #id_%s__yui_autocomplete input {_position:absolute;width:100%%;height:1.4em;z-index:0;} /* abs for ie quirks */
113    #id_%s__container {position:relative; width:100%%;}
114    #id_%s__container .yui-ac-content {position:absolute;width:100%%;border:1px solid #ccc;background:#fff;overflow:hidden;z-index:9050;}
115    #id_%s__container .yui-ac-shadow {position:absolute;margin:.3em;width:100%%;background:#eee;z-index:8000;}
116    #id_%s__container ul {padding:5px 0;width:100%%; list-item-type: none;margin-left: 0; padding-left: 0;z-index:9000;}
117    #id_%s__container li {padding:0 5px;cursor:default;white-space:nowrap;padding-left: 0; margin-left: 0;}
118    #id_%s__container li.yui-ac-highlight {background:#9cf;z-index:9000;}
119    #id_%s__container li.yui-ac-prehighlight {background:#CCFFFF;z-index:9000;}
120    .yui-ac-bd { padding:0; margin: 0; z-index:9000;}
121</style>
122""" % \
123        (fn,self.width,fn,fn,fn,fn,fn,fn,fn,fn,fn)
124
125        html = """
126<div class="container" style="position: relative;">
127<div class="yui_autocomplete" id="id_%s__yui_autocomplete">
128  <input type="text" id="id_%s" name="%s" class="vCharField" value="%s" />
129  <div id="id_%s__container" class="yui_container"></div>
130</div>
131</div>
132
133""" % (fn,fn,fn,addslashes(init_val),fn)
134
135        return css + html + javascript
136
137    def prepare(self, new_data):
138        id = new_data.get(self.field_name, None)
139        if id:
140            try:
141                id = int(id)
142            except ValueError:
143                match = get_id_re.match(id)
144                id = match.groups()[0]
145        new_data[self.field_name] = id