r1477 - in xwiki/trunk: . core/src/main/java/com/xpn/xwiki core/src/main/java/com/xpn/xwiki/api core/src/main/java/com/xpn/xwiki/doc core/src/main/java/com/xpn/xwiki/objects/classes core/src/main/java/com/xpn/xwiki/objects/meta core/src/main/java/com/xpn/xwiki/validation core/src/main/resources src/main/web/skins/default src/main/web/skins/default/ajax src/main/web/skins/xwiki10 src/main/web/yui src/main/web/yui/autocomplete src/test/java/com/xpn/xwiki/test src/test/resources
Ludovic Dubost
ludovic at users.forge.objectweb.org
Mon Oct 30 05:11:24 CET 2006
Author: ludovic
Date: 2006-10-30 05:11:22 +0100 (Mon, 30 Oct 2006)
New Revision: 1477
Added:
xwiki/trunk/core/src/main/java/com/xpn/xwiki/validation/XWikiValidationStatus.java
xwiki/trunk/src/main/web/skins/default/ajax/wzToolTip.js
xwiki/trunk/src/main/web/skins/default/info.gif
xwiki/trunk/src/main/web/skins/xwiki10/info.gif
xwiki/trunk/src/main/web/yui/autocomplete/
xwiki/trunk/src/main/web/yui/autocomplete/README
xwiki/trunk/src/main/web/yui/autocomplete/autocomplete-debug.js
xwiki/trunk/src/main/web/yui/autocomplete/autocomplete-min.js
xwiki/trunk/src/main/web/yui/autocomplete/autocomplete.js
Removed:
xwiki/trunk/core/src/main/java/com/xpn/xwiki/validation/XWikiValidationException.java
Modified:
xwiki/trunk/core/src/main/java/com/xpn/xwiki/XWiki.java
xwiki/trunk/core/src/main/java/com/xpn/xwiki/XWikiContext.java
xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/Context.java
xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/Document.java
xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/PropertyClass.java
xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/XWiki.java
xwiki/trunk/core/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java
xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/BaseClass.java
xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/PropertyClass.java
xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/PropertyMetaClass.java
xwiki/trunk/core/src/main/resources/ApplicationResources.properties
xwiki/trunk/core/src/main/resources/xwiki.hbm.xml
xwiki/trunk/src/test/java/com/xpn/xwiki/test/ClassAdvancedTest.java
xwiki/trunk/src/test/java/com/xpn/xwiki/test/XWikiDocumentTest.java
xwiki/trunk/src/test/resources/xwiki.hbm.xml
xwiki/trunk/xwiki.iml
xwiki/trunk/xwiki.iws
xwiki/trunk/xwikibase.iml
Log:
Finished server-side validation (client side still needed)
Added new fields toXML and fromXML
Added field tooltips
Added server side validation tests
Corrected captcha config column names xwiki.hbm.xml
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/XWiki.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/XWiki.java 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/XWiki.java 2006-10-30 04:11:22 UTC (rev 1477)
@@ -74,8 +74,6 @@
import com.xpn.xwiki.util.Util;
import com.xpn.xwiki.web.*;
import com.xpn.xwiki.web.includeservletasstring.IncludeServletAsString;
-import com.xpn.xwiki.validation.XWikiValidationInterface;
-import com.xpn.xwiki.validation.XWikiValidationException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.methods.GetMethod;
@@ -4167,20 +4165,7 @@
}
public boolean validateDocument(XWikiDocument doc, XWikiContext context) throws XWikiException {
- XWikiValidationException xwe;
- String validationScript = "";
- XWikiRequest req = context.getRequest();
- if (req!=null) {
- validationScript = req.get("xvalidation");
- }
- if ((validationScript==null)||(validationScript.trim().equals(""))) {
- validationScript = doc.getValidationScript();
- }
- if ((validationScript==null)||(validationScript.trim().equals(""))) {
- XWikiValidationInterface validObject = (XWikiValidationInterface) parseGroovyFromPage(validationScript, context);
- return validObject.validateDocument(doc, context);
- }
- return true;
+ return doc.validate(context);
}
public String getMessage(String item, XWikiContext context) {
@@ -4202,9 +4187,29 @@
return null;
return parseMessage(message, context);
}
-
- public String getUniquePageName(String space, XWikiContext context) {
- String pageName = generateRandomString(16);
- return getUniquePageName(space, pageName, context);
+
+ public String addTooltip(String html, String message, String params, XWikiContext context) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("<span onmouseover=\"");
+ buffer.append(params);
+ buffer.append("; return escape('");
+ buffer.append(message.replaceAll("'","\\'"));
+ buffer.append("');\">");
+ buffer.append(html);
+ buffer.append("</span>");
+ return buffer.toString();
}
+
+ public String addTooltipJS(XWikiContext context) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("<script type=\"text/javascript\" src=\"");
+ buffer.append(getSkinFile("ajax/wzToolTip.js", context));
+ buffer.append("\"></script>");
+ // buffer.append("<div id=\"dhtmltooltip\"></div>");
+ return buffer.toString();
+ }
+
+ public String addTooltip(String html, String message, XWikiContext context) {
+ return addTooltip(html, message, "this.WIDTH='300'", context);
+ }
}
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/XWikiContext.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/XWikiContext.java 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/XWikiContext.java 2006-10-30 04:11:22 UTC (rev 1477)
@@ -29,12 +29,11 @@
import com.xpn.xwiki.user.api.XWikiUser;
import com.xpn.xwiki.util.Util;
import com.xpn.xwiki.web.*;
+import com.xpn.xwiki.validation.XWikiValidationStatus;
import org.apache.xmlrpc.server.XmlRpcServer;
import java.net.URL;
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Map;
+import java.util.*;
public class XWikiContext extends Hashtable {
@@ -70,6 +69,8 @@
// Used to avoir reloading archives in the same request
private Map archiveCache = new HashMap();
+ private List displayedFields = new ArrayList();
+
public XWikiContext() {
}
@@ -322,5 +323,21 @@
public XWikiMessageTool getMessageTool() {
return ((XWikiMessageTool) get("msg"));
- }
+ }
+
+ public XWikiValidationStatus getValidationStatus() {
+ return (XWikiValidationStatus) get("validation_status");
+ }
+
+ public void setValidationStatus(XWikiValidationStatus status) {
+ put("validation_status", status);
+ }
+
+ public void addDisplayedField(String fieldname) {
+ displayedFields.add(fieldname);
+ }
+
+ public List getDisplayedFields() {
+ return displayedFields;
+ }
}
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/Context.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/Context.java 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/Context.java 2006-10-30 04:11:22 UTC (rev 1477)
@@ -24,12 +24,15 @@
package com.xpn.xwiki.api;
import com.xpn.xwiki.XWikiContext;
+import com.xpn.xwiki.validation.XWikiValidationStatus;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.web.XWikiRequest;
import com.xpn.xwiki.web.XWikiResponse;
import com.xpn.xwiki.web.XWikiURLFactory;
+import java.util.List;
+
public class Context extends Api {
public Context(XWikiContext context) {
@@ -238,4 +241,13 @@
public String getLinksQueryString() {
return context.getLinksQueryString();
}
+
+ public XWikiValidationStatus getValidationStatus() {
+ return context.getValidationStatus();
+ }
+
+ public List getDisplayedFields() {
+ return context.getDisplayedFields();
+ }
+
}
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/Document.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/Document.java 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/Document.java 2006-10-30 04:11:22 UTC (rev 1477)
@@ -702,6 +702,39 @@
currentObj = getObject(className, nb);
}
+ public String getActiveClass() {
+ if (currentObj==null)
+ return null;
+ else
+ return currentObj.getName();
+ }
+
+ public String displayPrettyName(String fieldname) {
+ if (currentObj == null)
+ return doc.displayPrettyName(fieldname, context);
+ else
+ return doc.displayPrettyName(fieldname, currentObj.getBaseObject(), context);
+ }
+
+ public String displayPrettyName(String fieldname, Object obj) {
+ if (obj == null)
+ return "";
+ return doc.displayPrettyName(fieldname, obj.getBaseObject(), context);
+ }
+
+ public String displayTooltip(String fieldname) {
+ if (currentObj == null)
+ return doc.displayTooltip(fieldname, context);
+ else
+ return doc.displayTooltip(fieldname, currentObj.getBaseObject(), context);
+ }
+
+ public String displayTooltip(String fieldname, Object obj) {
+ if (obj == null)
+ return "";
+ return doc.displayTooltip(fieldname, obj.getBaseObject(), context);
+ }
+
public String display(String fieldname) {
if (currentObj == null)
return doc.display(fieldname, context);
@@ -1260,4 +1293,7 @@
return attachment;
}
+ public boolean validate() throws XWikiException {
+ return doc.validate(context);
+ }
}
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/PropertyClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/PropertyClass.java 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/PropertyClass.java 2006-10-30 04:11:22 UTC (rev 1477)
@@ -1,23 +1,23 @@
-/*
- * Copyright 2006, 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.
- *
- */
+/*
+ * Copyright 2006, 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.api;
@@ -45,4 +45,21 @@
else
return null;
}
+
+ public String getPrettyName() {
+ return getBasePropertyClass().getPrettyName();
+ }
+
+ public String getValidationMessage() {
+ return getBasePropertyClass().getValidationMessage();
+ }
+
+ public String getValidationRegExp() {
+ return getBasePropertyClass().getValidationRegExp();
+ }
+
+ public String getTooltip() {
+ return getBasePropertyClass().getTooltip();
+ }
+
}
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/XWiki.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/XWiki.java 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/api/XWiki.java 2006-10-30 04:11:22 UTC (rev 1477)
@@ -39,6 +39,7 @@
import com.xpn.xwiki.stats.api.XWikiStatsService;
import com.xpn.xwiki.stats.impl.DocumentStats;
import com.xpn.xwiki.web.Utils;
+import com.xpn.xwiki.web.XWikiMessageTool;
import org.suigeneris.jrcs.diff.Chunk;
import java.awt.image.BufferedImage;
@@ -2068,17 +2069,52 @@
return new PropertyClass(xwiki.getPropertyClassFromName(propPath, context), context);
}
+ /**
+ * Generates a unique page name based on initial page name and already existing pages
+ * @param space
+ * @param name
+ * @return a unique page name
+ */
public String getUniquePageName(String space, String name){
- return "";// xwiki.getUniquePageName(space, name, context);
+ return xwiki.getUniquePageName(space, name, context);
}
+ /**
+ * Cleans up the page name to make it valid
+ * @param name
+ * @return A valid page name
+ */
public String clearName(String name){
return xwiki.clearName(name, context);
}
+ /**
+ * Inserts a tooltip using toolTip.js
+ * @param html HTML viewed
+ * @param message HTML Tooltip message
+ * @param params Parameters in Javascropt added to the tooltip config
+ * @return HTML with working tooltip
+ */
+ public String addTooltip(String html, String message, String params) {
+ return xwiki.addTooltip(html, message, params, context);
+ }
- public String getUniquePageName(String space){
- return xwiki.getUniquePageName(space, context);
+ /**
+ * Inserts a tooltip using toolTip.js
+ * @param html HTML viewed
+ * @param message HTML Tooltip message
+ * @return HTML with working tooltip
+ */
+ public String addTooltip(String html, String message) {
+ return xwiki.addTooltip(html, message, context);
}
+
+ /**
+ * Inserts the tooltip Javascript
+ * @return
+ */
+ public String addTooltipJS() {
+ return xwiki.addTooltipJS(context);
+ }
}
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/doc/XWikiDocument.java 2006-10-30 04:11:22 UTC (rev 1477)
@@ -30,6 +30,8 @@
import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
+import com.xpn.xwiki.validation.XWikiValidationInterface;
+import com.xpn.xwiki.validation.XWikiValidationStatus;
import com.xpn.xwiki.api.DocumentSection;
import com.xpn.xwiki.notify.XWikiNotificationRule;
import com.xpn.xwiki.objects.BaseCollection;
@@ -46,6 +48,7 @@
import com.xpn.xwiki.web.EditForm;
import com.xpn.xwiki.web.ObjectAddForm;
import com.xpn.xwiki.web.XWikiMessageTool;
+import com.xpn.xwiki.web.XWikiRequest;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -943,6 +946,54 @@
this.template = template;
}
+ public String displayPrettyName(String fieldname, XWikiContext context) {
+ try {
+ BaseObject object = getxWikiObject();
+ if (object == null)
+ object = getFirstObject(fieldname, context);
+ return displayPrettyName(fieldname, object, context);
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ public String displayPrettyName(String fieldname, BaseObject obj, XWikiContext context) {
+ try {
+ PropertyClass pclass = (PropertyClass) obj.getxWikiClass(context).get(fieldname);
+ return pclass.getPrettyName();
+ }
+ catch (Exception e) {
+ return "";
+ // return "||Exception showing field " + fieldname + ": " + e.getMessage() + "||";
+ }
+ }
+
+ public String displayTooltip(String fieldname, XWikiContext context) {
+ try {
+ BaseObject object = getxWikiObject();
+ if (object == null)
+ object = getFirstObject(fieldname, context);
+ return displayTooltip(fieldname, object, context);
+ } catch (Exception e) {
+ return "";
+ }
+ }
+
+ public String displayTooltip(String fieldname, BaseObject obj, XWikiContext context) {
+ try {
+ PropertyClass pclass = (PropertyClass) obj.getxWikiClass(context).get(fieldname);
+ String tooltip = pclass.getTooltip();
+ if ((tooltip!=null)&&(!tooltip.trim().equals(""))) {
+ String img = "<img src=\"" + context.getWiki().getSkinFile("info.gif", context) + "\" align=\"middle\" />";
+ return context.getWiki().addTooltip(img, tooltip, context);
+ } else
+ return "";
+ }
+ catch (Exception e) {
+ return "";
+ }
+ }
+
public String display(String fieldname, String type, BaseObject obj, XWikiContext context) {
try {
type = type.toLowerCase();
@@ -959,6 +1010,7 @@
String fcontent = pclass.displayView(fieldname, prefix, obj, context);
result.append(getRenderedContent(fcontent, context));
} else if (type.equals("edit")) {
+ context.addDisplayedField(fieldname);
result.append("{pre}");
pclass.displayEdit(result, fieldname, prefix, obj, context);
result.append("{/pre}");
@@ -1306,6 +1358,7 @@
doc.setCreator(getCreator());
doc.setDefaultLanguage(getDefaultLanguage());
doc.setDefaultTemplate(getDefaultTemplate());
+ doc.setValidationScript(getValidationScript());
doc.setLanguage(getLanguage());
doc.setTranslation(getTranslation());
doc.setxWikiClass((BaseClass) getxWikiClass().clone());
@@ -1387,6 +1440,12 @@
if (!getTemplate().equals(doc.getTemplate()))
return false;
+ if (!getDefaultTemplate().equals(doc.getDefaultTemplate()))
+ return false;
+
+ if (!getValidationScript().equals(doc.getValidationScript()))
+ return false;
+
if (!getxWikiClass().equals(doc.getxWikiClass()))
return false;
@@ -1552,6 +1611,14 @@
el.addText(getTemplate());
docel.add(el);
+ el = new DOMElement("defaultTemplate");
+ el.addText(getDefaultTemplate());
+ docel.add(el);
+
+ el = new DOMElement("validationScript");
+ el.addText(getValidationScript());
+ docel.add(el);
+
List alist = getAttachmentList();
for (int ai = 0; ai < alist.size(); ai++) {
XWikiAttachment attach = (XWikiAttachment) alist.get(ai);
@@ -1699,6 +1766,8 @@
setLanguage(getElement(docel, "language"));
setDefaultLanguage(getElement(docel, "defaultLanguage"));
setTitle(getElement(docel,"title"));
+ setDefaultTemplate(getElement(docel,"defaultTemplate"));
+ setValidationScript(getElement(docel,"validationScript"));
String strans = getElement(docel, "translation");
if ((strans == null) || strans.equals(""))
@@ -2592,7 +2661,10 @@
}
public String getDefaultTemplate() {
- return defaultTemplate;
+ if (defaultTemplate==null)
+ return "";
+ else
+ return defaultTemplate;
}
public void setDefaultTemplate(String defaultTemplate) {
@@ -2956,6 +3028,9 @@
}
public String getValidationScript() {
+ if (validationScript==null)
+ return "";
+ else
return validationScript;
}
@@ -2981,4 +3056,43 @@
}
}
+ public boolean validate(XWikiContext context) throws XWikiException {
+ boolean isValid = true;
+ for (Iterator it = getxWikiObjects().keySet().iterator(); it.hasNext();) {
+ String classname = (String) it.next();
+ BaseClass bclass = context.getWiki().getClass(classname, context);
+ Vector objects = getObjects(classname);
+
+ for (int i = 0; i < objects.size(); i++) {
+ BaseObject obj = (BaseObject) objects.get(i);
+ if (obj != null) {
+ isValid &= bclass.validateObject(obj, context);
+ }
+ }
+ }
+
+ String validationScript = "";
+ XWikiRequest req = context.getRequest();
+ if (req!=null) {
+ validationScript = req.get("xvalidation");
+ }
+ if ((validationScript==null)||(validationScript.trim().equals(""))) {
+ validationScript = getValidationScript();
+ }
+ if ((validationScript!=null)&&(!validationScript.trim().equals(""))) {
+ isValid &= executeValidationScript(context, validationScript);
+
+ }
+ return isValid;
+ }
+
+ private boolean executeValidationScript(XWikiContext context, String validationScript) throws XWikiException {
+ try {
+ XWikiValidationInterface validObject = (XWikiValidationInterface) context.getWiki().parseGroovyFromPage(validationScript, context);
+ return validObject.validateDocument(this, context);
+ } catch (Throwable e) {
+ XWikiValidationStatus.addExceptionToContext(getFullName(), "", e, context);
+ return false;
+ }
+ }
}
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/BaseClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/BaseClass.java 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/BaseClass.java 2006-10-30 04:11:22 UTC (rev 1477)
@@ -25,6 +25,8 @@
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
+import com.xpn.xwiki.validation.XWikiValidationInterface;
+import com.xpn.xwiki.validation.XWikiValidationStatus;
import com.xpn.xwiki.objects.BaseCollection;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.BaseProperty;
@@ -163,9 +165,12 @@
if (!getDefaultWeb().equals(bclass.getDefaultWeb()))
return false;
+ if (!getValidationScript().equals(bclass.getValidationScript()))
+ return false;
+
if (!getNameField().equals(bclass.getNameField()))
return false;
-
+
return true;
}
@@ -207,6 +212,11 @@
el.addText((getNameField()==null) ? "" : getNameField());
cel.add(el);
+ el = new DOMElement("validationScript");
+ el.addText((getValidationScript()==null) ? "" : getValidationScript());
+ cel.add(el);
+
+
Iterator it = getFieldList().iterator();
while (it.hasNext()) {
PropertyClass bprop = (PropertyClass)it.next();
@@ -250,6 +260,12 @@
j++;
}
+ Element valel = cel.element("validationScript");
+ if (valel!=null) {
+ setValidationScript(valel.getText());
+ j++;
+ }
+
List list = cel.elements();
for (int i=j;i<list.size();i++) {
Element pcel = (Element) list.get(i);
@@ -667,4 +683,31 @@
return validationScript;
}
+ public boolean validateObject(BaseObject obj, XWikiContext context) throws XWikiException {
+ boolean isValid = true;
+ Object[] props = (Object[]) getPropertyNames();
+ for (int i=0;i<props.length;i++) {
+ String propname = (String) props[i];
+ BaseProperty property = (BaseProperty) obj.get(propname);
+ PropertyClass propclass = (PropertyClass) get(propname);
+ isValid &= propclass.validateProperty(property, context);
+ }
+
+ String validSript = getValidationScript();
+ if ((validSript!=null)&&(!validSript.trim().equals("")))
+ isValid &= executeValidationScript(obj, validSript, context);
+
+ return isValid;
+ }
+
+ private boolean executeValidationScript(BaseObject obj, String validationScript, XWikiContext context) throws XWikiException {
+ try {
+ XWikiValidationInterface validObject = (XWikiValidationInterface) context.getWiki().parseGroovyFromPage(validationScript, context);
+ return validObject.validateObject(obj, context);
+ } catch (Throwable e) {
+ XWikiValidationStatus.addExceptionToContext(getName(), "", e, context);
+ return false;
+ }
+ }
+
}
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/PropertyClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/PropertyClass.java 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/classes/PropertyClass.java 2006-10-30 04:11:22 UTC (rev 1477)
@@ -25,6 +25,7 @@
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
+import com.xpn.xwiki.validation.XWikiValidationStatus;
import com.xpn.xwiki.objects.BaseCollection;
import com.xpn.xwiki.objects.BaseObject;
import com.xpn.xwiki.objects.BaseProperty;
@@ -47,7 +48,6 @@
private BaseClass object;
private int id;
private PropertyMetaClass pMetaClass;
- private String validationRegExp;
public PropertyClass() {
}
@@ -263,6 +263,26 @@
setStringValue("prettyName", prettyName);
}
+ public String getTooltip() {
+ return getLargeStringValue("tooltip");
+ }
+
+ public void setTooltip(String tooltip) {
+ setLargeStringValue("tooltip", tooltip);
+ }
+
+ public String getTranslatedPrettyName(XWikiContext context) {
+ String msgName = className + "_" + getName();
+ if ((context==null)||(context.getWiki()==null))
+ return getPrettyName();
+
+ String prettyName = context.getWiki().getMessage(msgName, context);
+ if (prettyName.equals(msgName))
+ return getPrettyName();
+ else
+ return prettyName;
+ }
+
public int getNumber() {
return getIntValue("number");
}
@@ -366,11 +386,40 @@
}
public void setValidationRegExp(String validationRegExp) {
- this.validationRegExp = validationRegExp;
+ setStringValue("validationRegExp", validationRegExp);
}
public String getValidationRegExp() {
- return validationRegExp;
+ return getStringValue("validationRegExp");
}
+ public String getValidationMessage() {
+ return getStringValue("validationMessage");
+ }
+
+ public void setValidationMessage(String validationMessage) {
+ setStringValue("validationMessage", validationMessage);
+ }
+
+ public boolean validateProperty(BaseProperty property, XWikiContext context) {
+ boolean isValid = false;
+ String regexp = getValidationRegExp();
+ if ((regexp==null)||(regexp.trim().equals("")))
+ return true;
+
+ String value = ((property==null)||(property.getValue()==null)) ? "" : property.getValue().toString();
+ try {
+ if (context.getUtil().match(regexp, value))
+ return true;
+ else {
+ XWikiValidationStatus.addErrorToContext((getObject()==null) ? "" : getObject().getClassName(), getName(), getTranslatedPrettyName(context), getValidationMessage(), context);
+ return false;
+ }
+ } catch (Exception e) {
+ XWikiValidationStatus.addExceptionToContext(getObject().getClassName(), getName(), e, context);
+ return false;
+ }
+
+ }
+
}
Modified: xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/PropertyMetaClass.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/PropertyMetaClass.java 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/objects/meta/PropertyMetaClass.java 2006-10-30 04:11:22 UTC (rev 1477)
@@ -49,6 +49,13 @@
prettyname_class.setSize(40);
safeput("prettyName", prettyname_class);
+ TextAreaClass tooltip_class = new TextAreaClass(this);
+ tooltip_class.setName("tooltip");
+ tooltip_class.setPrettyName("Tooltip");
+ tooltip_class.setSize(60);
+ tooltip_class.setRows(5);
+ safeput("tooltip", tooltip_class);
+
TextAreaClass customdisplay_class = new TextAreaClass(this);
customdisplay_class.setName("customDisplay");
customdisplay_class.setPrettyName("Custom Display");
@@ -73,6 +80,12 @@
validationRegExp_class.setPrettyName("Validation Regular Expression");
validationRegExp_class.setSize(40);
safeput("validationRegExp", validationRegExp_class);
+
+ StringClass validationMessage_class = new StringClass(this);
+ validationMessage_class.setName("validationMessage");
+ validationMessage_class.setPrettyName("Validation Message");
+ validationMessage_class.setSize(80);
+ safeput("validationMessage", validationMessage_class);
}
public BaseCollection getObject() {
Deleted: xwiki/trunk/core/src/main/java/com/xpn/xwiki/validation/XWikiValidationException.java
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/validation/XWikiValidationException.java 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/validation/XWikiValidationException.java 2006-10-30 04:11:22 UTC (rev 1477)
@@ -1,27 +0,0 @@
-/*
- * Copyright 2006, 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.
- *
- * @author jeremi
- */
-package com.xpn.xwiki.validation;
-
-import com.xpn.xwiki.XWikiException;
-
-public class XWikiValidationException extends XWikiException {
-}
Copied: xwiki/trunk/core/src/main/java/com/xpn/xwiki/validation/XWikiValidationStatus.java (from rev 1408, xwiki/trunk/core/src/main/java/com/xpn/xwiki/validation/XWikiValidationException.java)
===================================================================
--- xwiki/trunk/core/src/main/java/com/xpn/xwiki/validation/XWikiValidationException.java 2006-10-19 02:23:21 UTC (rev 1408)
+++ xwiki/trunk/core/src/main/java/com/xpn/xwiki/validation/XWikiValidationStatus.java 2006-10-30 04:11:22 UTC (rev 1477)
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2006, 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.
+ *
+ * @author jeremi
+ */
+package com.xpn.xwiki.validation;
+
+import com.xpn.xwiki.XWikiContext;
+
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.velocity.VelocityContext;
+
+public class XWikiValidationStatus {
+
+ private List errorObjects = new ArrayList();
+ private List propertyErrors = new ArrayList();
+ private List errors = new ArrayList();
+ private List exceptions = new ArrayList();
+
+
+ public XWikiValidationStatus() {
+ }
+
+ public static void addErrorToContext(String className, String propName, String propPrettyName, String validationMessage, XWikiContext context) {
+ XWikiValidationStatus errors = getValidationStatus(context);
+ errors.addError(className, propName, propPrettyName, validationMessage, context);
+
+ }
+
+ private static XWikiValidationStatus getValidationStatus(XWikiContext context) {
+ XWikiValidationStatus errors = (XWikiValidationStatus) context.getValidationStatus();
+ if (errors==null) {
+ errors = new XWikiValidationStatus();
+ context.setValidationStatus(errors);
+ }
+ return errors;
+ }
+
+ public static void addExceptionToContext(String className, String propName, Throwable e, XWikiContext context) {
+ XWikiValidationStatus errors = getValidationStatus(context);
+ errors.addException(className, propName, e, context);
+ }
+
+ public void addError(String className, String propName, String propPrettyName, String validationMessage, XWikiContext context) {
+ getErrorObjects().add(className);
+ getPropertyErrors().add(propName);
+
+ if ((validationMessage!=null)&&(!validationMessage.trim().equals("")))
+ getErrors().add(validationMessage);
+ else {
+ VelocityContext vcontext = (VelocityContext) context.get("vcontext");
+ if (vcontext==null)
+ getErrors().add("Validation error for property " + propPrettyName + " in class " + className);
+ else {
+ vcontext.put("className", className);
+ vcontext.put("propName", propPrettyName);
+ String message = context.getWiki().parseMessage("validation_error", context);
+ getErrors().add(message);
+ }
+ }
+ }
+
+ public void addException(String className, String propName, Throwable e, XWikiContext context) {
+ getExceptions().add(e);
+ }
+
+ public boolean hasExceptions() {
+ return (getExceptions().size()>0);
+ }
+
+ public List getExceptions() {
+ return exceptions;
+ }
+
+ public List getErrorObjects() {
+ return errorObjects;
+ }
+
+ public void setErrorObjects(List errorObjects) {
+ this.errorObjects = errorObjects;
+ }
+
+ public List getPropertyErrors() {
+ return propertyErrors;
+ }
+
+ public void setPropertyErrors(List propertyErrors) {
+ this.propertyErrors = propertyErrors;
+ }
+
+ public List getErrors() {
+ return errors;
+ }
+
+ public void setErrors(List errors) {
+ this.errors = errors;
+ }
+
+ public void setExceptions(List exceptions) {
+ this.exceptions = exceptions;
+ }
+}
Modified: xwiki/trunk/core/src/main/resources/ApplicationResources.properties
===================================================================
--- xwiki/trunk/core/src/main/resources/ApplicationResources.properties 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/resources/ApplicationResources.properties 2006-10-30 04:11:22 UTC (rev 1477)
@@ -488,4 +488,5 @@
comment_anonymous=Anonymous
comment_registered=Registered
comment=Comment
-confirmcommentnotcorrect=Confirm to avoid spam robots. Please try again !!
\ No newline at end of file
+confirmcommentnotcorrect=Confirm to avoid spam robots. Please try again !!
+validationerror=Field $propName is incorrect.
\ No newline at end of file
Modified: xwiki/trunk/core/src/main/resources/xwiki.hbm.xml
===================================================================
--- xwiki/trunk/core/src/main/resources/xwiki.hbm.xml 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/core/src/main/resources/xwiki.hbm.xml 2006-10-30 04:11:22 UTC (rev 1477)
@@ -39,11 +39,11 @@
</property>
<property name="contentUpdateDate" type="timestamp">
- <column name="XWD_CONTENT_UPDATE_DATE" />
+ <column name="XWD_CONTENT_UPDATE_DATE" not-null="true" />
</property>
<property name="creationDate" type="timestamp">
- <column name="XWD_CREATION_DATE" />
+ <column name="XWD_CREATION_DATE" not-null="true" />
</property>
<property name="author" type="string">
@@ -88,11 +88,11 @@
</property>
<property name="defaultTemplate" type="string">
- <column name="XWD_DEFAULT_TEMPLATE" />
+ <column name="XWD_DEFAULT_TEMPLATE" not-null="true"/>
</property>
<property name="validationScript" type="string">
- <column name="XWD_VALIDATION_SCRIPT" />
+ <column name="XWD_VALIDATION_SCRIPT" not-null="true" />
</property>
</class>
@@ -103,7 +103,7 @@
<generator class="assigned" />
</id>
<property name="archive" type="string">
- <column name="XWD_ARCHIVE" length="200000" not-null="false"/>
+ <column name="XWD_ARCHIVE" length="200000" not-null="false" />
</property>
</class>
@@ -718,19 +718,19 @@
<column name="XWP_LANGUAGES" length="255" />
</property>
<property name="registration_anonymous" type="string">
- <column name="XWP_REGISTRATION_ANONYMUOS" length="255" />
+ <column name="XWP_REGISTRATION_ANONYMOUS" length="255" />
</property>
<property name="registration_registered" type="string">
<column name="XWP_REGISTRATION_REGISTERED" length="255" />
</property>
<property name="edit_anonymous" type="string">
- <column name="XWP_EDIT_ANONYMUOS" length="255" />
+ <column name="XWP_EDIT_ANONYMOUS" length="255" />
</property>
<property name="edit_registered" type="string">
<column name="XWP_EDIT_REGISTERED" length="255" />
</property>
<property name="comment_anonymous" type="string">
- <column name="XWP_COMMENT_ANONYMUOS" length="255" />
+ <column name="XWP_COMMENT_ANONYMOUS" length="255" />
</property>
<property name="comment_registered" type="string">
<column name="XWP_COMMENT_REGISTERED" length="255" />
Added: xwiki/trunk/src/main/web/skins/default/ajax/wzToolTip.js
===================================================================
--- xwiki/trunk/src/main/web/skins/default/ajax/wzToolTip.js 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/src/main/web/skins/default/ajax/wzToolTip.js 2006-10-30 04:11:22 UTC (rev 1477)
@@ -0,0 +1,478 @@
+/* This notice must be untouched at all times.
+
+wz_tooltip.js v. 3.38
+
+The latest version is available at
+http://www.walterzorn.com
+or http://www.devira.com
+or http://www.walterzorn.de
+
+Copyright (c) 2002-2005 Walter Zorn. All rights reserved.
+Created 1. 12. 2002 by Walter Zorn (Web: http://www.walterzorn.com )
+Last modified: 9. 12. 2005
+
+Cross-browser tooltips working even in Opera 5 and 6,
+as well as in NN 4, Gecko-Browsers, IE4+, Opera 7+ and Konqueror.
+No onmouseouts required.
+Appearance of tooltips can be individually configured
+via commands within the onmouseovers.
+
+LICENSE: LGPL
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License (LGPL) as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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.
+
+For more details on the GNU Lesser General Public License,
+see http://www.gnu.org/copyleft/lesser.html
+*/
+
+
+
+//////////////// GLOBAL TOOPTIP CONFIGURATION /////////////////////
+var ttAbove = false; // tooltip above mousepointer? Alternative: true
+var ttBgColor = "#e6ecff";
+var ttBgImg = ""; // path to background image;
+var ttBorderColor = "#003399";
+var ttBorderWidth = 1;
+var ttDelay = 500; // time span until tooltip shows up [milliseconds]
+var ttFontColor = "#000066";
+var ttFontFace = "arial,helvetica,sans-serif";
+var ttFontSize = "11px";
+var ttFontWeight = "normal"; // alternative: "bold";
+var ttLeft = false; // tooltip on the left of the mouse? Alternative: true
+var ttOffsetX = 12; // horizontal offset of left-top corner from mousepointer
+var ttOffsetY = 15; // vertical offset "
+var ttOpacity = 100; // opacity of tooltip in percent (must be integer between 0 and 100)
+var ttPadding = 3; // spacing between border and content
+var ttShadowColor = "";
+var ttShadowWidth = 0;
+var ttStatic = false; // tooltip NOT move with the mouse? Alternative: true
+var ttSticky = false; // do NOT hide tooltip on mouseout? Alternative: true
+var ttTemp = 0; // time span after which the tooltip disappears; 0 (zero) means "infinite timespan"
+var ttTextAlign = "left";
+var ttTitleColor = "#ffffff"; // color of caption text
+var ttWidth = 300;
+//////////////////// END OF TOOLTIP CONFIG ////////////////////////
+
+
+
+////////////// TAGS WITH TOOLTIP FUNCTIONALITY ////////////////////
+// List may be extended or shortened:
+var tt_tags = new Array("a","area","b","big","caption","center","code","dd","div","dl","dt","em","h1","h2","h3","h4","h5","h6","i","img","input","li","map","ol","p","pre","s", "select", "small","span","strike","strong","sub","sup","table","td","th","tr","tt","u","var","ul","layer");
+/////////////////////////////////////////////////////////////////////
+
+
+
+///////// DON'T CHANGE ANYTHING BELOW THIS LINE /////////////////////
+var tt_obj = null, // current tooltip
+tt_ifrm = null, // iframe to cover windowed controls in IE
+tt_objW = 0, tt_objH = 0, // width and height of tt_obj
+tt_objX = 0, tt_objY = 0,
+tt_offX = 0, tt_offY = 0,
+xlim = 0, ylim = 0, // right and bottom borders of visible client area
+tt_sup = false, // true if T_ABOVE cmd
+tt_sticky = false, // tt_obj sticky?
+tt_wait = false,
+tt_act = false, // tooltip visibility flag
+tt_sub = false, // true while tooltip below mousepointer
+tt_u = "undefined",
+tt_mf = null, // stores previous mousemove evthandler
+// Opera: disable href when hovering <a>
+tt_tag = null; // stores hovered dom node, href and previous statusbar txt
+
+
+var tt_db = (document.compatMode && document.compatMode != "BackCompat")? document.documentElement : document.body? document.body : null,
+tt_n = navigator.userAgent.toLowerCase(),
+tt_nv = navigator.appVersion;
+// Browser flags
+var tt_op = !!(window.opera && document.getElementById),
+tt_op6 = tt_op && !document.defaultView,
+tt_op7 = tt_op && !tt_op6,
+tt_ie = tt_n.indexOf("msie") != -1 && document.all && tt_db && !tt_op,
+tt_ie6 = tt_ie && parseFloat(tt_nv.substring(tt_nv.indexOf("MSIE")+5)) >= 5.5,
+tt_n4 = (document.layers && typeof document.classes != tt_u),
+tt_n6 = (!tt_op && document.defaultView && typeof document.defaultView.getComputedStyle != tt_u),
+tt_w3c = !tt_ie && !tt_n6 && !tt_op && document.getElementById;
+
+function tt_Int(t_x)
+{
+ var t_y;
+ return isNaN(t_y = parseInt(t_x))? 0 : t_y;
+}
+function wzReplace(t_x, t_y)
+{
+ var t_ret = "",
+ t_str = this,
+ t_xI;
+ while((t_xI = t_str.indexOf(t_x)) != -1)
+ {
+ t_ret += t_str.substring(0, t_xI) + t_y;
+ t_str = t_str.substring(t_xI + t_x.length);
+ }
+ return t_ret+t_str;
+}
+String.prototype.wzReplace = wzReplace;
+function tt_N4Tags(tagtyp, t_d, t_y)
+{
+ t_d = t_d || document;
+ t_y = t_y || new Array();
+ var t_x = (tagtyp=="a")? t_d.links : t_d.layers;
+ for(var z = t_x.length; z--;) t_y[t_y.length] = t_x[z];
+ for(z = t_d.layers.length; z--;) t_y = tt_N4Tags(tagtyp, t_d.layers[z].document, t_y);
+ return t_y;
+}
+function tt_Htm(tt, t_id, txt)
+{
+ var t_bgc = (typeof tt.T_BGCOLOR != tt_u)? tt.T_BGCOLOR : ttBgColor,
+ t_bgimg = (typeof tt.T_BGIMG != tt_u)? tt.T_BGIMG : ttBgImg,
+ t_bc = (typeof tt.T_BORDERCOLOR != tt_u)? tt.T_BORDERCOLOR : ttBorderColor,
+ t_bw = (typeof tt.T_BORDERWIDTH != tt_u)? tt.T_BORDERWIDTH : ttBorderWidth,
+ t_ff = (typeof tt.T_FONTFACE != tt_u)? tt.T_FONTFACE : ttFontFace,
+ t_fc = (typeof tt.T_FONTCOLOR != tt_u)? tt.T_FONTCOLOR : ttFontColor,
+ t_fsz = (typeof tt.T_FONTSIZE != tt_u)? tt.T_FONTSIZE : ttFontSize,
+ t_fwght = (typeof tt.T_FONTWEIGHT != tt_u)? tt.T_FONTWEIGHT : ttFontWeight,
+ t_opa = (typeof tt.T_OPACITY != tt_u)? tt.T_OPACITY : ttOpacity,
+ t_padd = (typeof tt.T_PADDING != tt_u)? tt.T_PADDING : ttPadding,
+ t_shc = (typeof tt.T_SHADOWCOLOR != tt_u)? tt.T_SHADOWCOLOR : (ttShadowColor || 0),
+ t_shw = (typeof tt.T_SHADOWWIDTH != tt_u)? tt.T_SHADOWWIDTH : (ttShadowWidth || 0),
+ t_algn = (typeof tt.T_TEXTALIGN != tt_u)? tt.T_TEXTALIGN : ttTextAlign,
+ t_tit = (typeof tt.T_TITLE != tt_u)? tt.T_TITLE : "",
+ t_titc = (typeof tt.T_TITLECOLOR != tt_u)? tt.T_TITLECOLOR : ttTitleColor,
+ t_w = (typeof tt.T_WIDTH != tt_u)? tt.T_WIDTH : ttWidth;
+ if(t_shc || t_shw)
+ {
+ t_shc = t_shc || "#cccccc";
+ t_shw = t_shw || 5;
+ }
+ if(tt_n4 && (t_fsz == "10px" || t_fsz == "11px")) t_fsz = "12px";
+
+ var t_optx = (tt_n4? '' : tt_n6? ('-moz-opacity:'+(t_opa/100.0)) : tt_ie? ('filter:Alpha(opacity='+t_opa+')') : ('opacity:'+(t_opa/100.0))) + ';';
+ var t_y = '<div id="'+t_id+'" style="position:absolute;z-index:1010;';
+ t_y += 'left:0px;top:0px;width:'+(t_w+t_shw)+'px;visibility:'+(tt_n4? 'hide' : 'hidden')+';'+t_optx+'">' +
+ '<table border="0" cellpadding="0" cellspacing="0"'+(t_bc? (' bgcolor="'+t_bc+'" style="background:'+t_bc+';"') : '')+' width="'+t_w+'">';
+ if(t_tit)
+ {
+ t_y += '<tr><td style="padding-left:3px;padding-right:3px;" align="'+t_algn+'"><font color="'+t_titc+'" face="'+t_ff+'" ' +
+ 'style="color:'+t_titc+';font-family:'+t_ff+';font-size:'+t_fsz+';"><b>' +
+ (tt_n4? ' ' : '')+t_tit+'</b></font></td></tr>';
+ }
+ t_y += '<tr><td><table border="0" cellpadding="'+t_padd+'" cellspacing="'+t_bw+'" width="100%">' +
+ '<tr><td'+(t_bgc? (' bgcolor="'+t_bgc+'"') : '')+(t_bgimg? ' background="'+t_bgimg+'"' : '')+' style="text-align:'+t_algn+';';
+ if(tt_n6) t_y += 'padding:'+t_padd+'px;';
+ t_y += '" align="'+t_algn+'"><font color="'+t_fc+'" face="'+t_ff+'"' +
+ ' style="color:'+t_fc+';font-family:'+t_ff+';font-size:'+t_fsz+';font-weight:'+t_fwght+';">';
+ if(t_fwght == 'bold') t_y += '<b>';
+ t_y += txt;
+ if(t_fwght == 'bold') t_y += '</b>';
+ t_y += '</font></td></tr></table></td></tr></table>';
+ if(t_shw)
+ {
+ var t_spct = Math.round(t_shw*1.3);
+ if(tt_n4)
+ {
+ t_y += '<layer bgcolor="'+t_shc+'" left="'+t_w+'" top="'+t_spct+'" width="'+t_shw+'" height="0"></layer>' +
+ '<layer bgcolor="'+t_shc+'" left="'+t_spct+'" align="bottom" width="'+(t_w-t_spct)+'" height="'+t_shw+'"></layer>';
+ }
+ else
+ {
+ t_optx = tt_n6? '-moz-opacity:0.85;' : tt_ie? 'filter:Alpha(opacity=85);' : 'opacity:0.85;';
+ t_y += '<div id="'+t_id+'R" style="position:absolute;background:'+t_shc+';left:'+t_w+'px;top:'+t_spct+'px;width:'+t_shw+'px;height:1px;overflow:hidden;'+t_optx+'"></div>' +
+ '<div style="position:relative;background:'+t_shc+';left:'+t_spct+'px;top:0px;width:'+(t_w-t_spct)+'px;height:'+t_shw+'px;overflow:hidden;'+t_optx+'"></div>';
+ }
+ }
+ return(t_y+'</div>' +
+ (tt_ie6 ? '<iframe id="TTiEiFrM" src="javascript:false" scrolling="no" frameborder="0" style="filter:Alpha(opacity=0);position:absolute;top:0px;left:0px;display:none;"></iframe>' : ''));
+}
+function tt_EvX(t_e)
+{
+ var t_y = tt_Int(t_e.pageX || t_e.clientX || 0) +
+ tt_Int(tt_ie? tt_db.scrollLeft : 0) +
+ tt_offX;
+ if(t_y > xlim) t_y = xlim;
+ var t_scr = tt_Int(window.pageXOffset || (tt_db? tt_db.scrollLeft : 0) || 0);
+ if(t_y < t_scr) t_y = t_scr;
+ return t_y;
+}
+function tt_EvY(t_e)
+{
+ var t_y = tt_Int(t_e.pageY || t_e.clientY || 0) +
+ tt_Int(tt_ie? tt_db.scrollTop : 0);
+ if(tt_sup) t_y -= (tt_objH + tt_offY - 15);
+ else if(t_y > ylim || !tt_sub && t_y > ylim-24)
+ {
+ t_y -= (tt_objH + 5);
+ tt_sub = false;
+ }
+ else
+ {
+ t_y += tt_offY;
+ tt_sub = true;
+ }
+ return t_y;
+}
+function tt_ReleasMov()
+{
+ if(document.onmousemove == tt_Move)
+ {
+ if(!tt_mf && document.releaseEvents) document.releaseEvents(Event.MOUSEMOVE);
+ document.onmousemove = tt_mf;
+ }
+}
+function tt_ShowIfrm(t_x)
+{
+ if(!tt_obj || !tt_ifrm) return;
+ if(t_x)
+ {
+ tt_ifrm.style.width = tt_objW+'px';
+ tt_ifrm.style.height = tt_objH+'px';
+ tt_ifrm.style.display = "block";
+ }
+ else tt_ifrm.style.display = "none";
+}
+function tt_GetDiv(t_id)
+{
+ return(
+ tt_n4? (document.layers[t_id] || null)
+ : tt_ie? (document.all[t_id] || null)
+ : (document.getElementById(t_id) || null)
+ );
+}
+function tt_GetDivW()
+{
+ return tt_Int(
+ tt_n4? tt_obj.clip.width
+ : (tt_obj.style.pixelWidth || tt_obj.offsetWidth)
+ );
+}
+function tt_GetDivH()
+{
+ return tt_Int(
+ tt_n4? tt_obj.clip.height
+ : (tt_obj.style.pixelHeight || tt_obj.offsetHeight)
+ );
+}
+
+// Compat with DragDrop Lib: Ensure that z-index of tooltip is lifted beyond toplevel dragdrop element
+function tt_SetDivZ()
+{
+ var t_i = tt_obj.style || tt_obj;
+ if(t_i)
+ {
+ if(window.dd && dd.z)
+ t_i.zIndex = Math.max(dd.z+1, t_i.zIndex);
+ if(tt_ifrm) tt_ifrm.style.zIndex = t_i.zIndex-1;
+ }
+}
+function tt_SetDivPos(t_x, t_y)
+{
+ var t_i = tt_obj.style || tt_obj;
+ var t_px = (tt_op6 || tt_n4)? '' : 'px';
+ t_i.left = (tt_objX = t_x) + t_px;
+ t_i.top = (tt_objY = t_y) + t_px;
+ if(tt_ifrm)
+ {
+ tt_ifrm.style.left = t_i.left;
+ tt_ifrm.style.top = t_i.top;
+ }
+}
+function tt_ShowDiv(t_x)
+{
+ tt_ShowIfrm(t_x);
+ if(tt_n4) tt_obj.visibility = t_x? 'show' : 'hide';
+ else tt_obj.style.visibility = t_x? 'visible' : 'hidden';
+ tt_act = t_x;
+}
+function tt_OpDeHref(t_e)
+{
+ var t_tag;
+ if(t_e)
+ {
+ t_tag = t_e.target;
+ while(t_tag)
+ {
+ if(t_tag.hasAttribute("href"))
+ {
+ tt_tag = t_tag
+ tt_tag.t_href = tt_tag.getAttribute("href");
+ tt_tag.removeAttribute("href");
+ tt_tag.style.cursor = "hand";
+ tt_tag.onmousedown = tt_OpReHref;
+ tt_tag.stats = window.status;
+ window.status = tt_tag.t_href;
+ break;
+ }
+ t_tag = t_tag.parentElement;
+ }
+ }
+}
+function tt_OpReHref()
+{
+ if(tt_tag)
+ {
+ tt_tag.setAttribute("href", tt_tag.t_href);
+ window.status = tt_tag.stats;
+ tt_tag = null;
+ }
+}
+function tt_Show(t_e, t_id, t_sup, t_delay, t_fix, t_left, t_offx, t_offy, t_static, t_sticky, t_temp)
+{
+ if(tt_obj) tt_Hide();
+ tt_mf = document.onmousemove || null;
+ if(window.dd && (window.DRAG && tt_mf == DRAG || window.RESIZE && tt_mf == RESIZE)) return;
+ var t_sh, t_h;
+
+ tt_obj = tt_GetDiv(t_id);
+ if(tt_obj)
+ {
+ t_e = t_e || window.event;
+ tt_sub = !(tt_sup = t_sup);
+ tt_sticky = t_sticky;
+ tt_objW = tt_GetDivW();
+ tt_objH = tt_GetDivH();
+ tt_offX = t_left? -(tt_objW+t_offx) : t_offx;
+ tt_offY = t_offy;
+ if(tt_op7) tt_OpDeHref(t_e);
+ if(tt_n4)
+ {
+ if(tt_obj.document.layers.length)
+ {
+ t_sh = tt_obj.document.layers[0];
+ t_sh.clip.height = tt_objH - Math.round(t_sh.clip.width*1.3);
+ }
+ }
+ else
+ {
+ t_sh = tt_GetDiv(t_id+'R');
+ if(t_sh)
+ {
+ t_h = tt_objH - tt_Int(t_sh.style.pixelTop || t_sh.style.top || 0);
+ if(typeof t_sh.style.pixelHeight != tt_u) t_sh.style.pixelHeight = t_h;
+ else t_sh.style.height = t_h+'px';
+ }
+ }
+
+ xlim = tt_Int((tt_db && tt_db.clientWidth)? tt_db.clientWidth : window.innerWidth) +
+ tt_Int(window.pageXOffset || (tt_db? tt_db.scrollLeft : 0) || 0) -
+ tt_objW -
+ (tt_n4? 21 : 0);
+ ylim = tt_Int(window.innerHeight || tt_db.clientHeight) +
+ tt_Int(window.pageYOffset || (tt_db? tt_db.scrollTop : 0) || 0) -
+ tt_objH - tt_offY;
+
+ tt_SetDivZ();
+ if(t_fix) tt_SetDivPos(tt_Int((t_fix = t_fix.split(','))[0]), tt_Int(t_fix[1]));
+ else tt_SetDivPos(tt_EvX(t_e), tt_EvY(t_e));
+
+ var t_txt = 'tt_ShowDiv(\'true\');';
+ if(t_sticky) t_txt += '{'+
+ 'tt_ReleasMov();'+
+ 'window.tt_upFunc = document.onmouseup || null;'+
+ 'if(document.captureEvents) document.captureEvents(Event.MOUSEUP);'+
+ 'document.onmouseup = new Function("window.setTimeout(\'tt_Hide();\', 10);");'+
+ '}';
+ else if(t_static) t_txt += 'tt_ReleasMov();';
+ if(t_temp > 0) t_txt += 'window.tt_rtm = window.setTimeout(\'tt_sticky = false; tt_Hide();\','+t_temp+');';
+ window.tt_rdl = window.setTimeout(t_txt, t_delay);
+
+ if(!t_fix)
+ {
+ if(document.captureEvents) document.captureEvents(Event.MOUSEMOVE);
+ document.onmousemove = tt_Move;
+ }
+ }
+}
+var tt_area = false;
+function tt_Move(t_ev)
+{
+ if(!tt_obj) return;
+ if(tt_n6 || tt_w3c)
+ {
+ if(tt_wait) return;
+ tt_wait = true;
+ setTimeout('tt_wait = false;', 5);
+ }
+ var t_e = t_ev || window.event;
+ tt_SetDivPos(tt_EvX(t_e), tt_EvY(t_e));
+ if(tt_op6)
+ {
+ if(tt_area && t_e.target.tagName != 'AREA') tt_Hide();
+ else if(t_e.target.tagName == 'AREA') tt_area = true;
+ }
+}
+function tt_Hide()
+{
+ if(window.tt_obj)
+ {
+ if(window.tt_rdl) window.clearTimeout(tt_rdl);
+ if(!tt_sticky || !tt_act)
+ {
+ if(window.tt_rtm) window.clearTimeout(tt_rtm);
+ tt_ShowDiv(false);
+ tt_SetDivPos(-tt_objW, -tt_objH);
+ tt_obj = null;
+ if(typeof window.tt_upFunc != tt_u) document.onmouseup = window.tt_upFunc;
+ }
+ tt_sticky = false;
+ if(tt_op6 && tt_area) tt_area = false;
+ tt_ReleasMov();
+ if(tt_op7) tt_OpReHref();
+ }
+}
+function tt_Init()
+{
+ if(!(tt_op || tt_n4 || tt_n6 || tt_ie || tt_w3c)) return;
+
+ var htm = tt_n4? '<div style="position:absolute;"></div>' : '',
+ tags,
+ t_tj,
+ over,
+ esc = 'return escape(';
+ var i = tt_tags.length; while(i--)
+ {
+ tags = tt_ie? (document.all.tags(tt_tags[i]) || 1)
+ : document.getElementsByTagName? (document.getElementsByTagName(tt_tags[i]) || 1)
+ : (!tt_n4 && tt_tags[i]=="a")? document.links
+ : 1;
+ if(tt_n4 && (tt_tags[i] == "a" || tt_tags[i] == "layer")) tags = tt_N4Tags(tt_tags[i]);
+ var j = tags.length; while(j--)
+ {
+ if(typeof (t_tj = tags[j]).onmouseover == "function" && t_tj.onmouseover.toString().indexOf(esc) != -1 && !tt_n6 || tt_n6 && (over = t_tj.getAttribute("onmouseover")) && over.indexOf(esc) != -1)
+ {
+ if(over) t_tj.onmouseover = new Function(over);
+ var txt = unescape(t_tj.onmouseover());
+ htm += tt_Htm(
+ t_tj,
+ "tOoLtIp"+i+""+j,
+ txt.wzReplace("& ","&")
+ );
+
+ t_tj.onmouseover = new Function('e',
+ 'tt_Show(e,'+
+ '"tOoLtIp' +i+''+j+ '",'+
+ ((typeof t_tj.T_ABOVE != tt_u)? t_tj.T_ABOVE : ttAbove)+','+
+ ((typeof t_tj.T_DELAY != tt_u)? t_tj.T_DELAY : ttDelay)+','+
+ ((typeof t_tj.T_FIX != tt_u)? '"'+t_tj.T_FIX+'"' : '""')+','+
+ ((typeof t_tj.T_LEFT != tt_u)? t_tj.T_LEFT : ttLeft)+','+
+ ((typeof t_tj.T_OFFSETX != tt_u)? t_tj.T_OFFSETX : ttOffsetX)+','+
+ ((typeof t_tj.T_OFFSETY != tt_u)? t_tj.T_OFFSETY : ttOffsetY)+','+
+ ((typeof t_tj.T_STATIC != tt_u)? t_tj.T_STATIC : ttStatic)+','+
+ ((typeof t_tj.T_STICKY != tt_u)? t_tj.T_STICKY : ttSticky)+','+
+ ((typeof t_tj.T_TEMP != tt_u)? t_tj.T_TEMP : ttTemp)+
+ ');'
+ );
+ t_tj.onmouseout = tt_Hide;
+ if(t_tj.alt) t_tj.alt = "";
+ if(t_tj.title) t_tj.title = "";
+ }
+ }
+ }
+ document.write(htm);
+ if(document.getElementById) tt_ifrm = document.getElementById("TTiEiFrM");
+}
+tt_Init();
Added: xwiki/trunk/src/main/web/skins/default/info.gif
===================================================================
(Binary files differ)
Property changes on: xwiki/trunk/src/main/web/skins/default/info.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: xwiki/trunk/src/main/web/skins/xwiki10/info.gif
===================================================================
(Binary files differ)
Property changes on: xwiki/trunk/src/main/web/skins/xwiki10/info.gif
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: xwiki/trunk/src/main/web/yui/autocomplete/README
===================================================================
--- xwiki/trunk/src/main/web/yui/autocomplete/README 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/src/main/web/yui/autocomplete/README 2006-10-30 04:11:22 UTC (rev 1477)
@@ -0,0 +1,40 @@
+AutoComplete Release Notes
+
+
+
+*** version 0.11.3 ***
+
+* The iFrameSrc property has been deprecated. Implementers no longer need to
+specify an https URL to avoid IE security warnings when working with sites over
+SSL.
+
+
+
+*** version 0.11.0 ***
+
+* The method getListIds() has been deprecated for getListItems(), which returns
+an array of DOM references.
+
+* All classnames have been prefixed with "yui-ac-".
+
+* Container elements should no longer have CSS property "display" set to "none".
+
+* The useIFrame property can now be set after instantiation.
+
+* On some browsers, the unmatchedItemSelectEvent may not be fired properly when
+delimiter characters are defined.
+
+* On some browsers, defining delimiter characters while enabling forceSelection
+may result in unexpected behavior.
+
+
+
+*** version 0.10.0 ***
+
+* Initial release
+
+* In order to enable the useIFrame property, it should be set in the
+constructor.
+
+* On some browsers, defining delimiter characters while enabling forceSelection
+may result in unexpected behavior.
Added: xwiki/trunk/src/main/web/yui/autocomplete/autocomplete-debug.js
===================================================================
--- xwiki/trunk/src/main/web/yui/autocomplete/autocomplete-debug.js 2006-10-26 20:56:29 UTC (rev 1476)
+++ xwiki/trunk/src/main/web/yui/autocomplete/autocomplete-debug.js 2006-10-30 04:11:22 UTC (rev 1477)
@@ -0,0 +1,2788 @@
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.txt
+version: 0.11.3
+*/
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+/**
+ * Class providing the customizable functionality of a plug-and-play DHTML
+ * auto complete widget. Some key features:
+ * <ul>
+ * <li>Navigate with up/down arrow keys and/or mouse to pick a selection</li>
+ * <li>The drop down container can "roll down" or "fly out" via configurable
+ * animation</li>
+ * <li>UI look-and-feel customizable through CSS, including container
+ * attributes, borders, position, fonts, etc</li>
+ * </ul>
+ *
+ * requires YAHOO.util.Dom Dom utility
+ * requires YAHOO.util.Event Event utility
+ * requires YAHOO.widget.DataSource Data source class
+ * see YAHOO.util.Animation Animation utility
+ * see JSON JSON library
+ *
+ * @constructor
+ * @param {element | string} inputEl DOM element reference or string ID of the auto complete input field
+ * @param {element | string} containerEl DOM element reference or string ID of the auto complete <div>
+ * container
+ * @param {object} oDataSource Instance of YAHOO.widget.DataSource for query/results
+ * @param {object} oConfigs Optional object literal of config params
+ */
+YAHOO.widget.AutoComplete = function(inputEl,containerEl,oDataSource,oConfigs) {
+ if(inputEl && containerEl && oDataSource) {
+ // Validate data source
+ if (oDataSource && (oDataSource instanceof YAHOO.widget.DataSource)) {
+ this.dataSource = oDataSource;
+ }
+ else {
+ YAHOO.log("Could not instantiate AutoComplete due to an invalid DataSource", "error", this.toString());
+ return;
+ }
+
+ // Validate input element
+ if(YAHOO.util.Dom.inDocument(inputEl)) {
+ if(typeof inputEl == "string") {
+ this._sName = "instance" + YAHOO.widget.AutoComplete._nIndex + " " + inputEl;
+ this._oTextbox = document.getElementById(inputEl);
+ }
+ else {
+ this._sName = (inputEl.id) ?
+ "instance" + YAHOO.widget.AutoComplete._nIndex + " " + inputEl.id:
+ "instance" + YAHOO.widget.AutoComplete._nIndex;
+ this._oTextbox = inputEl;
+ }
+ }
+ else {
+ YAHOO.log("Could not instantiate AutoComplete due to an invalid input element", "error", this.toString());
+ return;
+ }
+
+ // Validate container element
+ if(YAHOO.util.Dom.inDocument(containerEl)) {
+ if(typeof containerEl == "string") {
+ this._oContainer = document.getElementById(containerEl);
+ }
+ else {
+ this._oContainer = containerEl;
+ }
+ if(this._oContainer.style.display == "none") {
+ YAHOO.log("The container may not display properly if display is set to \"none\" in CSS", "warn", this.toString());
+ }
+ }
+ else {
+ YAHOO.log("Could not instantiate AutoComplete due to an invalid container element", "error", this.toString());
+ return;
+ }
+
+ // Set any config params passed in to override defaults
+ if (typeof oConfigs == "object") {
+ for(var sConfig in oConfigs) {
+ if (sConfig) {
+ this[sConfig] = oConfigs[sConfig];
+ }
+ }
+ }
+
+ // Initialization sequence
+ this._initContainer();
+ this._initProps();
+ this._initList();
+ this._initContainerHelpers();
+
+ // Set up events
+ var oSelf = this;
+ var oTextbox = this._oTextbox;
+ // Events are actually for the content module within the container
+ var oContent = this._oContainer._oContent;
+
+ // Dom events
+ YAHOO.util.Event.addListener(oTextbox,"keyup",oSelf._onTextboxKeyUp,oSelf);
+ YAHOO.util.Event.addListener(oTextbox,"keydown",oSelf._onTextboxKeyDown,oSelf);
+ YAHOO.util.Event.addListener(oTextbox,"keypress",oSelf._onTextboxKeyPress,oSelf);
+ YAHOO.util.Event.addListener(oTextbox,"focus",oSelf._onTextboxFocus,oSelf);
+ YAHOO.util.Event.addListener(oTextbox,"blur",oSelf._onTextboxBlur,oSelf);
+ YAHOO.util.Event.addListener(oContent,"mouseover",oSelf._onContainerMouseover,oSelf);
+ YAHOO.util.Event.addListener(oContent,"mouseout",oSelf._onContainerMouseout,oSelf);
+ YAHOO.util.Event.addListener(oContent,"scroll",oSelf._onContainerScroll,oSelf);
+ YAHOO.util.Event.addListener(oContent,"resize",oSelf._onContainerResize,oSelf);
+ if(oTextbox.form) {
+ YAHOO.util.Event.addListener(oTextbox.form,"submit",oSelf._onFormSubmit,oSelf);
+ }
+
+ // Custom events
+ this.textboxFocusEvent = new YAHOO.util.CustomEvent("textboxFocus", this);
+ this.textboxKeyEvent = new YAHOO.util.CustomEvent("textboxKey", this);
+ this.dataRequestEvent = new YAHOO.util.CustomEvent("dataRequest", this);
+ this.dataReturnEvent = new YAHOO.util.CustomEvent("dataReturn", this);
+ this.dataErrorEvent = new YAHOO.util.CustomEvent("dataError", this);
+ this.containerExpandEvent = new YAHOO.util.CustomEvent("containerExpand", this);
+ this.typeAheadEvent = new YAHOO.util.CustomEvent("typeAhead", this);
+ this.itemMouseOverEvent = new YAHOO.util.CustomEvent("itemMouseOver", this);
+ this.itemMouseOutEvent = new YAHOO.util.CustomEvent("itemMouseOut", this);
+ this.itemArrowToEvent = new YAHOO.util.CustomEvent("itemArrowTo", this);
+ this.itemArrowFromEvent = new YAHOO.util.CustomEvent("itemArrowFrom", this);
+ this.itemSelectEvent = new YAHOO.util.CustomEvent("itemSelect", this);
+ this.unmatchedItemSelectEvent = new YAHOO.util.CustomEvent("unmatchedItemSelect", this);
+ this.selectionEnforceEvent = new YAHOO.util.CustomEvent("selectionEnforce", this);
+ this.containerCollapseEvent = new YAHOO.util.CustomEvent("containerCollapse", this);
+ this.textboxBlurEvent = new YAHOO.util.CustomEvent("textboxBlur", this);
+
+ // Finish up
+ oTextbox.setAttribute("autocomplete","off");
+ YAHOO.widget.AutoComplete._nIndex++;
+ YAHOO.log("AutoComplete initialized","info",this.toString());
+ }
+ // Required arguments were not found
+ else {
+ YAHOO.log("Could not instantiate AutoComplete due invalid arguments", "error", this.toString());
+ }
+};
+
+/***************************************************************************
+ * Public member variables
+ ***************************************************************************/
+/**
+ * The data source object that encapsulates the data used for auto completion.
+ * This object should be an inherited object from YAHOO.widget.DataSource.
+ *
+ * @type object
+ */
+YAHOO.widget.AutoComplete.prototype.dataSource = null;
+
+/**
+ * Number of characters that must be entered before querying for results.
+ * Default: 1.
+ *
+ * @type number
+ */
+YAHOO.widget.AutoComplete.prototype.minQueryLength = 1;
+
+/**
+ * Maximum number of results to display in auto complete container. Default: 10.
+ *
+ * @type number
+ */
+YAHOO.widget.AutoComplete.prototype.maxResultsDisplayed = 10;
+
+/**
+ * Number of seconds to delay before submitting a query request. If a query
+ * request is received before a previous one has completed its delay, the
+ * previous request is cancelled and the new request is set to the delay.
+ * Default: 0.5.
+ *
+ * @type number
+ */
+YAHOO.widget.AutoComplete.prototype.queryDelay = 0.5;
+
+/**
+ * Class name of a highlighted item within the auto complete container.
+ * Default: "yui-ac-highlight".
+ *
+ * @type string
+ */
+YAHOO.widget.AutoComplete.prototype.highlightClassName = "yui-ac-highlight";
+
+/**
+ * Class name of a pre-highlighted item within the auto complete container.
+ * Default: null.
+ *
+ * @type string
+ */
+YAHOO.widget.AutoComplete.prototype.prehighlightClassName = null;
+
+/**
+ * Query delimiter. A single character separator for multiple delimited
+ * selections. Multiple delimiter characteres may be defined as an array of
+ * strings. A null value or empty string indicates that query results cannot
+ * be delimited. This feature is not recommended if you need forceSelection to
+ * be true. Default: null.
+ *
+ * @type string or array
+ */
+YAHOO.widget.AutoComplete.prototype.delimChar = null;
+
+/**
+ * Whether or not the first item in the auto complete container should be
+ * automatically highlighted on expand. Default: true.
+ *
+ * @type boolean
+ */
+YAHOO.widget.AutoComplete.prototype.autoHighlight = true;
+
+/**
+ * Whether or not the auto complete input field should be automatically updated
+ * with the first query result as the user types, auto-selecting the substring
+ * that the user has not typed. Default: false.
+ *
+ * @type boolean
+ */
+YAHOO.widget.AutoComplete.prototype.typeAhead = false;
+
+/**
+ * Whether or not to animate the expansion/collapse of the auto complete
+ * container in the horizontal direction. Default: false.
+ *
+ * @type boolean
+ */
+YAHOO.widget.AutoComplete.prototype.animHoriz = false;
+
+/**
+ * Whether or not to animate the expansion/collapse of the auto complete
+ * container in the vertical direction. Default: true.
+ *
+ * @type boolean
+ */
+YAHOO.widget.AutoComplete.prototype.animVert = true;
+
+/**
+ * Speed of container expand/collapse animation, in seconds. Default: 0.3.
+ *
+ * @type number
+ */
+YAHOO.widget.AutoComplete.prototype.animSpeed = 0.3;
+
+/**
+ * Whether or not to force the user's selection to match one of the query
+ * results. Enabling this feature essentially transforms the auto complete form
+ * input field into a <select> field. This feature is not recommended
+ * with delimiter character(s) defined. Default: false.
+ *
+ * @type boolean
+ */
+YAHOO.widget.AutoComplete.prototype.forceSelection = false;
+
+/**
+ * Whether or not to allow browsers to cache user-typed input in the input
+ * field. Disabling this feature will prevent the widget from setting the
+ * autocomplete="off" on the auto complete input field. When autocomplete="off"
+ * and users click the back button after form submission, user-typed input can
+ * be prefilled by the browser from its cache. This caching of user input may
+ * not be desired for sensitive data, such as credit card numbers, in which
+ * case, implementers should consider setting allowBrowserAutocomplete to false.
+ * Default: true.
+ *
+ * @type boolean
+ */
+YAHOO.widget.AutoComplete.prototype.allowBrowserAutocomplete = true;
+
+/**
+ * Whether or not the auto complete container should always be displayed.
+ * Enabling this feature prevents the toggling of the container to a collapsed
+ * state. Default: false.
+ *
+ * @type boolean
+ */
+YAHOO.widget.AutoComplete.prototype.alwaysShowContainer = false;
+
+/**
+ * Whether or not to use an iFrame to layer over Windows form elements in
+ * IE. Set to true only when the auto complete container will be on top of a
+ * <select> field in IE and thus exposed to the IE z-index bug (i.e.,
+ * 5.5 < IE < 7). Default:false.
+ *
+ * @type boolean
+ */
+YAHOO.widget.AutoComplete.prototype.useIFrame = false;
+
+/**
+ * Whether or not the auto complete container should have a shadow. Default:false.
+ *
+ * @type boolean
+ */
+YAHOO.widget.AutoComplete.prototype.useShadow = false;
+
+/***************************************************************************
+ * Public methods
+ ***************************************************************************/
+ /**
+ * Public accessor to the unique name of the auto complete instance.
+ *
+ * @return {string} Unique name of the auto complete instance
+ */
+YAHOO.widget.AutoComplete.prototype.toString = function() {
+ return "AutoComplete " + this._sName;
+};
+
+/**
+ * Public accessor to the internal array of DOM <li> elements that
+ * display query results within the auto complete container.
+ *
+ * @return {array} Array of <li> elements within the auto complete
+ * container
+ */
+YAHOO.widget.AutoComplete.prototype.getListItems = function() {
+ return this._aListItems;
+};
+
+/**
+ * Public accessor to the data held in an <li> element of the
+ * auto complete container.
+ *
+ * @return {object or array} Object or array of result data or null
+ */
+YAHOO.widget.AutoComplete.prototype.getListItemData = function(oListItem) {
+ if(oListItem._oResultData) {
+ return oListItem._oResultData;
+ }
+ else {
+ return false;
+ }
+};
+
+/**
+ * Sets HTML markup for the auto complete container header. This markup will be
+ * inserted within a <div> tag with a class of "ac_hd".
+ *
+ * @param {string} sHeader HTML markup for container header
+ */
+YAHOO.widget.AutoComplete.prototype.setHeader = function(sHeader) {
+ if(sHeader) {
+ if(this._oContainer._oContent._oHeader) {
+ this._oContainer._oContent._oHeader.innerHTML = sHeader;
+ this._oContainer._oContent._oHeader.style.display = "block";
+ }
+ }
+ else {
+ this._oContainer._oContent._oHeader.innerHTML = "";
+ this._oContainer._oContent._oHeader.style.display = "none";
+ }
+};
+
+/**
+ * Sets HTML markup for the auto complete container footer. This markup will be
+ * inserted within a <div> tag with a class of "ac_ft".
+ *
+ * @param {string} sFooter HTML markup for container footer
+ */
+YAHOO.widget.AutoComplete.prototype.setFooter = function(sFooter) {
+ if(sFooter) {
+ if(this._oContainer._oContent._oFooter) {
+ this._oContainer._oContent._oFooter.innerHTML = sFooter;
+ this._oContainer._oContent._oFooter.style.display = "block";
+ }
+ }
+ else {
+ this._oContainer._oContent._oFooter.innerHTML = "";
+ this._oContainer._oContent._oFooter.style.display = "none";
+ }
+};
+
+/**
+ * Sets HTML markup for the auto complete container body. This markup will be
+ * inserted within a <div> tag with a class of "ac_bd".
+ *
+ * @param {string} sHeader HTML markup for container body
+ */
+YAHOO.widget.AutoComplete.prototype.setBody = function(sBody) {
+ if(sBody) {
+ if(this._oContainer._oContent._oBody) {
+ this._oContainer._oContent._oBody.innerHTML = sBody;
+ this._oContainer._oContent._oBody.style.display = "block";
+ this._oContainer._oContent.style.display = "block";
+ }
+ }
+ else {
+ this._oContainer._oContent._oBody.innerHTML = "";
+ this._oContainer._oContent.style.display = "none";
+ }
+ this._maxResultsDisplayed = 0;
+};
+
+/**
+ * Overridable method that converts a result item object into HTML markup
+ * for display. Return data values are accessible via the oResultItem object,
+ * and the key return value will always be oResultItem[0]. Markup will be
+ * displayed within <li> element tags in the container.
+ *
+ * @param {object} oResultItem Result item object representing one query result
+ * @param {string} sQuery The current query string
+ * @return {string} HTML markup of formatted result data
+ */
+YAHOO.widget.AutoComplete.prototype.formatResult = function(oResultItem, sQuery) {
+ var sResult = oResultItem[0];
+ if(sResult) {
+ return sResult;
+ }
+ else {
+ return "";
+ }
+};
+
+/**
+ * Makes query request to the data source.
+ *
+ * @param {string} sQuery Query string.
+ */
+YAHOO.widget.AutoComplete.prototype.sendQuery = function(sQuery) {
+ if(sQuery) {
+ this._sendQuery(sQuery);
+ }
+ else {
+ YAHOO.log("Query could not be sent because the string value was empty or null.","warn",this.toString());
+ return;
+ }
+};
+
+/***************************************************************************
+ * Events
+ ***************************************************************************/
+/**
+ * Fired when the auto complete text input box receives focus. Subscribers
+ * receive the following array:<br>
+ * - args[0] The auto complete object instance
+ */
+YAHOO.widget.AutoComplete.prototype.textboxFocusEvent = null;
+
+/**
+ * Fired when the auto complete text input box receives key input. Subscribers
+ * receive the following array:<br>
+ * - args[0] The auto complete object instance
+ * - args[1] The keycode number
+ */
+YAHOO.widget.AutoComplete.prototype.textboxKeyEvent = null;
+
+/**
+ * Fired when the auto complete instance makes a query to the data source.
+ * Subscribers receive the following array:<br>
+ * - args[0] The auto complete object instance
+ * - args[1] The query string
+ */
+YAHOO.widget.AutoComplete.prototype.dataRequestEvent = null;
+
+/**
+ * Fired when the auto complete instance receives query results from the data
+ * source. Subscribers receive the following array:<br>
+ * - args[0] The auto complete object instance
+ * - args[1] The query string
+ * - args[2] Results array
+ */
+YAHOO.widget.AutoComplete.prototype.dataReturnEvent = null;
+
+/**
+ * Fired when the auto complete instance does not receive query results from the
+ * data source due to an error. Subscribers receive the following array:<br>
+ * - args[0] The auto complete object instance
+ * - args[1] The query string
+ */
+YAHOO.widget.AutoComplete.prototype.dataErrorEvent = null;
+
+/**
+ * Fired when the auto complete container is expanded. If alwaysShowContainer is
+ * enabled, then containerExpandEvent will be fired when the container is
+ * populated with results. Subscribers receive the following array:<br>
+ * - args[0] The auto complete object instance
+ */
+YAHOO.widget.AutoComplete.prototype.containerExpandEvent = null;
+
+/**
+ * Fired when the auto complete textbox has been prefilled by the type-ahead
+ * feature. Subscribers receive the following array:<br>
+ * - args[0] The auto complete object instance
+ * - args[1] The query string
+ * - args[2] The prefill string
+ */
+YAHOO.widget.AutoComplete.prototype.typeAheadEvent = null;
+
+/**
+ * Fired when result item has been moused over. Subscribers receive the following
+ * array:<br>
+ * - args[0] The auto complete object instance
+ * - args[1] The <li> element item moused to
+ */
+YAHOO.widget.AutoComplete.prototype.itemMouseOverEvent = null;
+
+/**
+ * Fired when result item has been moused out. Subscribers receive the
+ * following array:<br>
+ * - args[0] The auto complete object instance
+ * - args[1] The <li> element item moused from
+ */
+YAHOO.widget.AutoComplete.prototype.itemMouseOutEvent = null;
+
+/**
+ * Fired when result item has been arrowed to. Subscribers receive the following
+ * array:<br>
+ * - args[0] The auto complete object instance
+ * - args[1] The <li> element item arrowed to
+ */
+YAHOO.widget.AutoComplete.prototype.itemArrowToEvent = null;
+
+/**
+ * Fired when result item has been arrowed away from. Subscribers receive the
+ * following array:<br>
+ * - args[0] The auto complete object instance
+ * - args[1] The <li> element item arrowed from
+ */
+YAHOO.widget.AutoComplete.prototype.itemArrowFromEvent = null;
+
+/**
+ * Fired when an item is selected via mouse click, ENTER key, or TAB key.
+ * Subscribers receive the following array:<br>
+ * - args[0] The auto complete object instance
+ * - args[1] The selected <li> element item
+ * - args[2] The data returned for the item, either as an object, or mapped from the schema into an array
+ */
+YAHOO.widget.AutoComplete.prototype.itemSelectEvent = null;
+
+/**
+ * Fired when an user selection does not match any of the displayed result items.
+ * Note that this event may not behave as expected when delimiter characters
+ * have been defined. Subscribers receive the following array:<br>
+ * - args[0] The auto complete object instance
+ * - args[1] The user selection
+ */
+YAHOO.widget.AutoComplete.prototype.unmatchedItemSelectEvent = null;
+
+/**
+ * Fired if forceSelection is enabled and the user's input has been cleared
+ * because it did not match one of the returned query results. Subscribers
+ * receive the following array:<br>
+ * - args[0] The auto complete object instance
+ */
+YAHOO.widget.AutoComplete.prototype.selectionEnforceEvent = null;
+
+/**
+ * Fired when the auto complete container is collapsed. If alwaysShowContainer is
+ * enabled, then containerCollapseEvent will be fired when the container is
+ * cleared of results. Subscribers receive the following array:<br>
+ * - args[0] The auto complete object instance
+ */
+YAHOO.widget.AutoComplete.prototype.containerCollapseEvent = null;
+
+/**
+ * Fired when the auto complete text input box loses focus. Subscribers receive
+ * an array of the following array:<br>
+ * - args[0] The auto complete object instance
+ */
+YAHOO.widget.AutoComplete.prototype.textboxBlurEvent = null;
+
+/***************************************************************************
+ * Private member variables
+ ***************************************************************************/
+/**
+ * Internal class variable to index multiple auto complete instances.
+ *
+ * @type number
+ * @private
+ */
+YAHOO.widget.AutoComplete._nIndex = 0;
+
+/**
+ * Name of auto complete instance.
+ *
+ * @type string
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._sName = null;
+
+/**
+ * Text input box DOM element.
+ *
+ * @type object
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._oTextbox = null;
+
+/**
+ * Whether or not the textbox is currently in focus. If query results come back
+ * but the user has already moved on, do not proceed with auto complete behavior.
+ *
+ * @type boolean
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._bFocused = true;
+
+/**
+ * Animation instance for container expand/collapse.
+ *
+ * @type boolean
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._oAnim = null;
+
+/**
+ * Container DOM element.
+ *
+ * @type object
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._oContainer = null;
+
+/**
+ * Whether or not the auto complete container is currently open.
+ *
+ * @type boolean
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._bContainerOpen = false;
+
+/**
+ * Whether or not the mouse is currently over the auto complete
+ * container. This is necessary in order to prevent clicks on container items
+ * from being text input box blur events.
+ *
+ * @type boolean
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._bOverContainer = false;
+
+/**
+ * Array of <li> elements references that contain query results within the
+ * auto complete container.
+ *
+ * @type array
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._aListItems = null;
+
+/**
+ * Number of <li> elements currently displayed in auto complete container.
+ *
+ * @type number
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._nDisplayedItems = 0;
+
+/**
+ * Internal count of <li> elements displayed and hidden in auto complete container.
+ *
+ * @type number
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._maxResultsDisplayed = 0;
+
+/**
+ * Current query string
+ *
+ * @type string
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._sCurQuery = null;
+
+/**
+ * Past queries this session (for saving delimited queries).
+ *
+ * @type string
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._sSavedQuery = null;
+
+/**
+ * Pointer to the currently highlighted <li> element in the container.
+ *
+ * @type object
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._oCurItem = null;
+
+/**
+ * Whether or not an item has been selected since the container was populated
+ * with results. Reset to false by _populateList, and set to true when item is
+ * selected.
+ *
+ * @type boolean
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._bItemSelected = false;
+
+/**
+ * Key code of the last key pressed in textbox.
+ *
+ * @type number
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._nKeyCode = null;
+
+/**
+ * Delay timeout ID.
+ *
+ * @type number
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._nDelayID = -1;
+
+/**
+ * Src to iFrame used when useIFrame = true. Supports implementations over SSL
+ * as well.
+ *
+ * @type string
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._iFrameSrc = "javascript:false;";
+
+/***************************************************************************
+ * Private methods
+ ***************************************************************************/
+/**
+ * Updates and validates latest public config properties.
+ *
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._initProps = function() {
+ // Correct any invalid values
+ var minQueryLength = this.minQueryLength;
+ if(isNaN(minQueryLength) || (minQueryLength < 1)) {
+ minQueryLength = 1;
+ }
+ var maxResultsDisplayed = this.maxResultsDisplayed;
+ if(isNaN(this.maxResultsDisplayed) || (this.maxResultsDisplayed < 1)) {
+ this.maxResultsDisplayed = 10;
+ }
+ var queryDelay = this.queryDelay;
+ if(isNaN(this.queryDelay) || (this.queryDelay < 0)) {
+ this.queryDelay = 0.5;
+ }
+ var aDelimChar = (this.delimChar) ? this.delimChar : null;
+ if(aDelimChar) {
+ if(typeof aDelimChar == "string") {
+ this.delimChar = [aDelimChar];
+ }
+ else if(aDelimChar.constructor != Array) {
+ this.delimChar = null;
+ }
+ }
+ var animSpeed = this.animSpeed;
+ if((this.animHoriz || this.animVert) && YAHOO.util.Anim) {
+ if(isNaN(animSpeed) || (animSpeed < 0)) {
+ animSpeed = 0.3;
+ }
+ if(!this._oAnim ) {
+ oAnim = new YAHOO.util.Anim(this._oContainer._oContent, {}, this.animSpeed);
+ this._oAnim = oAnim;
+ }
+ else {
+ this._oAnim.duration = animSpeed;
+ }
+ }
+ if(this.forceSelection && this.delimChar) {
+ YAHOO.log("The forceSelection feature has been enabled with delimChar defined.","warn", this.toString());
+ }
+ if(this.alwaysShowContainer && (this.useShadow || this.useIFrame)) {
+ YAHOO.log("The features useShadow and useIFrame are not compatible with the alwaysShowContainer feature.","warn", this.toString());
+ }
+
+ if(this.alwaysShowContainer) {
+ this._bContainerOpen = true;
+ }
+};
+
+/**
+ * Initializes the auto complete container helpers if they are enabled and do
+ * not exist
+ *
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._initContainerHelpers = function() {
+ if(this.useShadow && !this._oContainer._oShadow) {
+ var oShadow = document.createElement("div");
+ oShadow.className = "yui-ac-shadow";
+ this._oContainer._oShadow = this._oContainer.appendChild(oShadow);
+ }
+ if(this.useIFrame && !this._oContainer._oIFrame) {
+ var oIFrame = document.createElement("iframe");
+ oIFrame.src = this._iFrameSrc;
+ oIFrame.frameBorder = 0;
+ oIFrame.scrolling = "no";
+ oIFrame.style.position = "absolute";
+ oIFrame.style.width = "100%";
+ oIFrame.style.height = "100%";
+ this._oContainer._oIFrame = this._oContainer.appendChild(oIFrame);
+ }
+};
+
+/**
+ * Initializes the auto complete container once at object creation
+ *
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._initContainer = function() {
+ if(!this._oContainer._oContent) {
+ // The oContent div helps size the iframe and shadow properly
+ var oContent = document.createElement("div");
+ oContent.className = "yui-ac-content";
+ oContent.style.display = "none";
+ this._oContainer._oContent = this._oContainer.appendChild(oContent);
+
+ var oHeader = document.createElement("div");
+ oHeader.className = "yui-ac-hd";
+ oHeader.style.display = "none";
+ this._oContainer._oContent._oHeader = this._oContainer._oContent.appendChild(oHeader);
+
+ var oBody = document.createElement("div");
+ oBody.className = "yui-ac-bd";
+ this._oContainer._oContent._oBody = this._oContainer._oContent.appendChild(oBody);
+
+ var oFooter = document.createElement("div");
+ oFooter.className = "yui-ac-ft";
+ oFooter.style.display = "none";
+ this._oContainer._oContent._oFooter = this._oContainer._oContent.appendChild(oFooter);
+ }
+ else {
+ YAHOO.log("Could not initialize the container","warn",this.toString());
+ }
+};
+
+/**
+ * Clears out contents of container body and creates up to
+ * YAHOO.widget.AutoComplete#maxResultsDisplayed <li> elements in an
+ * <ul> element.
+ *
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._initList = function() {
+ this._aListItems = [];
+ while(this._oContainer._oContent._oBody.hasChildNodes()) {
+ var oldListItems = this.getListItems();
+ if(oldListItems) {
+ for(var oldi = oldListItems.length-1; oldi >= 0; i--) {
+ oldListItems[oldi] = null;
+ }
+ }
+ this._oContainer._oContent._oBody.innerHTML = "";
+ }
+
+ var oList = document.createElement("ul");
+ oList = this._oContainer._oContent._oBody.appendChild(oList);
+ for(var i=0; i<this.maxResultsDisplayed; i++) {
+ var oItem = document.createElement("li");
+ oItem = oList.appendChild(oItem);
+ this._aListItems[i] = oItem;
+ this._initListItem(oItem, i);
+ }
+ this._maxResultsDisplayed = this.maxResultsDisplayed;
+};
+
+/**
+ * Initializes each <li> element in the container list.
+ *
+ * @param {object} oItem The <li> DOM element
+ * @param {number} nItemIndex The index of the element
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._initListItem = function(oItem, nItemIndex) {
+ var oSelf = this;
+ oItem.style.display = "none";
+ oItem._nItemIndex = nItemIndex;
+
+ oItem.mouseover = oItem.mouseout = oItem.onclick = null;
+ YAHOO.util.Event.addListener(oItem,"mouseover",oSelf._onItemMouseover,oSelf);
+ YAHOO.util.Event.addListener(oItem,"mouseout",oSelf._onItemMouseout,oSelf);
+ YAHOO.util.Event.addListener(oItem,"click",oSelf._onItemMouseclick,oSelf);
+};
+
+/**
+ * Handles <li> element mouseover events in the container.
+ *
+ * @param {event} v The mouseover event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onItemMouseover = function(v,oSelf) {
+ if(oSelf.prehighlightClassName) {
+ oSelf._togglePrehighlight(this,"mouseover");
+ }
+ else {
+ oSelf._toggleHighlight(this,"to");
+ }
+
+ oSelf.itemMouseOverEvent.fire(oSelf, this);
+};
+
+/**
+ * Handles <li> element mouseout events in the container.
+ *
+ * @param {event} v The mouseout event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onItemMouseout = function(v,oSelf) {
+ if(oSelf.prehighlightClassName) {
+ oSelf._togglePrehighlight(this,"mouseout");
+ }
+ else {
+ oSelf._toggleHighlight(this,"from");
+ }
+
+ oSelf.itemMouseOutEvent.fire(oSelf, this);
+};
+
+/**
+ * Handles <li> element click events in the container.
+ *
+ * @param {event} v The click event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onItemMouseclick = function(v,oSelf) {
+ // In case item has not been moused over
+ oSelf._toggleHighlight(this,"to");
+ oSelf._selectItem(this);
+};
+
+/**
+ * Handles container mouseover events.
+ *
+ * @param {event} v The mouseover event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onContainerMouseover = function(v,oSelf) {
+ oSelf._bOverContainer = true;
+};
+
+/**
+ * Handles container mouseout events.
+ *
+ * @param {event} v The mouseout event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onContainerMouseout = function(v,oSelf) {
+ oSelf._bOverContainer = false;
+ // If container is still active
+ if(oSelf._oCurItem) {
+ oSelf._toggleHighlight(oSelf._oCurItem,"to");
+ }
+};
+
+/**
+ * Handles container scroll events.
+ *
+ * @param {event} v The scroll event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onContainerScroll = function(v,oSelf) {
+ oSelf._oTextbox.focus();
+};
+
+/**
+ * Handles container resize events.
+ *
+ * @param {event} v The resize event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onContainerResize = function(v,oSelf) {
+ oSelf._toggleContainerHelpers(oSelf._bContainerOpen);
+};
+
+
+/**
+ * Handles textbox keydown events of functional keys, mainly for UI behavior.
+ *
+ * @param {event} v The keydown event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onTextboxKeyDown = function(v,oSelf) {
+ var nKeyCode = v.keyCode;
+
+ switch (nKeyCode) {
+ case 9: // tab
+ if(oSelf.delimChar && (oSelf._nKeyCode != nKeyCode)) {
+ if(oSelf._bContainerOpen) {
+ YAHOO.util.Event.stopEvent(v);
+ }
+ }
+ // select an item or clear out
+ if(oSelf._oCurItem) {
+ oSelf._selectItem(oSelf._oCurItem);
+ }
+ else {
+ oSelf._clearList();
+ }
+ break;
+ case 13: // enter
+ if(oSelf._nKeyCode != nKeyCode) {
+ if(oSelf._bContainerOpen) {
+ YAHOO.util.Event.stopEvent(v);
+ }
+ }
+ if(oSelf._oCurItem) {
+ oSelf._selectItem(oSelf._oCurItem);
+ }
+ else {
+ oSelf._clearList();
+ }
+ break;
+ case 27: // esc
+ oSelf._clearList();
+ return;
+ case 39: // right
+ oSelf._jumpSelection();
+ break;
+ case 38: // up
+ YAHOO.util.Event.stopEvent(v);
+ oSelf._moveSelection(nKeyCode);
+ break;
+ case 40: // down
+ YAHOO.util.Event.stopEvent(v);
+ oSelf._moveSelection(nKeyCode);
+ break;
+ default:
+ break;
+ }
+};
+
+/**
+ * Handles textbox keypress events, for stopEvent in Safari and FF 1.5/Mac
+ *
+ * @param {event} v The keyup event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress = function(v,oSelf) {
+ var nKeyCode = v.keyCode;
+
+ switch (nKeyCode) {
+ case 9: // tab
+ case 13: // enter
+ if((oSelf._nKeyCode != nKeyCode)) {
+ YAHOO.util.Event.stopEvent(v);
+ }
+ break;
+ case 38: // up
+ case 40: // down
+ YAHOO.util.Event.stopEvent(v);
+ break;
+ default:
+ break;
+ }
+};
+
+/**
+ * Handles textbox keyup events that trigger queries.
+ *
+ * @param {event} v The keyup event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onTextboxKeyUp = function(v,oSelf) {
+ // Check to see if any of the public properties have been updated
+ oSelf._initProps();
+
+ var nKeyCode = v.keyCode;
+ oSelf._nKeyCode = nKeyCode;
+ var sChar = String.fromCharCode(nKeyCode);
+ var sText = this.value; //string in textbox
+
+ // Filter out chars that don't trigger queries
+ if (oSelf._isIgnoreKey(nKeyCode) || (sText.toLowerCase() == oSelf._sCurQuery)) {
+ return;
+ }
+ else {
+ oSelf.textboxKeyEvent.fire(oSelf, nKeyCode);
+ }
+
+ // Set timeout on the request
+ if (oSelf.queryDelay > 0) {
+ var nDelayID =
+ setTimeout(function(){oSelf._sendQuery(sText);},(oSelf.queryDelay * 1000));
+
+ if (oSelf._nDelayID != -1) {
+ clearTimeout(oSelf._nDelayID);
+ }
+
+ oSelf._nDelayID = nDelayID;
+ }
+ else {
+ // No delay so send request immediately
+ oSelf._sendQuery(sText);
+ }
+};
+
+/**
+ * Whether or not key is functional or should be ignored. Note that the right
+ * arrow key is NOT an ignored key since it triggers queries for certain intl
+ * charsets.
+ *
+ * @param {number} nKeycode Code of key pressed
+ * @return {boolean} Whether or not to be ignore key
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._isIgnoreKey = function(nKeyCode) {
+ if ((nKeyCode == 9) || (nKeyCode == 13) || // tab, enter
+ (nKeyCode == 16) || (nKeyCode == 17) || // shift, ctl
+ (nKeyCode >= 18 && nKeyCode <= 20) || // alt,pause/break,caps lock
+ (nKeyCode == 27) || // esc
+ (nKeyCode >= 33 && nKeyCode <= 35) || // page up,page down,end
+ (nKeyCode >= 36 && nKeyCode <= 38) || // home,left,up
+ (nKeyCode == 40) || // down
+ (nKeyCode >= 44 && nKeyCode <= 45)) { // print screen,insert
+ return true;
+ }
+ return false;
+};
+
+/**
+ * Handles text input box receiving focus.
+ *
+ * @param {event} v The focus event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onTextboxFocus = function (v,oSelf) {
+ oSelf._oTextbox.setAttribute("autocomplete","off");
+ oSelf._bFocused = true;
+ oSelf.textboxFocusEvent.fire(oSelf);
+};
+
+/**
+ * Handles text input box losing focus.
+ *
+ * @param {event} v The focus event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onTextboxBlur = function (v,oSelf) {
+ // Don't treat as a blur if it was a selection via mouse click
+ if(!oSelf._bOverContainer || (oSelf._nKeyCode == 9)) {
+ // Current query needs to be validated
+ if(!oSelf._bItemSelected) {
+ if(!oSelf._bContainerOpen || (oSelf._bContainerOpen && !oSelf._textMatchesOption())) {
+ if(oSelf.forceSelection) {
+ oSelf._clearSelection();
+ }
+ else {
+ oSelf.unmatchedItemSelectEvent.fire(oSelf, oSelf._sCurQuery);
+ }
+ }
+ }
+
+ if(oSelf._bContainerOpen) {
+ oSelf._clearList();
+ }
+ oSelf._bFocused = false;
+ oSelf.textboxBlurEvent.fire(oSelf);
+ }
+};
+
+/**
+ * Handles form submission event.
+ *
+ * @param {event} v The submit event
+ * @param {object} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._onFormSubmit = function(v,oSelf) {
+ if(oSelf.allowBrowserAutocomplete) {
+ oSelf._oTextbox.setAttribute("autocomplete","on");
+ }
+ else {
+ oSelf._oTextbox.setAttribute("autocomplete","off");
+ }
+};
+
+/**
+ * Makes query request to the data source.
+ *
+ * @param {string} sQuery Query string.
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._sendQuery = function(sQuery) {
+ // Delimiter has been enabled
+ var aDelimChar = (this.delimChar) ? this.delimChar : null;
+ if(aDelimChar) {
+ // Loop through all possible delimiters and find the latest one
+ // A " " may be a false positive if they are defined as delimiters AND
+ // are used to separate delimited queries
+ var nDelimIndex = -1;
+ for(var i = aDelimChar.length-1; i >= 0; i--) {
+ var nNewIndex = sQuery.lastIndexOf(aDelimChar[i]);
+ if(nNewIndex > nDelimIndex) {
+ nDelimIndex = nNewIndex;
+ }
+ }
+ // If we think the last delimiter is a space (" "), make sure it is NOT
+ // a false positive by also checking the char directly before it
+ if(aDelimChar[i] == " ") {
+ for (var j = aDelimChar.length-1; j >= 0; j--) {
+ if(sQuery[nDelimIndex - 1] == aDelimChar[j]) {
+ nDelimIndex--;
+ break;
+ }
+ }
+ }
+ // A delimiter has been found so extract the latest query
+ if (nDelimIndex > -1) {
+ var nQueryStart = nDelimIndex + 1;
+ // Trim any white space from the beginning...
+ while(sQuery.charAt(nQueryStart) == " ") {
+ nQueryStart += 1;
+ }
+ // ...and save the rest of the string for later
+ this._sSavedQuery = sQuery.substring(0,nQueryStart);
+ // Here is the query itself
+ sQuery = sQuery.substr(nQueryStart);
+ }
+ else if(sQuery.indexOf(this._sSavedQuery) < 0){
+ this._sSavedQuery = null;
+ }
+ }
+
+ // Don't search queries that are too short
+ if (sQuery.length < this.minQueryLength) {
+ if (this._nDelayID != -1) {
+ clearTimeout(this._nDelayID);
+ }
+ this._clearList();
+ return;
+ }
+
+ sQuery = encodeURIComponent(sQuery);
+ this._nDelayID = -1; // Reset timeout ID because request has been made
+ this.dataRequestEvent.fire(this, sQuery);
+ this.dataSource.getResults(this._populateList, sQuery, this);
+};
+
+/**
+ * Hides all visuals related to the array of <li> elements in the container.
+ *
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._clearList = function() {
+ this._oContainer._oContent.scrollTop = 0;
+ var aItems = this._aListItems;
+
+ if(aItems && (aItems.length > 0)) {
+ for(var i = aItems.length-1; i >= 0 ; i--) {
+ aItems[i].style.display = "none";
+ }
+ }
+
+ if (this._oCurItem) {
+ this._toggleHighlight(this._oCurItem,"from");
+ }
+
+ this._oCurItem = null;
+ this._nDisplayedItems = 0;
+ this._sCurQuery = null;
+ this._toggleContainer(false);
+};
+
+/**
+ * Populates the array of <li> elements in the container with query
+ * results. This method is passed to YAHOO.widget.DataSource#getResults as a
+ * callback function so results from the datasource are returned to the
+ * auto complete instance.
+ *
+ * @param {string} sQuery The query string
+ * @param {object} aResults An array of query result objects from the data source
+ * @param {string} oSelf The auto complete instance
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._populateList = function(sQuery, aResults, oSelf) {
+ if(aResults === null) {
+ oSelf.dataErrorEvent.fire(oSelf, sQuery);
+ }
+ if (!oSelf._bFocused || !aResults) {
+ return;
+ }
+
+ var isOpera = (navigator.userAgent.toLowerCase().indexOf("opera") != -1);
+ var contentStyle = oSelf._oContainer._oContent.style;
+ contentStyle.width = (!isOpera) ? null : "";
+ contentStyle.height = (!isOpera) ? null : "";
+
+ var sCurQuery = decodeURIComponent(sQuery);
+ oSelf._sCurQuery = sCurQuery;
+ oSelf._bItemSelected = false;
+
+ if(oSelf._maxResultsDisplayed != oSelf.maxResultsDisplayed) {
+ oSelf._initList();
+ }
+
+ var nItems = Math.min(aResults.length,oSelf.maxResultsDisplayed);
+ oSelf._nDisplayedItems = nItems;
+ if (nItems > 0) {
+ oSelf._initContainerHelpers();
+ var aItems = oSelf._aListItems;
+
+ // Fill items with data
+ for(var i = nItems-1; i >= 0; i--) {
+ var oItemi = aItems[i];
+ var oResultItemi = aResults[i];
+ oItemi.innerHTML = oSelf.formatResult(oResultItemi, sCurQuery);
+ oItemi.style.display = "list-item";
+ oItemi._sResultKey = oResultItemi[0];
+ oItemi._oResultData = oResultItemi;
+
+ }
+
+ // Empty out remaining items if any
+ for(var j = aItems.length-1; j >= nItems ; j--) {
+ var oItemj = aItems[j];
+ oItemj.innerHTML = null;
+ oItemj.style.display = "none";
+ oItemj._sResultKey = null;
+ oItemj._oResultData = null;
+ }
+
+ if(oSelf.autoHighlight) {
+ // Go to the first item
+ var oFirstItem = aItems[0];
+ oSelf._toggleHighlight(oFirstItem,"to");
+ oSelf.itemArrowToEvent.fire(oSelf, oFirstItem);
+ oSelf._typeAhead(oFirstItem,sQuery);
+ }
+ else {
+ oSelf._oCurItem = null;
+ }
+
+ // Expand the container
+ oSelf._toggleContainer(true);
+ }
+ else {
+ oSelf._clearList();
+ }
+ oSelf.dataReturnEvent.fire(oSelf, sQuery, aResults);
+};
+
+/**
+ * When YAHOO.widget.AutoComplete#bForceSelection is true and the user attempts
+ * leave the text input box without selecting an item from the query results,
+ * the user selection is cleared.
+ *
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._clearSelection = function() {
+ var sValue = this._oTextbox.value;
+ var sChar = (this.delimChar) ? this.delimChar[0] : null;
+ var nIndex = (sChar) ? sValue.lastIndexOf(sChar, sValue.length-2) : -1;
+ if(nIndex > -1) {
+ this._oTextbox.value = sValue.substring(0,nIndex);
+ }
+ else {
+ this._oTextbox.value = "";
+ }
+ this._sSavedQuery = this._oTextbox.value;
+
+ // Fire custom event
+ this.selectionEnforceEvent.fire(this);
+};
+
+/**
+ * Whether or not user-typed value in the text input box matches any of the
+ * query results.
+ *
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._textMatchesOption = function() {
+ var foundMatch = false;
+
+ for(var i = this._nDisplayedItems-1; i >= 0 ; i--) {
+ var oItem = this._aListItems[i];
+ var sMatch = oItem._sResultKey.toLowerCase();
+ if (sMatch == this._sCurQuery.toLowerCase()) {
+ foundMatch = true;
+ break;
+ }
+ }
+ return(foundMatch);
+};
+
+/**
+ * Updates in the text input box with the first query result as the user types,
+ * selecting the substring that the user has not typed.
+ *
+ * @param {object} oItem The <li> element item whose data populates the input field
+ * @param {string} sQuery Query string
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._typeAhead = function(oItem, sQuery) {
+ // Don't update if turned off
+ if (!this.typeAhead) {
+ return;
+ }
+
+ var oTextbox = this._oTextbox;
+ var sValue = this._oTextbox.value; // any saved queries plus what user has typed
+
+ // Don't update with type-ahead if text selection is not supported
+ if(!oTextbox.setSelectionRange && !oTextbox.createTextRange) {
+ return;
+ }
+
+ // Select the portion of text that the user has not typed
+ var nStart = sValue.length;
+ this._updateValue(oItem);
+ var nEnd = oTextbox.value.length;
+ this._selectText(oTextbox,nStart,nEnd);
+ var sPrefill = oTextbox.value.substr(nStart,nEnd);
+ this.typeAheadEvent.fire(this,sQuery,sPrefill);
+};
+
+/**
+ * Selects text in a text input box.
+ *
+ * @param {object} oTextbox Text input box element in which to select text
+ * @param {number} nStart Starting index of text string to select
+ * @param {number} nEnd Ending index of text selection
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._selectText = function(oTextbox, nStart, nEnd) {
+ if (oTextbox.setSelectionRange) { // For Mozilla
+ oTextbox.setSelectionRange(nStart,nEnd);
+ }
+ else if (oTextbox.createTextRange) { // For IE
+ var oTextRange = oTextbox.createTextRange();
+ oTextRange.moveStart("character", nStart);
+ oTextRange.moveEnd("character", nEnd-oTextbox.value.length);
+ oTextRange.select();
+ }
+ else {
+ oTextbox.select();
+ }
+};
+
+/**
+ * Syncs auto complete container with its helpers.
+ *
+ * @param {boolean} bShow True if container is expanded, false if collapsed
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers = function(bShow) {
+ var bFireEvent = false;
+ var width = this._oContainer._oContent.offsetWidth + "px";
+ var height = this._oContainer._oContent.offsetHeight + "px";
+
+ if(this.useIFrame && this._oContainer._oIFrame) {
+ bFireEvent = true;
+ if(this.alwaysShowContainer || bShow) {
+ this._oContainer._oIFrame.style.width = width;
+ this._oContainer._oIFrame.style.height = height;
+ }
+ else {
+ this._oContainer._oIFrame.style.width = 0;
+ this._oContainer._oIFrame.style.height = 0;
+ }
+ }
+ if(this.useShadow && this._oContainer._oShadow) {
+ bFireEvent = true;
+ if(this.alwaysShowContainer || bShow) {
+ this._oContainer._oShadow.style.width = width;
+ this._oContainer._oShadow.style.height = height;
+ }
+ else {
+ this._oContainer._oShadow.style.width = 0;
+ this._oContainer._oShadow.style.height = 0;
+ }
+ }
+};
+
+/**
+ * Animates expansion or collapse of the container.
+ *
+ * @param {boolean} bShow True if container should be expanded, false if
+ * container should be collapsed
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._toggleContainer = function(bShow) {
+ // Implementer has container always open so don't mess with it
+ if(this.alwaysShowContainer) {
+ // Fire these events to give implementers a hook into the container
+ // being populated and being emptied
+ if(bShow) {
+ this.containerExpandEvent.fire(this);
+ }
+ else {
+ this.containerCollapseEvent.fire(this);
+ }
+ this._bContainerOpen = bShow;
+ return;
+ }
+
+ var oContainer = this._oContainer;
+ // Container is already closed
+ if (!bShow && !this._bContainerOpen) {
+ oContainer._oContent.style.display = "none";
+ return;
+ }
+
+ // If animation is enabled...
+ var oAnim = this._oAnim;
+ if (oAnim && oAnim.getEl() && (this.animHoriz || this.animVert)) {
+ // If helpers need to be collapsed, do it right away...
+ // but if helpers need to be expanded, wait until after the container expands
+ if(!bShow) {
+ this._toggleContainerHelpers(bShow);
+ }
+
+ if(oAnim.isAnimated()) {
+ oAnim.stop();
+ }
+
+ // Clone container to grab current size offscreen
+ var oClone = oContainer._oContent.cloneNode(true);
+ oContainer.appendChild(oClone);
+ oClone.style.top = "-9000px";
+ oClone.style.display = "block";
+
+ // Current size of the container is the EXPANDED size
+ var wExp = oClone.offsetWidth;
+ var hExp = oClone.offsetHeight;
+
+ // Calculate COLLAPSED sizes based on horiz and vert anim
+ var wColl = (this.animHoriz) ? 0 : wExp;
+ var hColl = (this.animVert) ? 0 : hExp;
+
+ // Set animation sizes
+ oAnim.attributes = (bShow) ?
+ {width: { to: wExp }, height: { to: hExp }} :
+ {width: { to: wColl}, height: { to: hColl }};
+
+ // If opening anew, set to a collapsed size...
+ if(bShow && !this._bContainerOpen) {
+ oContainer._oContent.style.width = wColl+"px";
+ oContainer._oContent.style.height = hColl+"px";
+ }
+ // Else, set it to its last known size.
+ else {
+ oContainer._oContent.style.width = wExp+"px";
+ oContainer._oContent.style.height = hExp+"px";
+ }
+
+ oContainer.removeChild(oClone);
+ oClone = null;
+
+ var oSelf = this;
+ var onAnimComplete = function() {
+ // Finish the collapse
+ oAnim.onComplete.unsubscribeAll();
+
+ if(bShow) {
+ oSelf.containerExpandEvent.fire(oSelf);
+ }
+ else {
+ oContainer._oContent.style.display = "none";
+ oSelf.containerCollapseEvent.fire(oSelf);
+ }
+ oSelf._toggleContainerHelpers(bShow);
+ };
+
+ // Display container and animate it
+ oContainer._oContent.style.display = "block";
+ oAnim.onComplete.subscribe(onAnimComplete);
+ oAnim.animate();
+ this._bContainerOpen = bShow;
+ }
+ // Else don't animate, just show or hide
+ else {
+ if(bShow) {
+ oContainer._oContent.style.display = "block";
+ this.containerExpandEvent.fire(this);
+ }
+ else {
+ oContainer._oContent.style.display = "none";
+ this.containerCollapseEvent.fire(this);
+ }
+ this._toggleContainerHelpers(bShow);
+ this._bContainerOpen = bShow;
+ }
+
+};
+
+/**
+ * Toggles the highlight on or off for an item in the container, and also cleans
+ * up highlighting of any previous item.
+ *
+ * @param {object} oNewItem New The <li> element item to receive highlight
+ * behavior
+ * @param {string} sType "mouseover" will toggle highlight on, and "mouseout"
+ * will toggle highlight off.
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._toggleHighlight = function(oNewItem, sType) {
+ var sHighlight = this.highlightClassName;
+ if(this._oCurItem) {
+ // Remove highlight from old item
+ YAHOO.util.Dom.removeClass(this._oCurItem, sHighlight);
+ }
+
+ if((sType == "to") && sHighlight) {
+ // Apply highlight to new item
+ YAHOO.util.Dom.addClass(oNewItem, sHighlight);
+ this._oCurItem = oNewItem;
+ }
+};
+
+/**
+ * Toggles the pre-highlight on or off for an item in the container.
+ *
+ * @param {object} oNewItem New The <li> element item to receive highlight
+ * behavior
+ * @param {string} sType "mouseover" will toggle highlight on, and "mouseout"
+ * will toggle highlight off.
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._togglePrehighlight = function(oNewItem, sType) {
+ if(oNewItem == this._oCurItem) {
+ return;
+ }
+
+ var sPrehighlight = this.prehighlightClassName;
+ if((sType == "mouseover") && sPrehighlight) {
+ // Apply prehighlight to new item
+ YAHOO.util.Dom.addClass(oNewItem, sPrehighlight);
+ }
+ else {
+ // Remove prehighlight from old item
+ YAHOO.util.Dom.removeClass(oNewItem, sPrehighlight);
+ }
+};
+
+/**
+ * Updates the text input box value with selected query result. If a delimiter
+ * has been defined, then the value gets appended with the delimiter.
+ *
+ * @param {object} oItem The <li> element item with which to update the value
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._updateValue = function(oItem) {
+ var oTextbox = this._oTextbox;
+ var sDelimChar = (this.delimChar) ? this.delimChar[0] : null;
+ var sSavedQuery = this._sSavedQuery;
+ var sResultKey = oItem._sResultKey;
+ oTextbox.focus();
+
+ // First clear text field
+ oTextbox.value = "";
+ // Grab data to put into text field
+ if(sDelimChar) {
+ if(sSavedQuery) {
+ oTextbox.value = sSavedQuery;
+ }
+ oTextbox.value += sResultKey + sDelimChar;
+ if(sDelimChar != " ") {
+ oTextbox.value += " ";
+ }
+ }
+ else { oTextbox.value = sResultKey; }
+
+ // scroll to bottom of textarea if necessary
+ if(oTextbox.type == "textarea") {
+ oTextbox.scrollTop = oTextbox.scrollHeight;
+ }
+
+ // move cursor to end
+ var end = oTextbox.value.length;
+ this._selectText(oTextbox,end,end);
+
+ this._oCurItem = oItem;
+};
+
+/**
+ * Selects a result item from the container
+ *
+ * @param {object} oItem The selected <li> element item
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._selectItem = function(oItem) {
+ this._bItemSelected = true;
+ this._updateValue(oItem);
+ this.itemSelectEvent.fire(this, oItem, oItem._oResultData);
+ this._clearList();
+};
+
+/**
+ * For values updated by type-ahead, the right arrow key jumps to the end
+ * of the textbox, otherwise the container is closed.
+ *
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._jumpSelection = function() {
+ if(!this.typeAhead) {
+ return;
+ }
+ else {
+ this._clearList();
+ }
+};
+
+/**
+ * Triggered by up and down arrow keys, changes the current highlighted
+ * <li> element item. Scrolls container if necessary.
+ *
+ * @param {number} nKeyCode Code of key pressed
+ * @private
+ */
+YAHOO.widget.AutoComplete.prototype._moveSelection = function(nKeyCode) {
+ if(this._bContainerOpen) {
+ // Determine current item's id number
+ var oCurItem = this._oCurItem;
+ var nCurItemIndex = -1;
+
+ if (oCurItem) {
+ nCurItemIndex = oCurItem._nItemIndex;
+ }
+
+ var nNewItemIndex = (nKeyCode == 40) ?
+ (nCurItemIndex + 1) : (nCurItemIndex - 1);
+
+ // Out of bounds
+ if (nNewItemIndex < -2 || nNewItemIndex >= this._nDisplayedItems) {
+ return;
+ }
+
+ if (oCurItem) {
+ // Unhighlight current item
+ this._toggleHighlight(oCurItem, "from");
+ this.itemArrowFromEvent.fire(this, oCurItem);
+ }
+ if (nNewItemIndex == -1) {
+ // Go back to query (remove type-ahead string)
+ if(this.delimChar && this._sSavedQuery) {
+ if (!this._textMatchesOption()) {
+ this._oTextbox.value = this._sSavedQuery;
+ }
+ else {
+ this._oTextbox.value = this._sSavedQuery + this._sCurQuery;
+ }
+ }
+ else {
+ this._oTextbox.value = this._sCurQuery;
+ }
+ this._oCurItem = null;
+ return;
+ }
+ if (nNewItemIndex == -2) {
+ // Close container
+ this._clearList();
+ return;
+ }
+
+ var oNewItem = this._aListItems[nNewItemIndex];
+
+ // Scroll the container if necessary
+ var oContent = this._oContainer._oContent;
+ var scrollOn = ((YAHOO.util.Dom.getStyle(oContent,"overflow") == "auto") ||
+ (YAHOO.util.Dom.getStyle(oContent,"overflowY") == "auto"));
+ if(scrollOn && (nNewItemIndex > -1) &&
+ (nNewItemIndex < this._nDisplayedItems)) {
+ // User is keying down
+ if(nKeyCode == 40) {
+ // Bottom of selected item is below scroll area...
+ if((oNewItem.offsetTop+oNewItem.offsetHeight) > (oContent.scrollTop + oContent.offsetHeight)) {
+ // Set bottom of scroll area to bottom of selected item
+ oContent.scrollTop = (oNewItem.offsetTop+oNewItem.offsetHeight) - oContent.offsetHeight;
+ }
+ // Bottom of selected item is above scroll area...
+ else if((oNewItem.offsetTop+oNewItem.offsetHeight) < oContent.scrollTop) {
+ // Set top of selected item to top of scroll area
+ oContent.scrollTop = oNewItem.offsetTop;
+
+ }
+ }
+ // User is keying up
+ else {
+ // Top of selected item is above scroll area
+ if(oNewItem.offsetTop < oContent.scrollTop) {
+ // Set top of scroll area to top of selected item
+ this._oContainer._oContent.scrollTop = oNewItem.offsetTop;
+ }
+ // Top of selected item is below scroll area
+ else if(oNewItem.offsetTop > (oContent.scrollTop + oContent.offsetHeight)) {
+ // Set bottom of selected item to bottom of scroll area
+ this._oContainer._oContent.scrollTop = (oNewItem.offsetTop+oNewItem.offsetHeight) - oContent.offsetHeight;
+ }
+ }
+ }
+
+ this._toggleHighlight(oNewItem, "to");
+ this.itemArrowToEvent.fire(this, oNewItem);
+ if(this.typeAhead) {
+ this._updateValue(oNewItem);
+ }
+ }
+};
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+/**
+ *