Added complete support for dynamic form to add extra authors fields to proceedings form and added initial support for autocompletion based on user names for authors.
authorMadhusudan.C.S <madhusudancs@gmail.com>
Fri, 15 Jan 2010 20:15:00 +0530
changeset 93 7c27e8d9231d
parent 92 3743275f7291
child 103 852015a7eead
Added complete support for dynamic form to add extra authors fields to proceedings form and added initial support for autocompletion based on user names for authors.
project/kiwipycon/proceedings/forms.py
project/kiwipycon/proceedings/views.py
project/static/img/shadow.png
project/static/jquery/jquery.autocomplete-min.js
project/static/jquery/jquery.autocomplete.css
project/templates/proceedings/submit.html
project/urls.py
--- a/project/kiwipycon/proceedings/forms.py	Thu Jan 14 21:07:03 2010 +0530
+++ b/project/kiwipycon/proceedings/forms.py	Fri Jan 15 20:15:00 2010 +0530
@@ -26,5 +26,10 @@
         "'Abstract' and other with a heading 'Body'.")
 
     authors = forms.CharField(
-        required=False, label=u'Author',
+        required=False, label=u'Author(s)',
         help_text=u'User ID of the author.')
+
+    attachment = forms.FileField(
+        required=False, label=u'Attachments',
+        help_text=u'Attachments like images that must used in your paper '
+        'for rendering.')
--- a/project/kiwipycon/proceedings/views.py	Thu Jan 14 21:07:03 2010 +0530
+++ b/project/kiwipycon/proceedings/views.py	Fri Jan 15 20:15:00 2010 +0530
@@ -1,8 +1,11 @@
 # -*- coding: utf-8 -*-
+import json
 
 from django.contrib.auth import login
 from django.contrib.auth.decorators import login_required
 from django.contrib.auth.forms import AuthenticationForm
+from django.contrib.auth.models import User
+from django.http import HttpResponse
 from django.shortcuts import render_to_response
 from django.template import RequestContext
 
@@ -92,3 +95,19 @@
         })
 
     return render_to_response(template, context)
