Index: src/main/java/com/xpn/xwiki/objects/meta/StringMetaClass.java
===================================================================
--- src/main/java/com/xpn/xwiki/objects/meta/StringMetaClass.java	(revision 4234)
+++ src/main/java/com/xpn/xwiki/objects/meta/StringMetaClass.java	(working copy)
@@ -1,51 +0,0 @@
-/*
- * Copyright 2006-2007, XpertNet SARL, and individual contributors as indicated
- * by the contributors.txt.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- *
- */
-
-package com.xpn.xwiki.objects.meta;
-
-import com.xpn.xwiki.XWikiContext;
-import com.xpn.xwiki.objects.BaseCollection;
-import com.xpn.xwiki.objects.classes.NumberClass;
-import com.xpn.xwiki.objects.classes.StringClass;
-
-public class StringMetaClass extends PropertyMetaClass
-{
-
-    public StringMetaClass()
-    {
-        super();
-        // setType("stringmetaclass");
-        setPrettyName("String Class");
-        setName(StringClass.class.getName());
-
-        NumberClass size_class = new NumberClass(this);
-        size_class.setName("size");
-        size_class.setPrettyName("Size");
-        size_class.setSize(5);
-        size_class.setNumberType("integer");
-        safeput("size", size_class);
-    }
-
-    public BaseCollection newObject(XWikiContext context)
-    {
-        return new StringClass();
-    }
-}
Index: src/main/java/com/xpn/xwiki/objects/meta/ListMetaClass.java
===================================================================
--- src/main/java/com/xpn/xwiki/objects/meta/ListMetaClass.java	(revision 4234)
+++ src/main/java/com/xpn/xwiki/objects/meta/ListMetaClass.java	(working copy)
@@ -47,6 +47,12 @@
         multi_class.setUnmodifiable(true);
         safeput("multiSelect", multi_class);
 
+        StringClass separators_class = new StringClass(this);
+        separators_class.setName("separators");
+        separators_class.setPrettyName("Separators");
+        separators_class.setSize(5);
+        safeput("separators", separators_class);
+
         BooleanClass relational_class = new BooleanClass(this);
         relational_class.setName("relationalStorage");
         relational_class.setPrettyName("Relational Storage");
Index: src/main/java/com/xpn/xwiki/objects/meta/DBListMetaClass.java
===================================================================
--- src/main/java/com/xpn/xwiki/objects/meta/DBListMetaClass.java	(revision 4234)
+++ src/main/java/com/xpn/xwiki/objects/meta/DBListMetaClass.java	(working copy)
@@ -25,39 +25,50 @@
 import com.xpn.xwiki.objects.BaseCollection;
 import com.xpn.xwiki.objects.classes.DBListClass;
 import com.xpn.xwiki.objects.classes.TextAreaClass;
