001: package org.araneaframework.jsp.tag.uilib.form.element.text;
002:
003: import java.io.Writer;
004: import java.util.HashMap;
005: import java.util.Iterator;
006: import java.util.Map;
007: import javax.servlet.jsp.JspException;
008: import org.araneaframework.core.ApplicationService;
009: import org.araneaframework.framework.ThreadContext;
010: import org.araneaframework.framework.TopServiceContext;
011: import org.araneaframework.framework.TransactionContext;
012: import org.araneaframework.jsp.UiUpdateEvent;
013: import org.araneaframework.jsp.util.JspUtil;
014: import org.araneaframework.jsp.util.JspWidgetCallUtil;
015: import org.araneaframework.uilib.event.OnChangeEventListener;
016: import org.araneaframework.uilib.form.control.AutoCompleteTextControl;
017:
018: /**
019: * Standard text input form element tag with autocompletion.
020: *
021: * @author Steven Jentson (steven@webmedia.ee)
022: * @author Taimo Peelo (taimo@araneaframework.org)
023: *
024: * @jsp.tag
025: * name = "autoCompleteTextInput"
026: * body-content = "JSP"
027: * description = "Form text input field, represents UiLib "AutoCompleteTextControl"."
028: */
029: public class FormAutoCompleteTextInputHtmlTag extends
030: BaseFormTextInputHtmlTag {
031: protected String divClass = "autocompletediv";
032:
033: protected int doEndTag(Writer out) throws Exception {
034: assertControlType("AutoCompleteTextControl");
035:
036: AutoCompleteTextControl.ViewModel viewModel = ((AutoCompleteTextControl.ViewModel) controlViewModel);
037:
038: Map attributes = new HashMap();
039: attributes.put("maxlength", viewModel.getMaxLength());
040: attributes.put("autocomplete", "off");
041:
042: // TODO: make it completely consistent with every other tag
043: // Disallow event output from base tag -- directly outwritten onblur attribute breaks onchange functionality
044: // due to autocomplete component attaching its own eventlisteners in javascript. Not sure why!
045: // Attaching base onblur with Event.observe() does not work quite correctly either. It is probably caused
046: // by browser workaround in scriptaculous library.
047: boolean b = events;
048: events = false;
049: writeTextInput(out, "text", true, attributes);
050: events = b;
051: // restore
052: //out.write("<script>Event.observe($('" + getScopedFullFieldId() + "'), 'change', function(){ " + JspWidgetCallUtil.getSubmitScriptForEvent() +"});</script>");
053:
054: JspUtil.writeOpenStartTag(out, "div");
055: JspUtil.writeAttribute(out, "id", "ACdiv." + getFullFieldId());
056: JspUtil.writeAttribute(out, "class", divClass);
057: // hide div to avoid flicker that occurs otherwise when new Ajax.AutoCompleter is finally created
058: JspUtil.writeAttribute(out, "style", "display:none;");
059: JspUtil.writeCloseStartTag(out);
060: JspUtil.writeEndTag(out, "div");
061:
062: StringBuffer acRequestUrl = constructACUrl();
063:
064: JspUtil
065: .writeStartTag_SS(out,
066: "script type=\"text/javascript\"");
067: out
068: .write(constructACRegistrationScript(viewModel,
069: acRequestUrl));
070: JspUtil.writeEndTag(out, "script");
071:
072: super .doEndTag(out);
073: return EVAL_PAGE;
074: }
075:
076: /* ***********************************************************************************
077: * Helper functions for construction of URL.
078: * ***********************************************************************************/
079: protected StringBuffer constructACUrl() {
080: StringBuffer result = new StringBuffer();
081: result.append("_ap.getSystemForm().action + \"?");
082: result
083: .append(
084: constructServiceParameter(TopServiceContext.TOP_SERVICE_KEY))
085: .append(" + \"").append('&');
086: result
087: .append(
088: constructServiceParameter(TransactionContext.TRANSACTION_ID_KEY))
089: .append(" + \"").append('&');
090: result
091: .append(
092: constructServiceParameter(ThreadContext.THREAD_SERVICE_KEY))
093: .append(" + \"").append('&');
094: result.append(ApplicationService.ACTION_PATH_KEY).append('=')
095: .append(getFullFieldId()).append('&');
096: result.append(ApplicationService.ACTION_HANDLER_ID_KEY).append(
097: '=').append(AutoCompleteTextControl.LISTENER_NAME);
098:
099: return result;
100: }
101:
102: protected String constructServiceParameter(String serviceId) {
103: StringBuffer result = new StringBuffer();
104: result.append(serviceId).append("=\"").append(
105: "+_ap.getSystemForm().").append(serviceId).append(
106: ".value");
107: return result.toString();
108: }
109:
110: /* ***********************************************************************************
111: * Script for registration of the new autocompleter.
112: * ***********************************************************************************/
113: protected String constructACRegistrationScript(
114: AutoCompleteTextControl.ViewModel viewModel,
115: StringBuffer acRequestUrl) {
116: StringBuffer script = new StringBuffer();
117: script
118: .append("_ap.addClientLoadEvent(function() {new Ajax.Autocompleter(\"");
119: script.append(getFullFieldId());
120: script.append("\", \"ACdiv.");
121: script.append(getFullFieldId());
122: script.append("\", ");
123: script.append(acRequestUrl);
124: script.append("\", {");
125:
126: // Autocompleter options
127: for (Iterator i = getOptionMap().entrySet().iterator(); i
128: .hasNext();) {
129: Map.Entry entry = (Map.Entry) i.next();
130: script.append((String) entry.getKey());
131: script.append(":");
132: script.append((String) entry.getValue());
133: if (i.hasNext())
134: script.append(",");
135: }
136:
137: script.append("});});");
138:
139: return script.toString();
140: }
141:
142: /** @since 1.0.2 */
143: protected Map getOptionMap() {
144: AutoCompleteTextControl.ViewModel viewModel = ((AutoCompleteTextControl.ViewModel) controlViewModel);
145:
146: Map result = new HashMap(2);
147: result.put("minChars", String.valueOf(viewModel
148: .getMinCompletionLength()));
149: if (!viewModel.isDisabled() && events
150: && viewModel.isOnChangeEventRegistered())
151: result
152: .put(
153: "afterUpdateElement",
154: "function(el, selectedEl) {"
155: + JspWidgetCallUtil
156: .getSubmitScriptForEvent(getOnChangeEvent())
157: + "}");
158: return result;
159: }
160:
161: protected UiUpdateEvent getOnChangeEvent() {
162: return new UiUpdateEvent(OnChangeEventListener.ON_CHANGE_EVENT,
163: formFullId + "." + derivedId, (String) null,
164: updateRegionNames);
165: }
166:
167: /* ***********************************************************************************
168: * Tag attributes
169: * ***********************************************************************************/
170:
171: /**
172: * @jsp.attribute
173: * type = "java.lang.String"
174: * required = "false"
175: * description = "Class attribute assigned to <DIV> inside which suggestions are shown."
176: */
177: public void setDivClass(String divClass) throws JspException {
178: this .divClass = (String) evaluate("divClass", divClass,
179: String.class);
180: }
181: }
|