KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > barracuda > core > comp > renderer > html > HTMLActionRenderer


1 /*
2  * Copyright (C) 2003 Christian Cryder [christianc@granitepeaks.com]
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * $Id: HTMLActionRenderer.java,v 1.41 2004/02/01 05:16:27 christianc Exp $
19  */

20 package org.enhydra.barracuda.core.comp.renderer.html;
21
22 import java.util.*;
23
24 import org.apache.log4j.*;
25 import org.w3c.dom.*;
26 import org.w3c.dom.html.*;
27
28 import org.enhydra.barracuda.core.comp.*;
29 import org.enhydra.barracuda.core.comp.helper.*;
30 import org.enhydra.barracuda.core.comp.renderer.*;
31 import org.enhydra.barracuda.core.comp.scripting.*;
32 import org.enhydra.barracuda.core.helper.servlet.*;
33 import org.enhydra.barracuda.core.util.http.URLRewriter;
34 import org.enhydra.barracuda.core.view.*;
35 import org.enhydra.barracuda.plankton.http.LightweightURL;
36
37 /**
38  * This class handles the default rendering of actions into an HTML view.
39  */

40 public class HTMLActionRenderer extends HTMLComponentRenderer {
41
42     protected static final Logger logger = Logger.getLogger(HTMLActionRenderer.class.getName());
43
44     protected EnabledHelper eh = new EnabledHelper();
45
46     /**
47      * The purpose of this method is to create a default Node to be used when
48      * the component is not bound to any specific view. In the case of BAction,
49      * it will attempt to use the default template node if possible (ie. if
50      * it is an <a>, <form>, <input>, <button>, or <select> element); if anything else,
51      * it will defer to the super() method
52      *
53      * @param doc the master Document which can be used to create elements
54      * from scratch
55      * @param comp the component to be rendered
56      * @param vc the view context for the current request
57      * @return a default node (created from scratch)
58      * @throws UnsupportedFormatException if the renderer has no default node
59      */

60     public Node createDefaultNode(Document doc, BComponent comp, ViewContext vc) throws UnsupportedFormatException { //csc_110501.1
61
//ask the renderer to create the default Node
62
Node templateNode = vc.getTemplateNode();
63         Node defaultNode = null;
64         if ((templateNode instanceof HTMLAnchorElement)
65          || (templateNode instanceof HTMLFormElement)
66          || (templateNode instanceof HTMLInputElement)
67          || (templateNode instanceof HTMLButtonElement)
68          || (templateNode instanceof HTMLSelectElement)) {
69             defaultNode = templateNode.cloneNode(true);
70         } else {
71             return super.createDefaultNode(doc, comp, vc);
72         }
73         if (logger.isInfoEnabled()) logger.info("Creating default node: "+defaultNode);
74         return defaultNode;
75     }
76
77     /**
78      * Render the data from the component into the view, taking into
79      * consideration the specified ViewContext
80      *
81      * @param comp the component to be rendered
82      * @param view the view the component should be rendered in
83      * @param vc the view context
84      * @throws RenderException if unable to render the component in the
85      * specified view
86      */

87     public void renderComponent(BComponent comp, View view, ViewContext vc) throws RenderException {
88         //make sure the component is a BAction component
89
if (!(comp instanceof BAction)) {
90             String JavaDoc errmsg = "This renderer can only render BAction components: "+comp;
91             logger.warn(errmsg);
92             throw new NoSuitableRendererException(errmsg);
93         }
94         BAction actionComp = (BAction) comp;
95         HTMLElement el = (HTMLElement)view.getNode();
96
97         //show what we're doing
98
if (logger.isDebugEnabled()) showNodeInterfaces(view, logger);
99
100         //first, allow the parent class to do anything it needs to
101
super.renderComponent(actionComp, view, vc);
102
103         manipulateActionElement(el, actionComp, vc);
104
105         //finally, make sure we reflect the components enabled/disabled status
106
eh.setEnabled(el, actionComp.isEnabled());
107     }
108
109     /**
110      * Generic Element - cast elements to more specific elements in order to
111      * call the appropriate overloaded method. Throw an exception if the
112      * element is not supported.
113      *
114      * @param el the HTML element to be manipulated
115      * @param comp the BAction component containing information about the
116      * action to take on bound HTML element
117      * @param vc the current ViewContext
118      * @throws RenderException
119      */

120     protected static void manipulateActionElement(Element el, BAction comp, ViewContext vc) throws RenderException {
121         if (el instanceof HTMLAnchorElement) {
122             manipulateActionElement((HTMLAnchorElement)el, comp, vc);
123         } else if (el instanceof HTMLFormElement) {
124             manipulateActionElement((HTMLFormElement)el, comp, vc);
125         } else if (el instanceof HTMLInputElement) {
126             manipulateActionElement((HTMLInputElement)el, comp, vc);
127         } else if (el instanceof HTMLButtonElement) {
128             manipulateActionElement((HTMLButtonElement)el, comp, vc);
129         } else if (el instanceof HTMLSelectElement) {
130             manipulateActionElement((HTMLSelectElement)el, comp, vc);
131         //} else if (el instanceof [another supported element here]) {
132
// manipulateActionElement(([another supported element here])el, comp, vc);
133
//}
134
} else {
135             String JavaDoc errmsg = "Element does not implement one of HTMLAnchorElement, HTMLFormElement, HTMLInputElement, HTMLButtonElement, or HTMLSelectElement and cannot be rendered: "+el;
136             logger.warn(errmsg);
137             throw new NoSuitableRendererException(errmsg);
138         }
139     }
140
141     /**
142      * HTMLAnchorElement - set the "href" attribute
143      *
144      * @see #manipulateActionElement(Element, BAction, ViewContext)
145      */

146     protected static void manipulateActionElement(HTMLAnchorElement el, BAction comp, ViewContext vc) throws RenderException {
147         if (logger.isInfoEnabled()) logger.info("Rendering based on HTMLAnchorElement interface...");
148
149         //set the href
150
//csc_041403.1 - basically, don't set the action unless its actually been specified in the component;
151
//we may still need to do this in the other manipulateActionElementFunctions...
152
//csc_041403.1 el.setHref(comp.getAction(vc));
153
if (comp.hasAction()) el.setHref(comp.getAction(vc)); //csc_041403.1
154

155         //if we need to disable the back button and the client supports
156
//Javascript, we can do so by setting the onclick attribute
157
if (comp.getDisableBackButton() && clientScriptingAllowed(comp, vc)) {
158             el.setAttribute("onclick", "location.replace(this.href);return false;");
159         }
160     }
161
162     /**
163      * HTMLFormElement - set the "action" attribute
164      *
165      * @see #manipulateActionElement(Element, BAction, ViewContext)
166      */

167     protected static void manipulateActionElement(HTMLFormElement el, BAction comp, ViewContext vc) throws RenderException {
168         if (logger.isInfoEnabled()) logger.info("Rendering based on HTMLFormElement interface...");
169
170         //if the client supports Javascript...
171
if (clientScriptingAllowed(comp, vc)) {
172             StringBuffer JavaDoc sb = new StringBuffer JavaDoc(200);
173             StringBuffer JavaDoc sbAction = new StringBuffer JavaDoc(200);
174             boolean disable = comp.getDisableBackButton();
175
176             if (disable) sbAction.append(ParamGateway.PARAM_TARGET);
177             LightweightURL lu = new LightweightURL(comp.getAction(vc, true));
178             sbAction.append(lu.getBaseStr());
179             if (disable) sbAction.append(ParamGateway.PARAM_EXT);
180             sbAction.append(lu.getParamStr());
181
182             //redirect the form to param gateway servlet
183
el.setAction(URLRewriter.encodeURL(vc, sbAction.toString()));
184
185             addSubmitScript(comp, sb, "this");
186
187             //set the onsubmit attribute
188
el.setAttribute("onsubmit", sb.toString());
189
190             //make sure we include the necessary script library
191
includeScriptLibrary(el, comp, BScriptResource.JS_FORM_CONTROL);
192             if (disable) includeScriptLibrary(el, comp, BScriptResource.JS_CLIENT_SERVER_HTTP_LIB);
193         } else { //else just set the form action
194
el.setAction(comp.getAction(vc));
195         }
196     }
197
198     /**
199      * HTMLInputElement
200      *
201      * @see #manipulateActionElement(Element, BAction, ViewContext)
202      */

203     protected static void manipulateActionElement(HTMLInputElement el, BAction comp, ViewContext vc) throws RenderException {
204         if (logger.isInfoEnabled()) logger.info("Rendering based on HTMLInputElement interface...");
205         HTMLFormElement fel = el.getForm();
206 //TODO:need to handle elements that are not part of a form (ie. fel==null)
207

208         //if the client supports Javascript...
209
if (clientScriptingAllowed(comp, vc)) {
210             //build the action String
211
StringBuffer JavaDoc sb = new StringBuffer JavaDoc(200);
212             StringBuffer JavaDoc sbAction = new StringBuffer JavaDoc(100);
213             boolean disable = comp.getDisableBackButton();
214
215             //adjust the documents action
216
if (disable) sbAction.append(ParamGateway.PARAM_TARGET);
217             LightweightURL lu = new LightweightURL(comp.getAction(vc, true));
218             sbAction.append(lu.getBaseStr());
219             if (disable) sbAction.append(ParamGateway.PARAM_EXT);
220             sb.append("this.form.action='").append(URLRewriter.encodeURL(vc, sbAction.toString())).append(lu.getParamStr()).append("';");
221
222             addSubmitScript(comp, sb, "this.form");
223
224             //adjust the onclick value to invoke submit
225
el.setAttribute("onclick", sb.toString());
226
227             //if we are dealing with a "submit" button, we need to set the
228
//form's action as well since, if the user hits enter, the form
229
//will be submitted but the button will not be clicked (IE actually
230
//seems to handle this correctly, but Mozilla does not; this will
231
//work for both). Thanks to Iman L. Crawford [icrawford@greatnation.com]
232
//for pointing out this problem.
233
if ("submit".equalsIgnoreCase(el.getType())) {
234                 fel.setAttribute("onsubmit", new StringBuffer JavaDoc(50).append("this.").append(NamingHelper.getName(el)).append(".click();return false;").toString());
235             }
236
237             //make sure we include the necessary script library
238
includeScriptLibrary(el, comp, BScriptResource.JS_FORM_CONTROL);
239             if (disable) includeScriptLibrary(el, comp, BScriptResource.JS_CLIENT_SERVER_HTTP_LIB);
240         } else { //else do it the manual way
241
//make sure the button type is submit
242
if (!"submit".equalsIgnoreCase(el.getType())) {
243                 if ("button".equalsIgnoreCase(el.getType())) {
244                     //modify the <input> type to make this form submitable in
245
//a non-javascript environment.
246
el.setAttribute("type", "submit");
247                 } else {
248                     if (comp.getRenderStrategy() != RenderStrategy.CUSTOM_SCRIPT) {
249                         //whoops, it's an <input> element of neither type "submit",
250
//nor type "button". Probably overstepping bounds in
251
//modifying the type attribute here, so throw exception
252
//instead.
253
String JavaDoc errmsg = "Cannot render Input action listener; input type is not 'submit': "+el;
254                         logger.warn(errmsg);
255                         throw new NoSuitableRendererException(errmsg);
256                     }
257                 }
258             }
259
260             //rename the button appropriately (don't encode)
261
el.setName(FormGateway.FORM_TARGET+comp.getAction(vc, true));
262
263             //redirect the form to event forwarding servlet (encode)
264
fel.setAction(URLRewriter.encodeURL(vc, NamingHelper.getName(fel)+FormGateway.FORM_EXT));
265         }
266     }
267
268     /**
269      * HTMLButtonElement
270      *
271      * @see #manipulateActionElement(Element, BAction, ViewContext)
272      */

273     protected static void manipulateActionElement(HTMLButtonElement el, BAction comp, ViewContext vc) throws RenderException {
274         if (logger.isInfoEnabled()) logger.info("Rendering based on HTMLButtonElement interface...");
275         HTMLFormElement fel = el.getForm();
276 //TODO:need to handle elements that are not part of a form (ie. fel==null)
277

278         //if the client supports Javascript...
279
if (clientScriptingAllowed(comp, vc)) {
280             //build the action String
281
StringBuffer JavaDoc sb = new StringBuffer JavaDoc(200);
282             StringBuffer JavaDoc sbAction = new StringBuffer JavaDoc(100);
283             boolean disable = comp.getDisableBackButton();
284
285             //adjust the documents action
286
if (disable) sbAction.append(ParamGateway.PARAM_TARGET);
287             LightweightURL lu = new LightweightURL(comp.getAction(vc, true));
288             sbAction.append(lu.getBaseStr());
289             if (disable) sbAction.append(ParamGateway.PARAM_EXT);
290             sb.append("this.form.action='").append(URLRewriter.encodeURL(vc, sbAction.toString())).append(lu.getParamStr()).append("';");
291
292             addSubmitScript(comp, sb, "this.form");
293
294             //adjust the onclick value to invoke submit
295
el.setAttribute("onclick", sb.toString());
296
297             //if we are dealing with a "submit" button, we need to set the
298
//form's action as well since, if the user hits enter, the form
299
//will be submitted but the button will not be clicked (IE actually
300
//seems to handle this correctly, but Mozilla does not; this will
301
//work for both). Thanks to Iman L. Crawford [icrawford@greatnation.com]
302
//for pointing out this problem.
303
if ("submit".equalsIgnoreCase(el.getType())) {
304                 fel.setAttribute("onsubmit", new StringBuffer JavaDoc(50).append("this.").append(NamingHelper.getName(el)).append(".click();return false;").toString());
305             }
306
307             //make sure we include the necessary script library
308
includeScriptLibrary(el, comp, BScriptResource.JS_FORM_CONTROL);
309             if (disable) includeScriptLibrary(el, comp, BScriptResource.JS_CLIENT_SERVER_HTTP_LIB);
310         } else { //else do it the manual way
311
//make sure the button type is submit
312
if (!"submit".equalsIgnoreCase(el.getType())) {
313                 if ("button".equalsIgnoreCase(el.getType())) {
314                     //modify the <button> type to make this form submitable in
315
//a non-javascript environment.
316
el.setAttribute("type", "submit");
317                 } else {
318                     if (comp.getRenderStrategy() != RenderStrategy.CUSTOM_SCRIPT) {
319                         //whoops, it's a "reset" <button>. Probably overstepping
320
//bounds in modifying the type attribute here, so throw
321
//exception instead.
322
String JavaDoc errmsg = "Cannot render Button action listener; button type is not 'submit': "+el;
323                         logger.warn(errmsg);
324                         throw new NoSuitableRendererException(errmsg);
325                     }
326                 }
327             }
328
329             //rename the button appropriately (don't encode)
330
el.setName(FormGateway.FORM_TARGET+comp.getAction(vc, true));
331
332             //redirect the form to event forwarding servlet (encode)
333
fel.setAction(URLRewriter.encodeURL(vc, NamingHelper.getName(fel)+FormGateway.FORM_EXT));
334         }
335     }
336
337     /**
338      * HTMLSelectElement
339      *
340      * @see #manipulateActionElement(Element, BAction, ViewContext)
341      */

342     protected static void manipulateActionElement(HTMLSelectElement el, BAction comp, ViewContext vc) throws RenderException {
343         if (logger.isInfoEnabled()) logger.info("Rendering based on HTMLSelectElement interface...");
344
345         HTMLFormElement fel = el.getForm();
346 //TODO:need to handle elements that are not part of a form (ie. fel==null)
347

348         //if the client supports Javascript...
349
if (clientScriptingAllowed(comp, vc)) {
350             //build the action String
351
StringBuffer JavaDoc sb = new StringBuffer JavaDoc(200);
352             StringBuffer JavaDoc sbAction = new StringBuffer JavaDoc(100);
353             boolean disable = comp.getDisableBackButton();
354
355             //adjust the documents action
356
if (disable) sbAction.append(ParamGateway.PARAM_TARGET);
357             LightweightURL lu = new LightweightURL(comp.getAction(vc, true));
358             sbAction.append(lu.getBaseStr());
359             if (disable) sbAction.append(ParamGateway.PARAM_EXT);
360             sb.append("this.form.action='").append(URLRewriter.encodeURL(vc, sbAction.toString())).append(lu.getParamStr()).append("';");
361
362             addSubmitScript(comp, sb, "this.form");
363
364             //set the onchange value to invoke submit
365
el.setAttribute("onchange", sb.toString());
366
367             //make sure we include the necessary script library
368
includeScriptLibrary(el, comp, BScriptResource.JS_FORM_CONTROL);
369             if (disable) includeScriptLibrary(el, comp, BScriptResource.JS_CLIENT_SERVER_HTTP_LIB);
370         } else {
371             if (comp.getRenderStrategy() != RenderStrategy.CUSTOM_SCRIPT) {
372                 String JavaDoc errmsg = "Cannot render Select action listener; client does not support Javascript: "+el;
373                 logger.warn(errmsg);
374                 throw new NoSuitableRendererException(errmsg);
375             }
376
377             //rename the button appropriately (don't encode)
378
el.setName(FormGateway.FORM_TARGET+comp.getAction(vc, true));
379
380             //redirect the form to event forwarding servlet (encode)
381
fel.setAction(URLRewriter.encodeURL(vc, NamingHelper.getName(fel)+FormGateway.FORM_EXT));
382         }
383     }
384
385 ///////////////////////// Internal Utility Functions /////////////////////////
386

387     /**
388      * Does the client support javascript, is javascript currently enabled on
389      * the client, and does the current render strategy allow for javascript?
390      * If so, then client scripting is allowed.
391      *
392      * @param comp the BAction component containing information about the
393      * action to take on bound HTML element
394      * @param vc the current ViewContext
395      * @return true if javascript is allowed, false if not
396      */

397     private static boolean clientScriptingAllowed(BAction comp, ViewContext vc) {
398         return vc.getViewCapabilities().getScriptingType() instanceof ScriptingType.JavaScript1x
399             && comp.getRenderStrategy() != RenderStrategy.NEVER_SCRIPT
400             && comp.getRenderStrategy() != RenderStrategy.CUSTOM_SCRIPT;
401     }
402
403     /**
404      * includes a script resource to the document. Note: script resouces will
405      * only be added once to the document. Duplicates are ignored.
406      *
407      * @param el an HTMLElement providing a hook into the document
408      * @param comp the BAction component the script resource is being assocated
409      * with
410      * @param script the path to the script resource. This is assumed to be
411      * part of the xlib resources. An example string to pass in might
412      * be BScriptResource.JS_FORM_CONTROL
413      * @see BScriptResource
414      */

415     private static void includeScriptLibrary(HTMLElement el, BAction comp, String JavaDoc script) {
416         BScriptResource bsr = new BScriptResource(ResourceGateway.EXT_RESOURCE_ID+script);
417         bsr.setView(new DefaultView(el));
418         comp.addStepChild(bsr, true);
419     }
420
421     /**
422      * adds the standard submit script for form elements which have a BAction
423      * bound to them. Also adds any script functions added to BAction.
424      *
425      * @param comp the BAction component being added to the document
426      * @param sb the StringBuffer with which to add the script information
427      * @param form the name to use for the javascript reference to the current
428      * form element. eg... for a form element, the value would be
429      * "this". For an element in a form, the value would be
430      * "this.form".
431      * @see BAction#addScriptFunction(String)
432      */

433     private static void addSubmitScript(BAction comp, StringBuffer JavaDoc sb, String JavaDoc form) {
434       //saw_082603_2 begin - check the new disableFormLocking option in the BAction
435
//sb.append("return doSubmitAndLock(").append(form);
436
sb.append("return ");
437         if (comp.getDisableFormLocking()) sb.append("doSubmitAndNoLock(");
438         else sb.append("doSubmitAndLock(");
439         sb.append(form);
440       //saw_082603_2 end
441
Collection scriptFunctions = comp.getScriptFunctions();
442         if (scriptFunctions != null) {
443             Iterator iter = scriptFunctions.iterator();
444             while (iter.hasNext()) {
445                 sb.append(",").append((String JavaDoc)iter.next());
446             }
447         }
448         if (comp.getDisableBackButton()) sb.append(",cshl_SubmitAndReplace");
449         sb.append(");");
450     }
451 }
452
Popular Tags