001: /*
002: * $Id: CommandLinkRenderer.java 473327 2006-11-10 12:59:22Z niallp $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: package org.apache.struts.faces.renderer;
023:
024: import java.io.IOException;
025: import java.util.Iterator;
026:
027: import javax.faces.component.NamingContainer;
028: import javax.faces.component.UICommand;
029: import javax.faces.component.UIComponent;
030: import javax.faces.component.UIForm;
031: import javax.faces.component.UIParameter;
032: import javax.faces.context.FacesContext;
033: import javax.faces.context.ResponseWriter;
034: import javax.faces.event.ActionEvent;
035:
036: import org.apache.commons.logging.Log;
037: import org.apache.commons.logging.LogFactory;
038: import org.apache.struts.Globals;
039: import org.apache.struts.config.ActionConfig;
040: import org.apache.struts.config.ModuleConfig;
041:
042: /**
043: * <p><code>Renderer</code> implementation for the <code>commandLink</code>
044: * tag from the <em>Struts-Faces Integration Library</em>.</p>
045: *
046: * @version $Rev: 473327 $ $Date: 2006-11-10 06:59:22 -0600 (Fri, 10 Nov 2006) $
047: */
048:
049: public class CommandLinkRenderer extends AbstractRenderer {
050:
051: // -------------------------------------------------------- Static Variables
052:
053: /**
054: * <p>Token for private names.</p>
055: */
056: private static final String TOKEN = "org_apache_struts_faces_renderer_CommandLinkRenderer";
057:
058: /**
059: * <p>The <code>Log</code> instance for this class.</p>
060: */
061: private static Log log = LogFactory
062: .getLog(CommandLinkRenderer.class);
063:
064: // ---------------------------------------------------------- Public Methods
065:
066: /**
067: * <p>Perform setup processing that will be required for decoding the
068: * incoming request.</p>
069: *
070: * @param context FacesContext for the request we are processing
071: * @param component UIComponent to be processed
072: *
073: * @exception NullPointerException if <code>context</code>
074: * or <code>component</code> is null
075: */
076: public void decode(FacesContext context, UIComponent component) {
077:
078: // Implement spec requirements on NullPointerException
079: if ((context == null) || (component == null)) {
080: throw new NullPointerException();
081: }
082:
083: // Skip this component if it is not relevant
084: if (!component.isRendered() || isDisabled(component)
085: || isReadOnly(component)) {
086: return;
087: }
088:
089: // Set up variables we will need
090: UIForm form = null;
091: UIComponent parent = component.getParent();
092: while (parent != null) {
093: if (parent instanceof UIForm) {
094: form = (UIForm) parent;
095: break;
096: }
097: parent = parent.getParent();
098: }
099: if (form == null) {
100: log
101: .warn("CommandLinkComponent not nested inside UIForm, ignored");
102: return;
103: }
104:
105: // Was this the component that submitted this form?
106: String paramId = TOKEN;
107: String value = (String) context.getExternalContext()
108: .getRequestParameterMap().get(paramId);
109: if ((value == null)
110: || !value.equals(component.getClientId(context))) {
111: if (log.isTraceEnabled()) {
112: log.trace("decode(" + component.getId()
113: + ") --> not active");
114: }
115: return;
116: }
117:
118: // Queue an ActionEvent from this component
119: if (log.isTraceEnabled()) {
120: log.trace("decode(" + component.getId()
121: + ") --> queueEvent()");
122: }
123: component.queueEvent(new ActionEvent(component));
124:
125: }
126:
127: private static String passThrough[] = { "accesskey", "charset",
128: "dir", "hreflang", "lang", "onblur",
129: /* "onclick", */"ondblclick", "onfocus", "onkeydown",
130: "onkeypress", "onkeyup", "onmousedown", "onmousemove",
131: "onmouseout", "onmouseover", "onmouseup", "rel", "rev",
132: "style", "tabindex", "target", "title", "type" };
133:
134: /**
135: * <p>Render the beginning of a hyperlink to submit this form.</p>
136: *
137: * @param context FacesContext for the request we are processing
138: * @param component UIComponent to be rendered
139: * @param writer ResponseWriter we are rendering to
140: *
141: * @exception IOException if an input/output error occurs while rendering
142: * @exception NullPointerException if <code>context</code>
143: * or <code>component</code> is null
144: */
145: public void renderStart(FacesContext context,
146: UIComponent component, ResponseWriter writer)
147: throws IOException {
148:
149: // Skip this component if it is not relevant
150: if (!component.isRendered() || isDisabled(component)
151: || isReadOnly(component)) {
152: return;
153: }
154:
155: // Set up variables we will need
156: UIForm form = null;
157: UIComponent parent = component.getParent();
158: while (parent != null) {
159: if (parent instanceof UIForm) {
160: form = (UIForm) parent;
161: break;
162: }
163: parent = parent.getParent();
164: }
165: if (form == null) {
166: log
167: .warn("CommandLinkComponent not nested inside UIForm, ignored");
168: return;
169: }
170: String formClientId = form.getClientId(context);
171:
172: // If this is the first nested command link inside this form,
173: // render a hidden variable to identify which link did the submit
174: String key = formClientId + NamingContainer.SEPARATOR_CHAR
175: + TOKEN;
176: if (context.getExternalContext().getRequestMap().get(key) == null) {
177: writer.startElement("input", null);
178: writer.writeAttribute("name", TOKEN, null);
179: writer.writeAttribute("type", "hidden", null);
180: writer.writeAttribute("value", "", null);
181: writer.endElement("input");
182: context.getExternalContext().getRequestMap().put(key,
183: Boolean.TRUE);
184: }
185:
186: // Render the beginning of this hyperlink
187: writer.startElement("a", component);
188:
189: }
190:
191: /**
192: * <p>Render the attributes of a hyperlink to submit this form.</p>
193: *
194: * @param context FacesContext for the request we are processing
195: * @param component UIComponent to be rendered
196: * @param writer ResponseWriter we are rendering to
197: *
198: * @exception IOException if an input/output error occurs while rendering
199: * @exception NullPointerException if <code>context</code>
200: * or <code>component</code> is null
201: */
202: public void renderAttributes(FacesContext context,
203: UIComponent component, ResponseWriter writer)
204: throws IOException {
205:
206: // Skip this component if it is not relevant
207: if (!component.isRendered() || isDisabled(component)
208: || isReadOnly(component)) {
209: return;
210: }
211:
212: // Set up variables we will need
213: UIComponent form = null;
214: UIComponent parent = component.getParent();
215: while (parent != null) {
216: if (parent instanceof UIForm
217: || "org.apache.myfaces.trinidad.Form".equals(parent
218: .getFamily())
219: || "oracle.adf.Form".equals(parent.getFamily())) {
220: form = parent;
221: break;
222: }
223: parent = parent.getParent();
224: }
225: if (form == null) {
226: log
227: .warn("CommandLinkComponent not nested inside UIForm, ignored");
228: return;
229: }
230: String formClientId = form.getClientId(context);
231:
232: // Render the attributes of this hyperlink
233: if (component.getId() != null) {
234: writer.writeAttribute("id", component.getClientId(context),
235: "id");
236: }
237: writer.writeAttribute("href", "#", null);
238: String styleClass = (String) component.getAttributes().get(
239: "styleClass");
240: if (styleClass != null) {
241: writer.writeAttribute("class", styleClass, "styleClass");
242: }
243: renderPassThrough(context, component, writer, passThrough);
244:
245: // Render the JavaScript content of the "onclick" element
246: StringBuffer sb = new StringBuffer();
247: sb.append("document.forms['");
248: sb.append(formClientId);
249: sb.append("']['");
250: sb.append(TOKEN);
251: sb.append("'].value='");
252: sb.append(component.getClientId(context));
253: sb.append("';");
254: Iterator kids = component.getChildren().iterator();
255: while (kids.hasNext()) {
256: UIComponent kid = (UIComponent) kids.next();
257: if (!(kid instanceof UIParameter)) {
258: continue;
259: }
260: sb.append("document.forms['");
261: sb.append(formClientId);
262: sb.append("']['");
263: sb.append((String) kid.getAttributes().get("name"));
264: sb.append("'].value='");
265: sb.append((String) kid.getAttributes().get("value"));
266: sb.append("';");
267: }
268: sb.append("document.forms['");
269: sb.append(formClientId);
270: sb.append("'].submit(); return false;");
271: writer.writeAttribute("onclick", sb.toString(), null);
272:
273: // Render the component value as the hyperlink text
274: Object value = component.getAttributes().get("value");
275: if (value != null) {
276: if (value instanceof String) {
277: writer.write((String) value);
278: } else {
279: writer.write(value.toString());
280: }
281: }
282:
283: }
284:
285: /**
286: * <p>Render the end of a hyperlink to submit this form.</p>
287: *
288: * @param context FacesContext for the request we are processing
289: * @param component UIComponent to be rendered
290: * @param writer ResponseWriter we are rendering to
291: *
292: * @exception IOException if an input/output error occurs while rendering
293: * @exception NullPointerException if <code>context</code>
294: * or <code>component</code> is null
295: */
296: public void renderEnd(FacesContext context, UIComponent component,
297: ResponseWriter writer) throws IOException {
298:
299: // Skip this component if it is not relevant
300: if (!component.isRendered() || isDisabled(component)
301: || isReadOnly(component)) {
302: return;
303: }
304:
305: // Render the beginning of this hyperlink
306: writer.endElement("a");
307:
308: }
309:
310: }
|