+
+
+def getUsers(request):
+    """View function called by autocomplete jQuery plugin to get
+    the user names.
+    """
+
+    query = request.GET['query']
+    suggestions = User.objects.filter(username__startswith=query)
+    
+    suggest_data = {
+        'query': query,
+        'suggestions':[user.username for user in suggestions],
+        }
+
+    return HttpResponse(json.dumps(suggest_data))
\ No newline at end of file
Binary file project/static/img/shadow.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project/static/jquery/jquery.autocomplete-min.js	Fri Jan 15 20:15:00 2010 +0530
@@ -0,0 +1,10 @@
+/*
+*  Ajax Autocomplete for jQuery, version 1.1
+*  (c) 2009 Tomas Kirda
+*
+*  Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
+*  For details, see the web site: http://www.devbridge.com/projects/autocomplete/jquery/
+*
+*  Last Review: 09/27/2009
+*/
+(function($){var reEscape=new RegExp("(\\"+["/",".","*","+","?","|","(",")","[","]","{","}","\\"].join("|\\")+")","g");function fnFormatResult(value,data,currentValue){var pattern="("+currentValue.replace(reEscape,"\\$1")+")";return value.replace(new RegExp(pattern,"gi"),"<strong>$1</strong>");}function Autocomplete(el,options){this.el=$(el);this.el.attr("autocomplete","off");this.suggestions=[];this.data=[];this.badQueries=[];this.selectedIndex=-1;this.currentValue=this.el.val();this.intervalId=0;this.cachedResponse=[];this.onChangeInterval=null;this.ignoreValueChange=false;this.serviceUrl=options.serviceUrl;this.isLocal=false;this.options={autoSubmit:false,minChars:1,maxHeight:300,deferRequestBy:0,width:0,highlight:true,params:{},fnFormatResult:fnFormatResult,delimiter:null,zIndex:9999};this.initialize();this.setOptions(options);}$.fn.autocomplete=function(options){return new Autocomplete(this.get(0),options);};Autocomplete.prototype={killerFn:null,initialize:function(){var me,uid,autocompleteElId;me=this;uid=new Date().getTime();autocompleteElId="Autocomplete_"+uid;this.killerFn=function(e){if($(e.target).parents(".autocomplete").size()===0){me.killSuggestions();me.disableKillerFn();}};if(!this.options.width){this.options.width=this.el.width();}this.mainContainerId="AutocompleteContainter_"+uid;$('<div id="'+this.mainContainerId+'" style="position:absolute;z-index:9999;"><div class="autocomplete-w1"><div class="autocomplete" id="'+autocompleteElId+'" style="display:none; width:300px;"></div></div></div>').appendTo("body");this.container=$("#"+autocompleteElId);this.fixPosition();if(window.opera){this.el.keypress(function(e){me.onKeyPress(e);});}else{this.el.keydown(function(e){me.onKeyPress(e);});}this.el.keyup(function(e){me.onKeyUp(e);});this.el.blur(function(){me.enableKillerFn();});this.el.focus(function(){me.fixPosition();});},setOptions:function(options){var o=this.options;$.extend(o,options);if(o.lookup){this.isLocal=true;if($.isArray(o.lookup)){o.lookup={suggestions:o.lookup,data:[]};}}$("#"+this.mainContainerId).css({zIndex:o.zIndex});this.container.css({maxHeight:o.maxHeight+"px",width:o.width});},clearCache:function(){this.cachedResponse=[];this.badQueries=[];},disable:function(){this.disabled=true;},enable:function(){this.disabled=false;},fixPosition:function(){var offset=this.el.offset();$("#"+this.mainContainerId).css({top:(offset.top+this.el.innerHeight())+"px",left:offset.left+"px"});},enableKillerFn:function(){var me=this;$(document).bind("click",me.killerFn);},disableKillerFn:function(){var me=this;$(document).unbind("click",me.killerFn);},killSuggestions:function(){var me=this;this.stopKillSuggestions();this.intervalId=window.setInterval(function(){me.hide();me.stopKillSuggestions();},300);},stopKillSuggestions:function(){window.clearInterval(this.intervalId);},onKeyPress:function(e){if(this.disabled||!this.enabled){return;}switch(e.keyCode){case 27:this.el.val(this.currentValue);this.hide();break;case 9:case 13:if(this.selectedIndex===-1){this.hide();return;}this.select(this.selectedIndex);if(e.keyCode===9){return;}break;case 38:this.moveUp();break;case 40:this.moveDown();break;default:return;}e.stopImmediatePropagation();e.preventDefault();},onKeyUp:function(e){if(this.disabled){return;}switch(e.keyCode){case 38:case 40:return;}clearInterval(this.onChangeInterval);if(this.currentValue!==this.el.val()){if(this.options.deferRequestBy>0){var me=this;this.onChangeInterval=setInterval(function(){me.onValueChange();},this.options.deferRequestBy);}else{this.onValueChange();}}},onValueChange:function(){clearInterval(this.onChangeInterval);this.currentValue=this.el.val();var q=this.getQuery(this.currentValue);this.selectedIndex=-1;if(this.ignoreValueChange){this.ignoreValueChange=false;return;}if(q===""||q.length<this.options.minChars){this.hide();}else{this.getSuggestions(q);}},getQuery:function(val){var d,arr;d=this.options.delimiter;if(!d){return $.trim(val);}arr=val.split(d);return $.trim(arr[arr.length-1]);},getSuggestionsLocal:function(q){var ret,arr,len,val,i;arr=this.options.lookup;len=arr.suggestions.length;ret={suggestions:[],data:[]};q=q.toLowerCase();for(i=0;i<len;i++){val=arr.suggestions[i];if(val.toLowerCase().indexOf(q)===0){ret.suggestions.push(val);ret.data.push(arr.data[i]);}}return ret;},getSuggestions:function(q){var cr,me;cr=this.isLocal?this.getSuggestionsLocal(q):this.cachedResponse[q];if(cr&&$.isArray(cr.suggestions)){this.suggestions=cr.suggestions;this.data=cr.data;this.suggest();}else{if(!this.isBadQuery(q)){me=this;me.options.params.query=q;$.get(this.serviceUrl,me.options.params,function(txt){me.processResponse(txt);},"text");}}},isBadQuery:function(q){var i=this.badQueries.length;while(i--){if(q.indexOf(this.badQueries[i])===0){return true;}}return false;},hide:function(){this.enabled=false;this.selectedIndex=-1;this.container.hide();},suggest:function(){if(this.suggestions.length===0){this.hide();return;}var me,len,div,f,v,i,s,mOver,mClick;me=this;len=this.suggestions.length;f=this.options.fnFormatResult;v=this.getQuery(this.currentValue);mOver=function(xi){return function(){me.activate(xi);};};mClick=function(xi){return function(){me.select(xi);};};this.container.hide().empty();for(i=0;i<len;i++){s=this.suggestions[i];div=$((me.selectedIndex===i?'<div class="selected"':"<div")+' title="'+s+'">'+f(s,this.data[i],v)+"</div>");div.mouseover(mOver(i));div.click(mClick(i));this.container.append(div);}this.enabled=true;this.container.show();},processResponse:function(text){var response;try{response=eval("("+text+")");}catch(err){return;}if(!$.isArray(response.data)){response.data=[];}this.cachedResponse[response.query]=response;if(response.suggestions.length===0){this.badQueries.push(response.query);}if(response.query===this.getQuery(this.currentValue)){this.suggestions=response.suggestions;this.data=response.data;this.suggest();}},activate:function(index){var divs,activeItem;divs=this.container.children();if(this.selectedIndex!==-1&&divs.length>this.selectedIndex){$(divs.get(this.selectedIndex)).attr("class","");}this.selectedIndex=index;if(this.selectedIndex!==-1&&divs.length>this.selectedIndex){activeItem=divs.get(this.selectedIndex);$(activeItem).attr("class","selected");}return activeItem;},deactivate:function(div,index){div.className="";if(this.selectedIndex===index){this.selectedIndex=-1;}},select:function(i){var selectedValue,f;selectedValue=this.suggestions[i];if(selectedValue){this.el.val(selectedValue);if(this.options.autoSubmit){f=this.el.parents("form");if(f.length>0){f.get(0).submit();}}this.ignoreValueChange=true;this.hide();this.onSelect(i);}},moveUp:function(){if(this.selectedIndex===-1){return;}if(this.selectedIndex===0){this.container.children().get(0).className="";this.selectedIndex=-1;this.el.val(this.currentValue);return;}this.adjustScroll(this.selectedIndex-1);},moveDown:function(){if(this.selectedIndex===(this.suggestions.length-1)){return;}this.adjustScroll(this.selectedIndex+1);},adjustScroll:function(i){var activeItem,offsetTop,upperBound,lowerBound;activeItem=this.activate(i);offsetTop=activeItem.offsetTop;upperBound=this.container.scrollTop();lowerBound=upperBound+this.options.maxHeight-25;if(offsetTop<upperBound){this.container.scrollTop(offsetTop);}else{if(offsetTop>lowerBound){this.container.scrollTop(offsetTop-this.options.maxHeight+25);}}},onSelect:function(i){var me,onSelect,getValue,s,d;me=this;onSelect=me.options.onSelect;getValue=function(value){var del,currVal,arr;del=me.options.delimiter;if(!del){return value;}currVal=me.currentValue;arr=currVal.split(del);if(arr.length===1){return value;}return currVal.substr(0,currVal.length-arr[arr.length-1].length)+value;};s=me.suggestions[i];d=me.data[i];me.el.val(getValue(s));if($.isFunction(onSelect)){onSelect(s,d);}}};}(jQuery));
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/project/static/jquery/jquery.autocomplete.css	Fri Jan 15 20:15:00 2010 +0530
@@ -0,0 +1,6 @@
+
+.autocomplete-w1 { background:url(/static/img/shadow.png) no-repeat bottom right; position:absolute; top:0px; left:0px; margin:8px 0 0 6px; /* IE6 fix: */ _background:none; _margin:0; }
+.autocomplete { border:1px solid #999; background:#FFF; cursor:default; text-align:left; max-height:350px; overflow:auto; margin:-6px 6px 6px -6px; /* IE6 specific: */ _height:350px;  _margin:0; _overflow-x:hidden; }
+.autocomplete .selected { background:#F0F0F0; }
+.autocomplete div { padding:2px 5px; white-space:nowrap; }
+.autocomplete strong { font-weight:normal; color:#3399FF; }
--- a/project/templates/proceedings/submit.html	Thu Jan 14 21:07:03 2010 +0530
+++ b/project/templates/proceedings/submit.html	Fri Jan 15 20:15:00 2010 +0530
@@ -2,11 +2,16 @@
 {% block title %}Submit Paper for Proceedings{% endblock %}
 
 {% block addscripts %}
+  <link rel="stylesheet" type="text/css" href="/static/jquery/jquery.autocomplete.css" />
   <script type="text/javascript" src="/static/jquery/jquery-ui-1.7.2.custom.min.js"></script>
   <script type="text/javascript" src="/static/jquery/jquery-dynamic-form.js"></script>
+  <script type="text/javascript" src="/static/jquery/jquery.autocomplete-min.js"></script>
   <script type="text/javascript">
     $(document).ready(function(){	
-	  $("#author").dynamicForm("#plus", "#minus", {createColor: 'yellow',removeColor: 'red'});
+	  $("#author").dynamicForm("#plus", "#minus", {limit: 10, createColor: 'green',removeColor: 'red'});
+	  var a = $('input[id^=id_authors]').autocomplete({ 
+        serviceUrl:'/proceedings/getusers/', 
+      });
 	});
   </script>
 {% endblock %}
@@ -57,11 +62,12 @@
         </tr>
         <tr>
           <th>{{ proceedings_form.authors.label }}</th>
-          <td id="author">
+          <td>
+            <table style="position: relative; left: -3%;"><tr id="author"><td>
             {{ proceedings_form.authors.errors }}
             {{ proceedings_form.authors }}
             <span><a id="minus" href="">[Remove]</a><a id="plus" href="">[Add]</a></span>
-            <br />
+            </td><tr></table>
           </td>
         </tr>
       </table>
--- a/project/urls.py	Thu Jan 14 21:07:03 2010 +0530
+++ b/project/urls.py	Fri Jan 15 20:15:00 2010 +0530
@@ -59,6 +59,7 @@
 # Proceedings
 urlpatterns += patterns('project.kiwipycon.proceedings.views',
     url(r'^proceedings/submit/$',  'submit', name='kiwipycon_submit_proceedings'),
+    url(r'^proceedings/getusers/$',  'getUsers', name='kiwipycon_getusers_proceedings'),
     url(r'^proceedings/edit/$',  'edit', name='kiwipycon_edit_proceedings'),
     )