+import com.xpn.xwiki.objects.classes.BooleanClass;
+import com.xpn.xwiki.objects.classes.ListClass;
+import com.xpn.xwiki.objects.classes.NumberClass;
+import com.xpn.xwiki.objects.classes.StaticListClass;
 import com.xpn.xwiki.objects.classes.StringClass;
 
 public class DBListMetaClass extends ListMetaClass {
 
     public DBListMetaClass() {
-        super();
-        setPrettyName("Database List Class");
-        setName(DBListClass.class.getName());
+    	 super();
+         setPrettyName("Database List Class");
+         setName(DBListClass.class.getName());
 
-        TextAreaClass sql_class = new TextAreaClass(this);
-        sql_class.setName("sql");
-        sql_class.setPrettyName("Hibernate Query");
-        sql_class.setSize(80);
-        sql_class.setRows(5);
-        safeput("sql", sql_class);
+         TextAreaClass sql_class = new TextAreaClass(this);
+         sql_class.setName("sql");
+         sql_class.setPrettyName("Hibernate Query");
+         sql_class.setSize(80);
+         sql_class.setRows(5);
+         safeput("sql", sql_class);
 
-        StringClass classname_class = new StringClass(this);
-        classname_class.setName("classname");
-        classname_class.setPrettyName("XWiki Class Name");
-        classname_class.setSize(20);
-        safeput("classname", classname_class);
+         StringClass classname_class = new StringClass(this);
+         classname_class.setName("classname");
+         classname_class.setPrettyName("XWiki Class Name");
+         classname_class.setSize(20);
+         safeput("classname", classname_class);
 
-        StringClass idfield_class = new StringClass(this);
-        idfield_class.setName("idField");
-        idfield_class.setPrettyName("Id Field Name");
-        idfield_class.setSize(20);
-        safeput("idField", idfield_class);
+         StringClass idfield_class = new StringClass(this);
+         idfield_class.setName("idField");
+         idfield_class.setPrettyName("Id Field Name");
+         idfield_class.setSize(20);
+         safeput("idField", idfield_class);
 
-        StringClass valuefield_class = new StringClass(this);
-        valuefield_class.setName("valueField");
-        valuefield_class.setPrettyName("Value Field Name");
-        valuefield_class.setSize(20);
-        safeput("valueField", valuefield_class);
+         StringClass valuefield_class = new StringClass(this);
+         valuefield_class.setName("valueField");
+         valuefield_class.setPrettyName("Value Field Name");
+         valuefield_class.setSize(20);
+         safeput("valueField", valuefield_class);
+         
+         BooleanClass picker_class = new BooleanClass(this);
+         picker_class.setName("picker");
+         picker_class.setPrettyName("Use Suggest");
+         picker_class.setDisplayType("yesno");
+         picker_class.setUnmodifiable(true);
+         safeput("picker", picker_class);
     }
 
     public BaseCollection newObject(XWikiContext context) {
Index: src/main/java/com/xpn/xwiki/objects/meta/StaticListMetaClass.java
===================================================================
--- src/main/java/com/xpn/xwiki/objects/meta/StaticListMetaClass.java	(revision 4234)
+++ src/main/java/com/xpn/xwiki/objects/meta/StaticListMetaClass.java	(working copy)
@@ -24,13 +24,16 @@
 import com.xpn.xwiki.XWikiContext;
 import com.xpn.xwiki.objects.BaseCollection;
 import com.xpn.xwiki.objects.classes.StaticListClass;
+import com.xpn.xwiki.objects.classes.BooleanClass;
+import com.xpn.xwiki.objects.classes.ListClass;
+import com.xpn.xwiki.objects.classes.NumberClass;
 import com.xpn.xwiki.objects.classes.StringClass;
 
 public class StaticListMetaClass extends ListMetaClass {
 
 
     public StaticListMetaClass() {
-        super();
+    	super();
         setPrettyName("Static List Class");
         setName(StaticListClass.class.getName());
 
@@ -38,13 +41,15 @@
         values_class.setName("values");
         values_class.setPrettyName("Values");
         values_class.setSize(40);
-        safeput("values", values_class);
-
-        StringClass separators_class = new StringClass(this);
-        separators_class.setName("separators");
-        separators_class.setPrettyName("Separators");
-        separators_class.setSize(5);
-        safeput("separators", separators_class);        
+        safeput("values", values_class); 
+        
+        BooleanClass picker_class = new BooleanClass(this);
+        picker_class.setName("picker");
+        picker_class.setPrettyName("Use Suggest");
+        picker_class.setDisplayType("yesno");
+        picker_class.setUnmodifiable(true);
+        safeput("picker", picker_class);
+        
     }
 
     public BaseCollection newObject(XWikiContext context) {
Index: src/main/java/com/xpn/xwiki/objects/classes/ListClass.java
===================================================================
--- src/main/java/com/xpn/xwiki/objects/classes/ListClass.java	(revision 4234)
+++ src/main/java/com/xpn/xwiki/objects/classes/ListClass.java	(working copy)
@@ -47,10 +47,9 @@
 import com.xpn.xwiki.plugin.query.XWikiCriteria;
 import com.xpn.xwiki.plugin.query.XWikiQuery;
 
+
 public abstract class ListClass extends PropertyClass
 {
-
-
     public ListClass(String name, String prettyname, PropertyMetaClass wclass)
     {
         super(name, prettyname, wclass);
@@ -72,11 +71,14 @@
         this(null);
     }
 
-    public String getSeparators()
-    {
-        return null;
+    public String getSeparators() {
+        return getStringValue("separators");
     }
 
+    public void setSeparators(String separators) {
+        setStringValue("separators", separators);
+    }
+
     public String getDisplayType()
     {
         return getStringValue("displayType");
@@ -429,7 +431,9 @@
             input.setSize(getSize());
             input.setName(prefix + name);
             input.setID(prefix + name);
+   
             buffer.append(input.toString());
+            
         } else if (getDisplayType().equals("radio") || getDisplayType().equals("checkbox")) {
             displayRadioEdit(buffer, name, prefix, object, context);
         } else {
Index: src/main/java/com/xpn/xwiki/objects/classes/DBListClass.java
===================================================================
--- src/main/java/com/xpn/xwiki/objects/classes/DBListClass.java	(revision 4234)
+++ src/main/java/com/xpn/xwiki/objects/classes/DBListClass.java	(working copy)
@@ -25,12 +25,25 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Iterator;
 
 import com.xpn.xwiki.XWiki;
 import com.xpn.xwiki.XWikiContext;
 import com.xpn.xwiki.objects.meta.PropertyMetaClass;
 import com.xpn.xwiki.plugin.query.QueryPlugin;
 
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.StringTokenizer;
+import org.apache.commons.lang.StringUtils;
+import org.apache.ecs.xhtml.input;
+import com.xpn.xwiki.objects.BaseCollection;
+import com.xpn.xwiki.objects.BaseProperty;
+import com.xpn.xwiki.objects.DBStringListProperty;
+import com.xpn.xwiki.objects.ListProperty;
+import com.xpn.xwiki.XWikiException;
+
+
 public class DBListClass extends ListClass
 {
     private List cachedDBList;
@@ -232,4 +245,206 @@
     public void flushCache() {
         setCachedDBList(null);
     }
+    
+    // return first or second col from user query
+    public String returnCol(String hibquery, boolean first) {
+    	String firstCol = "-", secondCol = "-";
+    	
+    	int fromIndx = hibquery.indexOf("from");
+		 
+		if(fromIndx > 0) {
+			 String firstPart = hibquery.substring(0, fromIndx);
+			 firstPart.replaceAll("\\s+", " ");
+			 int comIndx = hibquery.indexOf(",");
+			 
+			 //there are more than one columns to select- take the second one (the value)
+			 if(comIndx > 0 && comIndx < fromIndx) {
+
+				 StringTokenizer st = new StringTokenizer(firstPart, " ,()", true);
+				 ArrayList words = new ArrayList();
+				 
+				 while(st.hasMoreTokens()) 
+					 words.add(st.nextToken().toLowerCase());
+				 
+				 int comma = words.indexOf(",") - 1;
+				 while(words.get(comma).toString().compareTo(" ") == 0) {
+					 comma--;
+				 }
+				 firstCol = words.get(comma).toString().trim();
+				 
+				 comma = words.indexOf(",") + 1;
+				 while(words.get(comma).toString().compareTo(" ") == 0) {
+					  comma++;
+				 }
+				 				 
+              	 if(words.get(comma).toString().compareTo("(") == 0) {
+              		 int i = comma+1;
+              		 while(words.get(i).toString().compareTo(")") != 0) {
+              			 secondCol += words.get(i).toString();
+              			 i++;
+              		 }
+              		 secondCol += ")";
+              	 }
+              	 else secondCol = words.get(comma).toString().trim();
+			 }
+			 //has only one column
+			 else {
+				  int i = fromIndx - 1;
+				  while(firstPart.charAt(i) == ' ')
+					  i--;
+				  String col = " ";
+				  while(firstPart.charAt(i) != ' ') {
+					  col += firstPart.charAt(i);
+					  i--;
+				  }
+				  String reverse = " ";
+				  for(i = (col.length()-1); i >= 0; i--)
+					  reverse += col.charAt(i);
+				  firstCol = reverse.trim();
+			 }
+		}
+		if(first == true) return firstCol;
+		else return secondCol;
+    }
+    
+    //the result of the second query, to retrieve the value
+    public String getValue(String val, String sql, XWikiContext context) {
+    	String firstCol = returnCol(sql, true);
+		String secondCol = returnCol(sql, false);
+		
+		String newsql = sql.substring(0, sql.indexOf(firstCol));
+		newsql += secondCol + " ";
+		newsql += sql.substring(sql.indexOf("from"));
+		newsql += "and " + firstCol + "='" + val + "'";
+		
+		Object[] list = null;
+		XWiki xwiki = context.getWiki();
+		String res = "";
+		try {
+				list = xwiki.search(newsql, context).toArray();
+				if(list.length > 0) res = list[0].toString();
+			}catch(Exception e) {
+				e.printStackTrace();
+			}  
+		return res;
+    }
+    
+    
+    //override the method from parent ListClass
+    public void displayEdit(StringBuffer buffer, String name, String prefix,
+            BaseCollection object, XWikiContext context)
+        {
+            //input display  	
+            if (getDisplayType().equals("input")) {
+            	input input = new input();
+                input.setType("text");
+                input.setSize(getSize());
+                boolean changeInputName = false;
+                boolean setInpVal = true;
+                
+                BaseProperty prop = (BaseProperty) object.safeget(name);
+                String val = "";
+                if (prop != null)  val = prop.toFormString();
+                
+                if(isPicker()) {
+                	input.addAttribute("autocomplete", "off");
+                	String path = "";
+                	try {
+                   	 	XWiki xwiki = context.getWiki();
+                   	 	path = xwiki.getURL("Main.WebHome", "view", context);
+                	} catch(XWikiException e) {
+                		e.printStackTrace();
+                	  }
+               	 	String classname = this.getObject().getName();
+               	 	String fieldname = this.getName();
+               	 	String hibquery = this.getSql();
+               	 	String secondCol = "-", firstCol = "-";
+               	 	
+               	 	if(hibquery != null && !hibquery.equals("")) {
+               	 		firstCol = returnCol(hibquery, true);
+               	 		secondCol = returnCol(hibquery, false);
+               	 		       	 		
+               	 		if(secondCol.compareTo("-") != 0) {
+               	 			changeInputName = true;                    		 
+               	 			input hidden = new input();
+               	 			hidden.setID(prefix + name);
+               	 			hidden.setName(prefix + name);
+               	 			hidden.setType("hidden");
+               	 			if(val != null && !val.equals("")) hidden.setValue(val);
+               	 			buffer.append(hidden.toString());
+               	 			
+               	 			input.setValue(getValue(val, hibquery, context));
+               	 			setInpVal = false;
+               	 		}
+               	 	}
+               	 	
+               	 	String script = "\""+path+"?xpage=suggest&amp;classname="+classname+"&amp;fieldname="+fieldname+"&amp;firCol="+firstCol+"&amp;secCol="+secondCol+"&amp;\"";            	 	
+               	 	String varname = "\"input\"";
+               	    String seps = "\""+this.getSeparators()+"\"";
+               	    if(isMultiSelect())
+               	    	input.setOnFocus("new ajaxSuggest(this, {script:"+script+", varname:"+varname+", seps:"+seps+"} )");
+               	    else
+               	    	input.setOnFocus("new ajaxSuggest(this, {script:"+script+", varname:"+varname+"} )");
+         	 	  
+               	 
+               	 	
+                }
+               	 	
+               	if(changeInputName == true) {
+               	 		input.setName(prefix + name + "_suggest");
+               	 		input.setID(prefix + name + "_suggest");
+               	}
+                else {
+               	 		input.setName(prefix + name);
+               	 		input.setID(prefix + name);
+               	 	 }
+               	if(setInpVal == true) input.setValue(val);
+               
+                buffer.append(input.toString());
+                                
+            } else if (getDisplayType().equals("radio") || getDisplayType().equals("checkbox")) {
+                displayRadioEdit(buffer, name, prefix, object, context);
+            } else {
+                displaySelectEdit(buffer, name, prefix, object, context);
+            }
+
+            if (!getDisplayType().equals("input")) {
+                org.apache.ecs.xhtml.input hidden = new input(input.hidden, prefix + name, "");
+                buffer.append(hidden);
+            }
+        }
+    
+    public void displayView(StringBuffer buffer, String name, String prefix,
+            BaseCollection object, XWikiContext context)
+        {
+    		if(isPicker() && getSql().compareTo("") != 0) {
+    			BaseProperty prop = (BaseProperty) object.safeget(name);
+    			String val = "";
+    			if(prop != null) val = prop.toFormString();
+    			Map map = getMap(context);
+ 
+    			String  secondCol = returnCol(getSql(), false);
+    			if(secondCol.compareTo("-") != 0) {
+    				String res = getValue(val, getSql(), context);
+            		buffer.append(getDisplayValue(res, name, map, context));
+    			}
+    			else buffer.append(getDisplayValue(val, name, map, context));
+    		}
+    		else {
+    				List selectlist;
+                    String separator = getSeparator();
+                    BaseProperty prop = (BaseProperty) object.safeget(name);
+                    Map map = getMap(context);
+                    if ((prop instanceof ListProperty) || (prop instanceof DBStringListProperty)) {
+                        selectlist = (List) prop.getValue();
+                        List newlist = new ArrayList();
+                        for (Iterator it = selectlist.iterator(); it.hasNext();) {
+                            newlist.add(getDisplayValue(it.next(), name, map, context));
+                        }
+                        buffer.append(StringUtils.join(newlist.toArray(), separator));
+                    } else {
+                    	buffer.append(getDisplayValue(prop.getValue(), name, map, context));
+                    }
+    		}  
+        }
 }
Index: src/main/java/com/xpn/xwiki/objects/classes/StaticListClass.java
===================================================================
--- src/main/java/com/xpn/xwiki/objects/classes/StaticListClass.java	(revision 4234)
+++ src/main/java/com/xpn/xwiki/objects/classes/StaticListClass.java	(working copy)
@@ -23,10 +23,17 @@
 
 import com.xpn.xwiki.XWikiContext;
 import com.xpn.xwiki.objects.meta.PropertyMetaClass;
+import com.xpn.xwiki.XWiki;
 
 import java.util.List;
 import java.util.Map;
+import com.xpn.xwiki.XWiki;
+import com.xpn.xwiki.XWikiException;
 
+import com.xpn.xwiki.objects.BaseCollection;
+import com.xpn.xwiki.objects.BaseProperty;
+import org.apache.ecs.xhtml.input;
+
 public class StaticListClass extends ListClass {
 
     public StaticListClass(PropertyMetaClass wclass) {
@@ -46,14 +53,6 @@
         setStringValue("values", values);
     }
 
-    public String getSeparators() {
-        return getStringValue("separators");
-    }
-
-    public void setSeparators(String separators) {
-        setStringValue("separators", separators);
-    }
-
     public List getList(XWikiContext context) {
         String values = getValues();
         return getListFromString(values);
@@ -63,4 +62,55 @@
         String values = getValues();
         return getMapFromString(values);
     }
+    
+    public void displayEdit(StringBuffer buffer, String name, String prefix,
+            BaseCollection object, XWikiContext context)
+        {
+            if (getDisplayType().equals("input")) {
+                input input = new input();
+                BaseProperty prop = (BaseProperty) object.safeget(name);
+                if (prop != null) {
+                    input.setValue(prop.toFormString());
+                }
+                input.setType("text");
+                input.setSize(getSize());
+                input.setName(prefix + name);
+                input.setID(prefix + name);
+                
+                if(isPicker()) {
+                	input.addAttribute("autocomplete", "off");
+                	String path = "";
+                	try {
+                   	 	XWiki xwiki = context.getWiki();
+                   	 	path = xwiki.getURL("Main.WebHome", "view", context);
+                	} catch(XWikiException e) {
+                		e.printStackTrace();
+                	}
+                	
+                	String classname = this.getObject().getName();
+               	 	String fieldname = this.getName();
+               	 	String secondCol = "-", firstCol = "-";
+               	 	
+               	 	String script = "\""+path+"?xpage=suggest&amp;classname="+classname+"&amp;fieldname="+fieldname+"&amp;firCol="+firstCol+"&amp;secCol="+secondCol+"&amp;\"";
+            	 	String varname = "\"input\"";
+            	 	String seps = "\""+this.getSeparators()+"\"";
+            	 	if(isMultiSelect())
+            	 		input.setOnFocus("new ajaxSuggest(this, {script:"+script+", varname:"+varname+", seps:"+seps+"} )");
+            	 	else
+            	 		input.setOnFocus("new ajaxSuggest(this, {script:"+script+", varname:"+varname+"} )");
+                }
+                
+                buffer.append(input.toString());
+                
+            } else if (getDisplayType().equals("radio") || getDisplayType().equals("checkbox")) {
+                displayRadioEdit(buffer, name, prefix, object, context);
+            } else {
+                displaySelectEdit(buffer, name, prefix, object, context);
+            }
+
+            if (!getDisplayType().equals("input")) {
+                org.apache.ecs.xhtml.input hidden = new input(input.hidden, prefix + name, "");
+                buffer.append(hidden);
+            }
+        }
 }
Index: src/main/java/com/xpn/xwiki/objects/classes/StringClass.java
===================================================================
--- src/main/java/com/xpn/xwiki/objects/classes/StringClass.java	(revision 4234)
+++ src/main/java/com/xpn/xwiki/objects/classes/StringClass.java	(working copy)
@@ -26,6 +26,7 @@
 
 import org.apache.ecs.xhtml.input;
 
+import com.xpn.xwiki.XWiki;
 import com.xpn.xwiki.XWikiContext;
 import com.xpn.xwiki.objects.BaseCollection;
 import com.xpn.xwiki.objects.BaseProperty;
@@ -33,6 +34,7 @@
 import com.xpn.xwiki.objects.meta.PropertyMetaClass;
 import com.xpn.xwiki.plugin.query.XWikiCriteria;
 import com.xpn.xwiki.plugin.query.XWikiQuery;
+import com.xpn.xwiki.XWikiException;
 
 public class StringClass extends PropertyClass
 {
@@ -62,7 +64,17 @@
     {
         setIntValue("size", size);
     }
+    
+    public boolean isPicker()
+    {
+        return (getIntValue("picker") == 1);
+    }
 
+    public void setPicker(boolean picker)
+    {
+        setIntValue("picker", picker ? 1 : 0);
+    }
+
     public BaseProperty fromString(String value)
     {
         BaseProperty property = newProperty();
@@ -90,6 +102,26 @@
         input.setName(prefix + name);
         input.setID(prefix + name);
         input.setSize(getSize());
+        
+        if(isPicker()) {
+        	input.addAttribute("autocomplete", "off");
+        	String path = "";
+        	try {
+           	 	XWiki xwiki = context.getWiki();
+           	 	path = xwiki.getURL("Main.WebHome", "view", context);
+        	} catch(XWikiException e) {
+        		e.printStackTrace();
+        	  }
+        	
+        	String classname = this.getObject().getName();
+       	 	String fieldname = this.getName();
+       	 	String secondCol = "-", firstCol = "-";
+       	 	
+       	 	String script = "\""+path+"?xpage=suggest&amp;classname="+classname+"&amp;fieldname="+fieldname+"&amp;firCol="+firstCol+"&amp;secCol="+secondCol+"&amp;\"";
+    	 	String varname = "\"input\"";
+    	 	input.setOnFocus("new ajaxSuggest(this, {script:"+script+", varname:"+varname+"} )");
+        }
+        
         buffer.append(input.toString());
     }
 
Index: standard/src/main/webapp/skins/albatross/tagedit.vm
===================================================================
--- standard/src/main/webapp/skins/albatross/tagedit.vm	(revision 4234)
+++ standard/src/main/webapp/skins/albatross/tagedit.vm	(working copy)
@@ -88,9 +88,13 @@
       </dl>
     #end
   #else
+     #set($path = $xwiki.getURL("Main.WebHome", "view")) 
+     #set($script = $path+"?xpage=suggest&amp;classname=XWiki.TagClass&amp;fieldname=tags&amp;firCol=-&amp;secCol=-&amp;")
+     #set($seps = $xwiki.getDocument("XWiki.TagClass").xWikiClass.tags.getProperty('separators').value)
+     
     <dl>
     <dt><label for="tags">$msg.get("core.tagedit.title")</label></dt>
-    <dd><input type="text" id="tags" name="tags" value="$!tdoc.tags"/></dd>
+    <dd><input type="text" id="tags" name="tags" autocomplete="off" onfocus="new ajaxSuggest(this, {script:'$script', varname: 'input', seps:'$seps', offsety: 13} );" value="$!tdoc.tags"/></dd>
     </dl>
   #end
 #end
\ No newline at end of file
Index: standard/src/main/webapp/skins/albatross/suggest/ajaxSuggest.js
===================================================================
--- standard/src/main/webapp/skins/albatross/suggest/ajaxSuggest.js	(revision 0)
+++ standard/src/main/webapp/skins/albatross/suggest/ajaxSuggest.js	(revision 0)
@@ -0,0 +1,949 @@
+
+
+var useXWKns;
+
+if (useXWKns)
+{
+	if (typeof(xwk) == "undefined")
+		xwk = {}
+	_xwk = xwk;
+}
+else
+{
+	_xwk = this;
+}
+
+
+if (typeof(_xwk.ajaxSuggest) == "undefined")
+	_xwk.ajaxSuggest = {}
+
+
+_xwk.ajaxSuggest = function (fld, param)
+{
+	this.fld = fld;
+
+	if (!this.fld)
+		return false;
+	
+	
+	
+	
+	// init variables
+	//
+	this.sInput 		= "";
+	this.nInputChars 	= 0;
+	this.aSuggestions 	= [];
+	this.iHighlighted 	= 0;
+	
+	// parameters object
+	//
+	this.oP = (param) ? param : {};
+	
+	// defaults	
+	//
+	if (!this.oP.minchars)									this.oP.minchars = 1;
+	if (!this.oP.method)									this.oP.meth = "get";
+	if (!this.oP.varname)									this.oP.varname = "input";
+	if (!this.oP.className)									this.oP.className = "ajaxsuggest";
+	if (!this.oP.timeout)									this.oP.timeout = 2500;
+	if (!this.oP.delay)										this.oP.delay = 500;
+	if (!this.oP.offsety)									this.oP.offsety = -5;
+	if (!this.oP.shownoresults)								this.oP.shownoresults = true;
+	if (!this.oP.noresults)									this.oP.noresults = "No results!";
+	if (!this.oP.maxheight && this.oP.maxheight !== 0)		this.oP.maxheight = 250;
+	if (!this.oP.cache && this.oP.cache != false)			this.oP.cache = false;
+	if (this.oP.seps)                                       this.seps = this.oP.seps;
+	else													this.seps = "";
+	
+	
+	
+	
+	// set keyup handler for field
+	// and prevent autocomplete from client
+	//
+	var pointer = this;
+	
+	// NOTE: not using addEventListener because UpArrow fired twice in Safari
+	//_xwk.DOM.addEvent( this.fld, 'keyup', function(ev){ return pointer.onKeyPress(ev); } );
+	
+	this.fld.onkeypress 	= function(ev){ return pointer.onKeyPress(ev); }
+	this.fld.onkeyup 		= function(ev){ return pointer.onKeyUp(ev); }
+	
+	this.fld.setAttribute("autocomplete", "off");
+}
+
+
+
+_xwk.ajaxSuggest.prototype.onKeyPress = function(ev)
+{
+	
+	var key = (window.event) ? window.event.keyCode : ev.keyCode;
+
+
+
+	// set responses to keydown events in the field
+	// this allows the user to use the arrow keys to scroll through the results
+	// ESCAPE clears the list
+	// TAB sets the current highlighted value
+	//
+	var RETURN = 13;
+	var TAB = 9;
+	var ESC = 27;
+	
+	var bubble = true;
+
+	switch(key)
+	{
+
+		case RETURN: {
+		        if(this.aSuggestions.length == 1) {
+		        	this.setHighlight(1);
+		        }
+		     	this.setHighlightedValue();
+				bubble = false;
+			}
+			break;
+
+
+		case ESC:
+			this.clearSuggestions();
+			break;
+	}
+
+	return bubble;
+}
+
+
+
+_xwk.ajaxSuggest.prototype.onKeyUp = function(ev)
+{
+	var key = (window.event) ? window.event.keyCode : ev.keyCode;
+	
+
+
+	// set responses to keydown events in the field
+	// this allows the user to use the arrow keys to scroll through the results
+	// ESCAPE clears the list
+	// TAB sets the current highlighted value
+	//
+
+	var ARRUP = 38;
+	var ARRDN = 40;
+	
+	var bubble = true;
+
+	switch(key)
+	{
+
+
+		case ARRUP:
+			this.changeHighlight(key);
+			bubble = false;
+			break;
+
+
+		case ARRDN:
+			this.changeHighlight(key);
+			bubble = false;
+			break;
+		
+		
+		default: {
+		    //if there are separators in the input string,
+		    // get suggestions only for the text after the last separator
+		    if(this.seps) 
+		    {
+		        var lastIndx = -1;
+				for(var i = 0; i < this.seps.length; i++)
+				 	if(this.fld.value.lastIndexOf(this.seps.charAt(i)) > lastIndx)
+				 		lastIndx = this.fld.value.lastIndexOf(this.seps.charAt(i));
+				if(lastIndx == -1)
+				    this.getSuggestions(this.fld.value);
+				else 
+				    this.getSuggestions(this.fld.value.substring(lastIndx+1));
+		    }
+			else 
+				this.getSuggestions(this.fld.value);
+		}
+	}
+
+	return bubble;
+	
+
+}
+
+	        
+_xwk.ajaxSuggest.prototype.getSuggestions = function (val)
+{
+	
+	// if input stays the same, do nothing
+	//
+	if (val == this.sInput)
+		return false;
+	
+	
+	// input length is less than the min required to trigger a request
+	// reset input string
+	// do nothing
+	//
+	if (val.length < this.oP.minchars)
+	{
+		this.sInput = "";
+		return false;
+	}
+	
+	
+	// if caching enabled, and user is typing (ie. length of input is increasing)
+	// filter results out of aSuggestions from last request
+	//
+	if (val.length>this.nInputChars && this.aSuggestions.length && this.oP.cache)
+	{
+		var arr = [];
+		for (var i=0;i<this.aSuggestions.length;i++)
+		{
+			if (this.aSuggestions[i].value.substr(0,val.length).toLowerCase() == val.toLowerCase())
+				arr.push( this.aSuggestions[i] );
+		}
+		
+		
+		this.sInput = val;
+		this.nInputChars = val.length;
+		this.aSuggestions = arr;
+		
+		this.createList(this.aSuggestions);
+		
+		
+		
+		return false;
+	}
+	else
+	// do new request
+	//
+	{
+	    this.sInput = val;
+		this.nInputChars = val.length;
+		
+		var pointer = this;
+		clearTimeout(this.ajID);
+		this.ajID = setTimeout( function() { pointer.doAjaxRequest() }, this.oP.delay );
+	}
+  
+	return false;
+}
+
+
+
+
+
+_xwk.ajaxSuggest.prototype.doAjaxRequest = function ()
+{
+	
+	var pointer = this;
+	
+	// create ajax request
+	var url = this.oP.script+this.oP.varname+"="+escape(this.fld.value);
+	var meth = this.oP.meth;
+	
+	var onSuccessFunc = function (req) { pointer.setSuggestions(req) };
+	var onErrorFunc = function (status) { alert("AJAX error: "+status); };
+
+	var myAjaxReq = new _xwk.AjaxReq();
+	myAjaxReq.makeRequest( url, meth, onSuccessFunc, onErrorFunc );
+}
+
+
+
+
+
+_xwk.ajaxSuggest.prototype.setSuggestions = function (req)
+{
+	this.aSuggestions = [];
+	
+	if (this.oP.json)
+	{
+		var jsondata = eval('(' + req.responseText + ')');
+		
+		for (var i=0;i<jsondata.results.length;i++)
+		{
+			this.aSuggestions.push(  { 'id':jsondata.results[i].id, 'value':jsondata.results[i].value, 'info':jsondata.results[i].info }  );
+		}
+	}
+	else
+	{
+
+		var xml = req.responseXML;
+	
+		// traverse xml
+		//
+		var results = xml.getElementsByTagName('results')[0].childNodes;
+
+		for (var i=0;i<results.length;i++)
+		{
+			if (results[i].hasChildNodes()) {
+				this.aSuggestions.push(  { 'id':results[i].getAttribute('id'), 'value':results[i].childNodes[0].nodeValue, 'info':results[i].getAttribute('info') }  );
+			}
+		}
+	
+	}
+	
+	this.idAs = "as_"+this.fld.id;
+	
+
+	this.createList(this.aSuggestions);
+
+}
+
+
+
+_xwk.ajaxSuggest.prototype.createList = function(arr)
+{
+	var pointer = this;
+	
+	
+	// get rid of old list
+	// and clear the list removal timeout
+	//
+	_xwk.DOM.removeElement(this.idAs);
+	this.killTimeout();
+	
+	// if no results, and shownoresults is false, do nothing
+	if (arr.length == 0 && !this.oP.shownoresults)
+		return false;
+		
+	// create holding div
+	//
+	var div = _xwk.DOM.createElement("div", {id:this.idAs, className:this.oP.className});	
+	
+	var hcorner = _xwk.DOM.createElement("div", {className:"as_corner"});
+	var hbar = _xwk.DOM.createElement("div", {className:"as_bar"});
+	var header = _xwk.DOM.createElement("div", {className:"as_header"});
+	header.appendChild(hcorner);
+	header.appendChild(hbar);
+	div.appendChild(header);
+	
+	
+	
+	
+	// create and populate ul
+	//
+	var ul = _xwk.DOM.createElement("ul", {id:"as_ul"});
+	
+	
+	
+	
+	// loop throught arr of suggestions
+	// creating an LI element for each suggestion
+	//
+	for (var i=0;i<arr.length;i++)
+	{
+		// format output with the input enclosed in a EM element
+		// (as HTML, not DOM)
+		//
+		
+		var val = arr[i].value;
+		var st = val.toLowerCase().indexOf( this.sInput.toLowerCase() );
+		var output = val.substring(0,st) + "<em>" + val.substring(st, st+this.sInput.length) + "</em>" + val.substring(st+this.sInput.length);
+		
+		
+		var span = _xwk.DOM.createElement("span", {}, output, true);
+		/*if (arr[i].info != "")
+		{
+			var br			= _xwk.DOM.createElement("br", {});
+			span.appendChild(br);
+			var small		= _xwk.DOM.createElement("small", {}, arr[i].info);
+			span.appendChild(small);
+		}*/
+		
+		var a = _xwk.DOM.createElement("a", { href:"#" });
+				
+		var tl 	= _xwk.DOM.createElement("span", {className:"tl"}, " ");
+		var tr 	= _xwk.DOM.createElement("span", {className:"tr"}, " ");
+		a.appendChild(tl);
+		a.appendChild(tr);
+		
+		a.appendChild(span);
+		
+		a.name = i+1;
+		a.onclick = function () { pointer.setHighlightedValue(); return false; }
+		a.onmouseover = function () { pointer.setHighlight(this.name); }
+		
+		var li 	= _xwk.DOM.createElement(  "li", {}, a  );
+		
+		ul.appendChild( li );
+	}
+	
+	
+	// no results
+	//
+	if (arr.length == 0)
+	{
+		var li 			= _xwk.DOM.createElement(  "li", {className:"as_warning"}, this.oP.noresults  );
+		
+		ul.appendChild( li );
+		
+	}
+	
+	
+	div.appendChild( ul );
+	
+	
+	var fcorner = _xwk.DOM.createElement("div", {className:"as_corner"});
+	var fbar = _xwk.DOM.createElement("div", {className:"as_bar"});
+	var footer = _xwk.DOM.createElement("div", {className:"as_footer"});
+	footer.appendChild(fcorner);
+	footer.appendChild(fbar);
+	div.appendChild(footer);
+	
+	
+	
+	// get position of target textfield
+	// position holding div below it
+	// set width of holding div to width of field
+	//
+	var pos = _xwk.DOM.getPos(this.fld);
+	
+	div.style.left 		= pos.x + "px";
+	
+	div.style.top 		= (pos.y + this.fld.offsetHeight + this.oP.offsety) + "px";
+	
+	div.style.width 	= this.fld.offsetWidth + "px";
+	
+	
+	
+	// set mouseover functions for div
+	// when mouse pointer leaves div, set a timeout to remove the list after an interval
+	// when mouse enters div, kill the timeout so the list won't be removed
+	//
+	div.onmouseover 	= function(){ pointer.killTimeout() }
+	div.onmouseout 		= function(){ pointer.resetTimeout() }
+
+
+	// add DIV to document
+	//
+	document.getElementsByTagName("body")[0].appendChild(div);
+	
+	
+	
+	// currently no item is highlighted
+	//
+	this.iHighlighted = 0;
+	
+	
+	
+	
+	
+	
+	// remove list after an interval
+	//
+	var pointer = this;
+	this.toID = setTimeout(function () { pointer.clearSuggestions() }, this.oP.timeout);
+}
+
+
+
+
+_xwk.ajaxSuggest.prototype.changeHighlight = function(key)
+{	
+	var list = _xwk.DOM.getElement("as_ul");
+	if (!list)
+		return false;
+	
+	var n;
+
+	if (key == 40)
+		n = this.iHighlighted + 1;
+	else if (key == 38)
+		n = this.iHighlighted - 1;
+	
+	
+	if (n > list.childNodes.length)
+		n = list.childNodes.length;
+	if (n < 1)
+		n = 1;
+	
+	
+	this.setHighlight(n);
+}
+
+
+
+_xwk.ajaxSuggest.prototype.setHighlight = function(n)
+{
+	var list = _xwk.DOM.getElement("as_ul");
+	if (!list)
+		return false;
+	
+	if (this.iHighlighted > 0)
+		this.clearHighlight();
+	
+	this.iHighlighted = Number(n);
+	
+	list.childNodes[this.iHighlighted-1].className = "as_highlight";
+
+
+	this.killTimeout();
+}
+
+
+_xwk.ajaxSuggest.prototype.clearHighlight = function()
+{
+	var list = _xwk.DOM.getElement("as_ul");
+	if (!list)
+		return false;
+	
+	if (this.iHighlighted > 0)
+	{
+		list.childNodes[this.iHighlighted-1].className = "";
+		this.iHighlighted = 0;
+	}
+}
+
+
+_xwk.ajaxSuggest.prototype.setHighlightedValue = function ()
+{
+	if (this.iHighlighted)
+	{
+		if(this.sInput == "" && this.fld.value == "")
+			this.sInput = this.fld.value = this.aSuggestions[ this.iHighlighted-1 ].value;
+		else {
+				if(this.seps) 
+				{
+				 	var lastIndx = -1;
+				 	for(var i = 0; i < this.seps.length; i++)
+				 		if(this.fld.value.lastIndexOf(this.seps.charAt(i)) > lastIndx)
+				 			lastIndx = this.fld.value.lastIndexOf(this.seps.charAt(i));
+				    if(lastIndx == -1)
+				    	this.sInput = this.fld.value = this.aSuggestions[ this.iHighlighted-1 ].value;
+				    else 
+				    {
+				    	this.fld.value = this.fld.value.substring(0, lastIndx+1) + this.aSuggestions[ this.iHighlighted-1 ].value;
+				 	    this.sInput = this.fld.value.substring(lastIndx+1);
+				 	} 
+				}
+				else
+					this.sInput = this.fld.value = this.aSuggestions[ this.iHighlighted-1 ].value;
+		}
+		
+		this.fld.focus();
+		/*
+		// move cursor to end of input (safari)
+		//
+		if (this.fld.selectionStart)
+			this.fld.setSelectionRange(this.sInput.length, this.sInput.length);*/
+		
+
+		this.clearSuggestions();
+		
+		// pass selected object to callback function, if exists
+		//
+		if (typeof(this.oP.callback) == "function")
+			this.oP.callback( this.aSuggestions[this.iHighlighted-1] );
+				
+		//there is a hidden input
+		if(this.fld.id.indexOf("_suggest") > 0) {
+			var hidden_id = this.fld.id.substring(0, this.fld.id.indexOf("_suggest"));
+			var hidden_inp = document.getElementById(hidden_id);
+				
+			if(hidden_inp)
+			 	hidden_inp.value = this.aSuggestions[ this.iHighlighted-1 ].info;
+			 			
+		}
+	
+	}
+}
+
+
+
+
+
+
+_xwk.ajaxSuggest.prototype.killTimeout = function()
+{
+	clearTimeout(this.toID);
+}
+
+_xwk.ajaxSuggest.prototype.resetTimeout = function()
+{
+	clearTimeout(this.toID);
+	var pointer = this;
+	this.toID = setTimeout(function () { pointer.clearSuggestions() }, 1000);
+}
+
+
+
+
+
+
+
+_xwk.ajaxSuggest.prototype.clearSuggestions = function ()
+{
+	
+	this.killTimeout();
+	
+	var ele = _xwk.DOM.getElement(this.idAs);
+	var pointer = this;
+	if (ele)
+	{
+		var fade = new _xwk.Fader(ele,1,0,250,function () { _xwk.DOM.removeElement(pointer.idAs) });
+	}
+}
+
+
+
+
+
+
+
+
+
+
+// AJAX PROTOTYPE _____________________________________________
+
+
+if (typeof(_xwk.AjaxReq) == "undefined")
+	_xwk.AjaxReq = {}
+
+
+
+_xwk.AjaxReq = function ()
+{
+	this.req = {};
+	this.isIE = false;
+}
+
+
+
+_xwk.AjaxReq.prototype.makeRequest = function (url, meth, onComp, onErr)
+{
+	
+	if (meth != "POST")
+		meth = "GET";
+	
+	this.onComplete = onComp;
+	this.onError = onErr;
+	
+	var pointer = this;
+	
+	// branch for native XMLHttpRequest object
+	if (window.XMLHttpRequest)
+	{
+		this.req = new XMLHttpRequest();
+		this.req.onreadystatechange = function () { pointer.processReqChange() };
+		this.req.open("GET", url, true); //
+		this.req.send(null);
+	// branch for IE/Windows ActiveX version
+	}
+	else if (window.ActiveXObject)
+	{
+		this.req = new ActiveXObject("Microsoft.XMLHTTP");
+		if (this.req)
+		{
+			this.req.onreadystatechange = function () { pointer.processReqChange() };
+			this.req.open(meth, url, true);
+			this.req.send();
+		}
+	}
+}
+
+
+_xwk.AjaxReq.prototype.processReqChange = function()
+{
+	
+	// only if req shows "loaded"
+	if (this.req.readyState == 4) {
+		// only if "OK"
+		if (this.req.status == 200)
+		{
+			this.onComplete( this.req );
+		} else {
+			this.onError( this.req.status );
+		}
+	}
+}
+
+
+
+
+
+
+
+
+
+
+// DOM PROTOTYPE _____________________________________________
+
+
+if (typeof(_xwk.DOM) == "undefined")
+	_xwk.DOM = {}
+
+
+
+
+_xwk.DOM.createElement = function ( type, attr, cont, html )
+{
+	var ne = document.createElement( type );
+	if (!ne)
+		return false;
+		
+	for (var a in attr)
+		ne[a] = attr[a];
+		
+	if (typeof(cont) == "string" && !html)
+		ne.appendChild( document.createTextNode(cont) );
+	else if (typeof(cont) == "string" && html)
+		ne.innerHTML = cont;
+	else if (typeof(cont) == "object")
+		ne.appendChild( cont );
+
+	return ne;
+}
+
+
+
+
+
+_xwk.DOM.clearElement = function ( id )
+{
+	var ele = this.getElement( id );
+	
+	if (!ele)
+		return false;
+	
+	while (ele.childNodes.length)
+		ele.removeChild( ele.childNodes[0] );
+	
+	return true;
+}
+
+
+
+
+
+
+
+
+
+_xwk.DOM.removeElement = function ( ele )
+{
+	var e = this.getElement(ele);
+	
+	if (!e)
+		return false;
+	else if (e.parentNode.removeChild(e))
+		return true;
+	else
+		return false;
+}
+
+
+
+
+
+_xwk.DOM.replaceContent = function ( id, cont, html )
+{
+	var ele = this.getElement( id );
+	
+	if (!ele)
+		return false;
+	
+	this.clearElement( ele );
+	
+	if (typeof(cont) == "string" && !html)
+		ele.appendChild( document.createTextNode(cont) );
+	else if (typeof(cont) == "string" && html)
+		ele.innerHTML = cont;
+	else if (typeof(cont) == "object")
+		ele.appendChild( cont );
+}
+
+
+
+
+
+
+
+
+
+_xwk.DOM.getElement = function ( ele )
+{
+	if (typeof(ele) == "undefined")
+	{
+		return false;
+	}
+	else if (typeof(ele) == "string")
+	{
+		var re = document.getElementById( ele );
+		if (!re)
+			return false;
+		else if (typeof(re.appendChild) != "undefined" ) {
+			return re;
+		} else {
+			return false;
+		}
+	}
+	else if (typeof(ele.appendChild) != "undefined")
+		return ele;
+	else
+		return false;
+}
+
+
+
+
+
+
+
+_xwk.DOM.appendChildren = function ( id, arr )
+{
+	var ele = this.getElement( id );
+	
+	if (!ele)
+		return false;
+	
+	
+	if (typeof(arr) != "object")
+		return false;
+		
+	for (var i=0;i<arr.length;i++)
+	{
+		var cont = arr[i];
+		if (typeof(cont) == "string")
+			ele.appendChild( document.createTextNode(cont) );
+		else if (typeof(cont) == "object")
+			ele.appendChild( cont );
+	}
+}
+
+
+
+
+
+
+
+
+
+_xwk.DOM.getPos = function ( ele )
+{
+	var ele = this.getElement(ele);
+
+	var obj = ele;
+
+	var curleft = 0;
+	if (obj.offsetParent)
+	{
+		while (obj.offsetParent)
+		{
+			curleft += obj.offsetLeft
+			obj = obj.offsetParent;
+		}
+	}
+	else if (obj.x)
+		curleft += obj.x;
+
+
+	var obj = ele;
+	
+	var curtop = 0;
+	if (obj.offsetParent)
+	{
+		while (obj.offsetParent)
+		{
+			curtop += obj.offsetTop
+			obj = obj.offsetParent;
+		}
+	}
+	else if (obj.y)
+		curtop += obj.y;
+
+	return {x:curleft, y:curtop}
+}
+
+
+
+
+
+
+
+
+
+
+// FADER PROTOTYPE _____________________________________________
+
+
+
+if (typeof(_xwk.Fader) == "undefined")
+	_xwk.Fader = {}
+
+
+
+
+
+_xwk.Fader = function (ele, from, to, fadetime, callback)
+{	
+	if (!ele)
+		return false;
+	
+	this.ele = ele;
+	
+	this.from = from;
+	this.to = to;
+	
+	this.callback = callback;
+	
+	this.nDur = fadetime;
+		
+	this.nInt = 50;
+	this.nTime = 0;
+	
+	var p = this;
+	this.nID = setInterval(function() { p._fade() }, this.nInt);
+}
+
+
+
+
+_xwk.Fader.prototype._fade = function()
+{
+	this.nTime += this.nInt;
+	
+	var ieop = Math.round( this._tween(this.nTime, this.from, this.to, this.nDur) * 100 );
+	var op = ieop / 100;
+	
+	if (this.ele.filters) // internet explorer
+	{
+		try
+		{
+			this.ele.filters.item("DXImageTransform.Microsoft.Alpha").opacity = ieop;
+		} catch (e) { 
+			// If it is not set initially, the browser will throw an error.  This will set it if it is not set yet.
+			this.ele.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity='+ieop+')';
+		}
+	}
+	else // other browsers
+	{
+		this.ele.style.opacity = op;
+	}
+	
+	
+	if (this.nTime == this.nDur)
+	{
+		clearInterval( this.nID );
+		if (this.callback != undefined)
+			this.callback();
+	}
+}
+
+
+
+_xwk.Fader.prototype._tween = function(t,b,c,d)
+{
+	return b + ( (c-b) * (t/d) );
+}
+
+
+/**
+ *  Inspired by:		Timothy Groves - http://www.brandspankingnew.net
+ *	version:            2.0 - 2007-02-07
+ *
+ */
+

Property changes on: standard/src/main/webapp/skins/albatross/suggest/ajaxSuggest.js
___________________________________________________________________
Name: svn:executable
   + *

Index: standard/src/main/webapp/skins/albatross/suggest/ajaxSuggest.css
===================================================================
--- standard/src/main/webapp/skins/albatross/suggest/ajaxSuggest.css	(revision 0)
+++ standard/src/main/webapp/skins/albatross/suggest/ajaxSuggest.css	(revision 0)
@@ -0,0 +1,170 @@
+
+body
+{
+	position: relative;
+}
+
+
+div.ajaxsuggest
+{
+	position: absolute;
+	background-image: url(suggest_img/as_pointer.gif);
+	background-position: top;
+	background-repeat: no-repeat;
+	padding: 10px 0 0 0;
+}
+
+div.ajaxsuggest div.as_header,
+div.ajaxsuggest div.as_footer
+{
+	position: relative;
+	height: 6px;
+	padding: 0 6px;
+	background-image: url(suggest_img/ul_corner_tr.gif);
+	background-position: top right;
+	background-repeat: no-repeat;
+	overflow: hidden;
+}
+div.ajaxsuggest div.as_footer
+{
+	background-image: url(suggest_img/ul_corner_br.gif);
+}
+
+div.ajaxsuggest div.as_header div.as_corner,
+div.ajaxsuggest div.as_footer div.as_corner
+{
+	position: absolute;
+	top: 0;
+	left: 0;
+	height: 6px;
+	width: 6px;
+	background-image: url(suggest_img/ul_corner_tl.gif);
+	background-position: top left;
+	background-repeat: no-repeat;
+}
+div.ajaxsuggest div.as_footer div.as_corner
+{
+	background-image: url(suggest_img/ul_corner_bl.gif);
+}
+div.ajaxsuggest div.as_header div.as_bar,
+div.ajaxsuggest div.as_footer div.as_bar
+{
+	height: 6px;
+	overflow: hidden;
+	background-color: #333;
+}
+
+
+div.ajaxsuggest ul
+{
+	list-style: none;
+	margin: 0 0 -4px 0;
+	padding: 0;
+	overflow: hidden;
+	background-color: #333;
+}
+
+div.ajaxsuggest ul li
+{
+	color: #ccc;
+	padding: 0;
+	margin: 0 4px 4px;
+	text-align: left;
+}
+
+div.ajaxsuggest ul li a
+{
+	color: #ccc;
+	display: block;
+	text-decoration: none;
+	background-color: transparent;
+	text-shadow: #000 0px 0px 5px;
+	position: relative;
+	padding: 0;
+	width: 100%;
+}
+div.ajaxsuggest ul li a:hover
+{
+	background-color: #444;
+}
+div.ajaxsuggest ul li.as_highlight a:hover
+{
+	background-color: #1B5CCD;
+}
+
+div.ajaxsuggest ul li a span
+{
+	display: block;
+	padding: 3px 6px;
+	font-weight: bold;
+}
+
+div.ajaxsuggest ul li a span small
+{
+	font-weight: normal;
+	color: #fff;
+}
+
+div.ajaxsuggest ul li.as_highlight a span small
+{
+	color: #ccc;
+}
+
+div.ajaxsuggest ul li.as_highlight a
+{
+	color: #fff;
+	background-color: #1B5CCD;
+	background-image: url(suggest_img/hl_corner_br.gif);
+	background-position: bottom right;
+	background-repeat: no-repeat;
+}
+
+div.ajaxsuggest ul li.as_highlight a span
+{
+	background-image: url(suggest_img/hl_corner_bl.gif);
+	background-position: bottom left;
+	background-repeat: no-repeat;
+}
+
+div.ajaxsuggest ul li a .tl,
+div.ajaxsuggest ul li a .tr
+{
+	background-image: transparent;
+	background-repeat: no-repeat;
+	width: 6px;
+	height: 6px;
+	position: absolute;
+	top: 0;
+	padding: 0;
+	margin: 0;
+}
+div.ajaxsuggest ul li a .tr
+{
+	right: 0;
+}
+
+div.ajaxsuggest ul li.as_highlight a .tl
+{
+	left: 0;
+	background-image: url(suggest_img/hl_corner_tl.gif);
+	background-position: bottom left;
+}
+
+div.ajaxsuggest ul li.as_highlight a .tr
+{
+	right: 0;
+	background-image: url(suggest_img/hl_corner_tr.gif);
+	background-position: bottom right;
+}
+
+div.ajaxsuggest ul em
+{
+	font-style: normal;
+	color: #6EADE7;
+}
+
+div.ajaxsuggest ul li.as_warning
+{
+	font-weight: bold;
+	text-align: center;
+}

Property changes on: standard/src/main/webapp/skins/albatross/suggest/ajaxSuggest.css
___________________________________________________________________
Name: svn:executable
   + *

Index: standard/src/main/webapp/skins/albatross/suggest.vm
===================================================================
--- standard/src/main/webapp/skins/albatross/suggest.vm	(revision 0)
+++ standard/src/main/webapp/skins/albatross/suggest.vm	(revision 0)
@@ -0,0 +1,122 @@
+$response.setContentType("text/xml") 
+
+#set($input = $request.get("input").toLowerCase())
+#set($classname = $request.get("classname"))
+#set($fieldname = $request.get("fieldname"))
+#set($firCol = $request.get("firCol"))
+#set($secCol = $request.get("secCol"))
+#set($templatename = $classname + 'Template')
+#set($p = $xwiki.getDocument($classname).getxWikiClass().get($fieldname).getPropertyClass())
+#set($hibquery = $p.getSql())
+
+######################### User hibernate query
+#if("$!hibquery" != "")
+    #if($secCol != "-")
+    ### two columns, hidden input
+      #if($hibquery.indexOf("like") < 0)
+      #set($like = " and lower("+ $secCol + ") like '%" + $input + "%'")
+      #set($hibquery = $hibquery.concat($like))
+      #end
+      #set($queryResult = $xwiki.search($hibquery, 30, 0))
+    #set($results = $queryResult.toArray())
+    <?xml version="1.0" encoding="UTF-8"?>
+    <results type="1">
+        #foreach($res in $results)
+        #set($info = '-')
+        #set($rs = '-')
+        #foreach($r in $res)
+          #if($velocityCount == 1)
+            #set($info = $r)
+          #elseif($velocityCount == 2)
+            #set($rs = $r)
+            #end
+        #end
+        #if($info != '-')
+          #if($rs != '-')
+            <rs id="" info="$info">$rs</rs>
+          #end
+          #end
+        #end
+    </results>
+    #else ### one column, no hidden input
+   #if($firCol != "-")
+      #set($like = " and lower("+ $firCol + ") like '%" + $input + "%'")
+          #set($hibquery = $hibquery.concat($like))
+       #end
+  #set($queryResult = $xwiki.search($hibquery, 30, 0))
+  #set($results = $queryResult.toArray())
+  <?xml version="1.0" encoding="UTF-8"?>
+        <results type="2">
+    #foreach($res in $results)
+      <rs id="" info="">$res</rs>
+      #end
+    </results>
+    #end
+#else   ######################### DBListProperty query
+  #if($p.isRelationalStorage() && $p.isMultiSelect())
+    #set($sep = $p.getSeparators())
+    #if($sep) ### has separators
+      #set($input_words = $xwiki.split($input, $sep))
+      #foreach($i in $input_words)
+         #set($input = $i)
+      #end
+      #set($query = "select distinct list from BaseObject as obj, DBStringListProperty as prop join prop.list list  where obj.className = '${classname}' and obj.id = prop.id.id and prop.id.name = '${fieldname}'")
+      #set($queryResult = $xwiki.search($query.toString(), 30, 0))
+      #set($results = $queryResult.toArray())
+      <?xml version="1.0" encoding="UTF-8"?>
+      <results type="3">
+        #foreach($res in $results)
+              #set($list = $p.getListFromString($res, $sep, false))
+          #set($list = $list.toArray())
+          #foreach($word in $list)
+            #if($word.indexOf($input) >=0 )
+              <rs id="$velocityCount" info="">$word</rs>
+            #end
+          #end
+        #end
+      </results>
+     #end
+  ######################### StringListProperty query
+  #elseif($p.isMultiSelect())
+    #set($sep = $p.getSeparators())
+    #if($sep) ### has separators
+      #set($input_words = $xwiki.split($input, $sep))
+      #foreach($i in $input_words)
+         #set($input = $i)
+      #end
+      #set($query =  "select distinct prop.textValue from BaseObject as obj, StringListProperty as prop where obj.name <> '${templatename}' and obj.className='${classname}' and prop.id.id = obj.id   and prop.name = '${fieldname}' and lower(prop.textValue) like '%${input}%'")
+      #set($queryResult = $xwiki.search($query.toString(), 30, 0))
+      #set($results = $queryResult.toArray())
+      <?xml version="1.0" encoding="UTF-8"?>
+      <results type="5">
+        #foreach($res in $results)
+          #set($list = $p.getListFromString($res, $sep, false))
+          #set($list = $list.toArray())
+          #foreach($word in $list)
+            #if($word.indexOf($input) >=0 )
+              <rs id="$velocityCount" info="">$word</rs>
+            #end
+          #end
+        #end
+      </results>
+    #else ### no separators
+      <?xml version="1.0" encoding="UTF-8"?>
+      <results type="6">
+        #foreach($res in $results)
+          <rs id="$velocityCount" info="">$res</rs>
+        #end
+      </results>
+    #end
+  #else ######################### StringProperty query
+   
+      #set($query =  "select distinct prop.value from BaseObject as obj, StringProperty as prop where obj.className='${classname}' and obj.name<>'${templatename}' and prop.id.id = obj.id and prop.id.name='${fieldname}' and lower(prop.value) like '%${input}%'")
+      #set($queryResult = $xwiki.search($query.toString(), 30, 0))
+      #set($results = $queryResult.toArray())
+      <?xml version="1.0" encoding="UTF-8"?>
+      <results type="8">
+        #foreach($res in $results)
+          <rs id="$velocityCount" info="">$res</rs>
+        #end
+      </results>
+  #end
+#end
\ No newline at end of file

Property changes on: standard/src/main/webapp/skins/albatross/suggest.vm
___________________________________________________________________
Name: svn:executable
   + *

Index: standard/src/main/webapp/skins/albatross/style.css
===================================================================
--- standard/src/main/webapp/skins/albatross/style.css	(revision 4234)
+++ standard/src/main/webapp/skins/albatross/style.css	(working copy)
@@ -11,6 +11,7 @@
 @import "colorsblack.css";
 /*@import "ie.css";   masque temporairement : modif spécifique IE à réintéger*/
 @import "fullscreenEdit.css";
+@import "suggest/ajaxSuggest.css";
 
 /* Styles for custom hand written <table> tables */
 @import "css/table/table.css";
Index: standard/src/main/webapp/skins/albatross/javascript.vm
===================================================================
--- standard/src/main/webapp/skins/albatross/javascript.vm	(revision 4234)
+++ standard/src/main/webapp/skins/albatross/javascript.vm	(working copy)
@@ -7,6 +7,7 @@
 <script type="text/javascript" src="$xwiki.getSkinFile("chwScripts.js")"></script>
 <script type="text/javascript" src="$xwiki.getSkinFile("scripts/table/tablefilterNsort.js", true)"></script>
 <script type="text/javascript" src="$xwiki.getSkinFile("fullscreenEdit.js", true)"></script>
+<script type="text/javascript" src="$xwiki.getSkinFile("suggest/ajaxSuggest.js")"></script>
 
 #if(($context.action=="inline")||($context.action=="edit") || ($context.action=="admin"))
 <script type="text/javascript">
