001: /*
002: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
003: *
004: * "The contents of this file are subject to the Mozilla Public License
005: * Version 1.1 (the "License"); you may not use this file except in
006: * compliance with the License. You may obtain a copy of the License at
007: * http://www.mozilla.org/MPL/
008: *
009: * Software distributed under the License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
011: * License for the specific language governing rights and limitations under
012: * the License.
013: *
014: * The Original Code is ICEfaces 1.5 open source software code, released
015: * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
016: * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
017: * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
018: *
019: * Contributor(s): _____________________.
020: *
021: * Alternatively, the contents of this file may be used under the terms of
022: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
023: * License), in which case the provisions of the LGPL License are
024: * applicable instead of those above. If you wish to allow use of your
025: * version of this file only under the terms of the LGPL License and not to
026: * allow others to use your version of this file under the MPL, indicate
027: * your decision by deleting the provisions above and replace them with
028: * the notice and other provisions required by the LGPL License. If you do
029: * not delete the provisions above, a recipient may use your version of
030: * this file under either the MPL or the LGPL License."
031: *
032: */
033:
034: package com.icesoft.faces.component.selectinputtext;
035:
036: import com.icesoft.faces.context.DOMContext;
037: import com.icesoft.faces.context.effects.JavascriptContext;
038: import com.icesoft.faces.renderkit.dom_html_basic.DomBasicInputRenderer;
039: import com.icesoft.faces.renderkit.dom_html_basic.HTML;
040: import com.icesoft.faces.renderkit.dom_html_basic.PassThruAttributeRenderer;
041: import com.icesoft.faces.util.DOMUtils;
042: import org.apache.commons.logging.Log;
043: import org.apache.commons.logging.LogFactory;
044: import org.w3c.dom.Element;
045: import org.w3c.dom.Node;
046: import org.w3c.dom.Text;
047:
048: import javax.faces.component.UIComponent;
049: import javax.faces.component.UIInput;
050: import javax.faces.context.FacesContext;
051: import javax.faces.model.SelectItem;
052: import java.io.IOException;
053: import java.util.HashSet;
054: import java.util.Iterator;
055: import java.util.Map;
056: import java.util.Set;
057:
058: public class SelectInputTextRenderer extends DomBasicInputRenderer {
059: private final String AUTOCOMPLETE_DIV = "autoCompleteDiv";
060: private static final Log log = LogFactory
061: .getLog(SelectInputTextRenderer.class);
062:
063: public boolean getRendersChildren() {
064: return true;
065: }
066:
067: public void encodeBegin(FacesContext facesContext,
068: UIComponent uiComponent) throws IOException {
069: validateParameters(facesContext, uiComponent, null);
070: if (log.isTraceEnabled()) {
071: log.trace("encodeBegin");
072: }
073: SelectInputText component = (SelectInputText) uiComponent;
074: DOMContext domContext = DOMContext.attachDOMContext(
075: facesContext, uiComponent);
076: String clientId = uiComponent.getClientId(facesContext);
077: String divId = clientId + AUTOCOMPLETE_DIV;
078: String call = " new Ice.Autocompleter('" + clientId + "','"
079: + divId + "', " + component.getOptions() + " ,'"
080: + component.getRowClass() + "','"
081: + component.getSelectedRowClass() + "');";
082:
083: if (!domContext.isInitialized()) {
084: Element root = domContext.createRootElement(HTML.DIV_ELEM);
085: Element input = domContext.createElement(HTML.INPUT_ELEM);
086: input.setAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_TEXT);
087: setRootElementId(facesContext, input, uiComponent);
088: root.appendChild(input);
089: input.setAttribute(HTML.NAME_ATTR, clientId);
090: input.setAttribute(HTML.CLASS_ATTR, component
091: .getInputTextClass());
092: String inputStyle = component.getWidthAsStyle();
093: if (inputStyle != null && inputStyle.length() > 0)
094: input.setAttribute(HTML.STYLE_ATTR, inputStyle);
095: else
096: input.removeAttribute(HTML.STYLE_ATTR);
097: input.setAttribute("autocomplete", "off");
098: Element div = domContext.createElement(HTML.DIV_ELEM);
099: String listClass = component.getListClass();
100:
101: div.setAttribute(HTML.ID_ATTR, divId);
102: if (listClass == null) {
103: div
104: .setAttribute(HTML.STYLE_ATTR,
105: "display:none;border:1px solid black;background-color:white;z-index:500;");
106: } else {
107: div.setAttribute(HTML.CLASS_ATTR, listClass);
108: }
109: root.appendChild(div);
110: String rootStyle = component.getStyle();
111: if (rootStyle != null && rootStyle.length() > 0)
112: root.setAttribute(HTML.STYLE_ATTR, rootStyle);
113: else
114: root.removeAttribute(HTML.STYLE_ATTR);
115: root.setAttribute(HTML.CLASS_ATTR, component
116: .getStyleClass());
117:
118: // Element script = domContext.createElement(HTML.SCRIPT_ELEM);
119: // script.setAttribute(HTML.SCRIPT_LANGUAGE_ATTR,
120: // HTML.SCRIPT_LANGUAGE_JAVASCRIPT);
121: // String scriptCode = "window.onLoad(function(){" + call + "});";
122: // Node node = domContext.createTextNode(scriptCode);
123: // script.appendChild(node);
124: // root.appendChild(script);
125: if (log.isDebugEnabled()) {
126: log
127: .debug("SelectInputText:encodeBegin():component created with the following id : "
128: + clientId);
129: }
130: }
131: Set excludes = new HashSet();
132: excludes.add(HTML.ONKEYDOWN_ATTR);
133: excludes.add(HTML.ONKEYUP_ATTR);
134: excludes.add(HTML.ONFOCUS_ATTR);
135: excludes.add(HTML.ONBLUR_ATTR);
136: PassThruAttributeRenderer.renderAttributes(facesContext,
137: uiComponent, getExcludesArray(excludes));
138: JavascriptContext.addJavascriptCall(facesContext, call);
139: }
140:
141: public void encodeChildren(FacesContext facesContext,
142: UIComponent uiComponent) throws IOException {
143: DOMContext domContext = DOMContext.getDOMContext(facesContext,
144: uiComponent);
145: SelectInputText component = (SelectInputText) uiComponent;
146: Element input = (Element) domContext.getRootNode()
147: .getFirstChild();
148:
149: input.setAttribute("onfocus", "setFocus(this.id);");
150: input.setAttribute("onblur", "setFocus('');");
151: // this would prevent, when first valueChangeListener fires with null value
152: Object value = component.getValue();
153: if (value != null) {
154: input.setAttribute(HTML.VALUE_ATTR, value.toString());
155: // populate list of values only if the component's value have been changed.
156: if (component.hasChanged() && value.toString().length() > 0) {
157: if (log.isDebugEnabled()) {
158: log
159: .debug("SelectInputText:encodeChildren(): component's value have been changed, start populating list : ");
160: }
161: populateList(facesContext, uiComponent);
162: component.setChangedComponentId(null);
163: }
164: }
165: renderAttribute(uiComponent, input, HTML.DISABLED_ATTR,
166: HTML.DISABLED_ATTR);
167: renderAttribute(uiComponent, input, HTML.READONLY_ATTR,
168: HTML.READONLY_ATTR);
169: domContext.stepOver();
170: domContext.streamWrite(facesContext, uiComponent);
171: }
172:
173: public void populateList(FacesContext facesContext,
174: UIComponent uiComponent) throws IOException {
175: if (uiComponent instanceof UIInput) {
176: if (log.isTraceEnabled()) {
177: log.trace("populateList");
178: }
179: SelectInputText component = ((SelectInputText) uiComponent);
180: Iterator matchs = component.getItemList();
181:
182: if (component.getSelectFacet() != null) {
183: if (log.isDebugEnabled()) {
184: log
185: .debug("SelectInputText:populateList(): \"selectInputText\" facet found, generate generic html for list");
186: }
187: UIComponent facet = component.getSelectFacet();
188: DOMContext domContext = DOMContext.getDOMContext(
189: facesContext, uiComponent);
190:
191: Element listDiv = domContext
192: .createElement(HTML.DIV_ELEM);
193: Map requestMap = facesContext.getExternalContext()
194: .getRequestMap();
195: //set index to 0, so child components can get client id from autoComplete component
196: component.setIndex(0);
197: while (matchs.hasNext()) {
198: Element div = domContext
199: .createElement(HTML.DIV_ELEM);
200: SelectItem item = (SelectItem) matchs.next();
201: requestMap.put(component.getListVar(), item
202: .getValue());
203: listDiv.appendChild(div);
204: // When HTML is display we still need a selected value. Hidding the value in a hidden span
205: // accomplishes this.
206: Element spanToDisplay = domContext
207: .createElement(HTML.SPAN_ELEM);
208: spanToDisplay.setAttribute(HTML.CLASS_ATTR,
209: "informal");
210: div.appendChild(spanToDisplay);
211: domContext.setCursorParent(spanToDisplay);
212: encodeParentAndChildren(facesContext, facet);
213: Element spanToSelect = domContext
214: .createElement(HTML.SPAN_ELEM);
215: spanToSelect.setAttribute(HTML.STYLE_ATTR,
216: "visibility:hidden;display:none;");
217: Text label = domContext.createTextNode(DOMUtils
218: .escapeAnsi(item.getLabel()));
219: spanToSelect.appendChild(label);
220: div.appendChild(spanToSelect);
221: component.resetId(facet);
222: }
223: component.setIndex(-1);
224:
225: String nodeValue = DOMUtils.nodeToString(listDiv)
226: .replaceAll("\n", "");
227: String call = "Autocompleter.Finder.find('"
228: + component.getClientId(facesContext)
229: + "').updateNOW('" + nodeValue + "');";
230: JavascriptContext.addJavascriptCall(facesContext, call);
231:
232: } else {
233: if (log.isDebugEnabled()) {
234: log
235: .debug("SelectInputText:populateList(): \"selectItem(s)\" found, generate plain-text for list");
236: }
237: if (matchs.hasNext()) {
238: StringBuffer sb = new StringBuffer("<div>");
239: SelectItem item = null;
240: while (matchs.hasNext()) {
241: item = (SelectItem) matchs.next();
242: sb.append("<div>").append(
243: DOMUtils.escapeAnsi(item.getLabel()))
244: .append("</div>");
245: }
246: sb.append("</div>");
247: String call = "Autocompleter.Finder.find('"
248: + component.getClientId(facesContext)
249: + "').updateNOW('" + sb.toString() + "');";
250: JavascriptContext.addJavascriptCall(facesContext,
251: call);
252: }
253: }//outer if
254: }
255: }
256: }
|