KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icesoft > faces > context > effects > JavascriptContext


1 /*
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * "The contents of this file are subject to the Mozilla Public License
5  * Version 1.1 (the "License"); you may not use this file except in
6  * compliance with the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS"
10  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
11  * License for the specific language governing rights and limitations under
12  * the License.
13  *
14  * The Original Code is ICEfaces 1.5 open source software code, released
15  * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
16  * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
17  * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
18  *
19  * Contributor(s): _____________________.
20  *
21  * Alternatively, the contents of this file may be used under the terms of
22  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
23  * License), in which case the provisions of the LGPL License are
24  * applicable instead of those above. If you wish to allow use of your
25  * version of this file only under the terms of the LGPL License and not to
26  * allow others to use your version of this file under the MPL, indicate
27  * your decision by deleting the provisions above and replace them with
28  * the notice and other provisions required by the LGPL License. If you do
29  * not delete the provisions above, a recipient may use your version of
30  * this file under either the MPL or the LGPL License."
31  *
32  */

33
34 package com.icesoft.faces.context.effects;
35
36
37 import com.icesoft.faces.application.D2DViewHandler;
38 import com.icesoft.faces.application.StartupTime;
39 import com.icesoft.faces.context.BridgeFacesContext;
40
41 import javax.faces.component.UIComponent;
42 import javax.faces.context.ExternalContext;
43 import javax.faces.context.FacesContext;
44 import java.util.ArrayList JavaDoc;
45 import java.util.Collections JavaDoc;
46 import java.util.HashMap JavaDoc;
47 import java.util.Iterator JavaDoc;
48 import java.util.List JavaDoc;
49 import java.util.Map JavaDoc;
50 import java.util.Random JavaDoc;
51
52 /**
53  *
54  * Used to send Javascript to the browser
55  */

56 public class JavascriptContext {
57     private static final Random JavaDoc RANDOM = new Random JavaDoc();
58
59     /**
60      * Request scope key, used to store javascript code to be sent to the browser
61      */

62     private static final String JavaDoc REQUEST_KEY =
63             "icesoft_javascript_request_key_7698193";
64     /**
65      * Effects scope key, used to store the fired effects in the request scope
66      */

67     private static final String JavaDoc EFFECTS_REQUEST_KEY =
68             "icesoft_javascript_effects_request_key_9072451";
69     /**
70      * Request scope key for componenet focus
71      */

72     private static final String JavaDoc FOCUS_COMP_KEY =
73             "icesoft_javascript_focus_comp";
74     /**
75      * Request Scope Key, storing the focus
76      */

77     private static final String JavaDoc FOCUS_APP_KEY = "icesoft_javascript_focus_app";
78     /**
79      * Request Scope Key, indicating that extras needs to be included
80      */

81     public static final String JavaDoc LIB_KEY =
82             "icesoft_javascript_required_libs_897241";
83     /**
84      * ID of script node used to send Javascript in a dom update
85      */

86     public static final String JavaDoc DYNAMIC_CODE_ID = "dynamic-code";
87
88     /**
89      * URL of the ICE Bridge lib
90      */

91     public static final String JavaDoc ICE_BRIDGE = "/xmlhttp" + StartupTime.getStartupInc() + "icefaces-d2d.js";
92
93     /**
94      * URL of the ICE Extras lib
95      */

96     public static final String JavaDoc ICE_EXTRAS = "/xmlhttp" + StartupTime.getStartupInc() + "ice-extras.js";
97
98     /**
99      * Include a script tag in the <head> section of the page with the src
100      * attribute set to libname. This will insure that all icefaces pages
101      * contain this script for the remainder of the session.
102      *
103      * @param libname the source of the javascript file
104      * @param facesContext The facescontext this file is needed for
105      */

106     public static void includeLib(String JavaDoc libname, FacesContext facesContext) {
107         if (facesContext == null)
108             return;
109         ExternalContext externalContext = facesContext.getExternalContext();
110         if (externalContext == null)
111             return;
112         Map JavaDoc sessionMap = externalContext.getSessionMap();
113         if (sessionMap == null)
114             return;
115         List JavaDoc libs = (List JavaDoc) sessionMap.get(LIB_KEY);
116         if (libs == null) {
117             libs = new ArrayList JavaDoc();
118             sessionMap.put(LIB_KEY, libs);
119         }
120         if (!libs.contains(libname))
121             libs.add(libname);
122     }
123
124     /**
125      * Get the included javascript libraries
126      *
127      * @param facesContext
128      * @return
129      */

130     public static String JavaDoc[] getIncludedLibs(FacesContext facesContext) {
131         List JavaDoc libs = (List JavaDoc) facesContext.getExternalContext().getSessionMap()
132                 .get(LIB_KEY);
133         String JavaDoc[] result = new String JavaDoc[0];
134         if (libs != null) {
135             result = new String JavaDoc[libs.size()];
136             libs.toArray(result);
137         }
138         return result;
139     }
140
141     /**
142      * Add a javascript call to be executed on the browser. Code will be
143      * executed at the end of the current render cycle.
144      * <p/>
145      * Note: When sending function definitions you must specify the function
146      * name as this['functionName'] = function(){} For example: <code>
147      * helloWorld(name}{ alert('Hello [' + name + ']'); }</code>
148      * <p/>
149      * Would need to be written as <code> this['helloWorld'] = function(name){
150      * alert('Hello [' + name + ']'); }</code>
151      *
152      * @param facesContext
153      * @param call Javascript code to execute
154      */

155     public static void addJavascriptCall(FacesContext facesContext,
156                                          String JavaDoc call) {
157         Map JavaDoc map = facesContext.getExternalContext().getRequestMap();
158         addJavascriptCall(map, call);
159     }
160
161     /**
162      * Add a javascript call to the request map
163      * @param map
164      * @param call
165      */

166     private static void addJavascriptCall(Map JavaDoc map, String JavaDoc call) {
167         String JavaDoc currentValue = (String JavaDoc) map.get(REQUEST_KEY);
168         if (currentValue == null) {
169             map.put(REQUEST_KEY, call);
170         } else {
171             map.put(REQUEST_KEY, currentValue + call);
172         }
173     }
174
175     /**
176      * Add a javascript call to this request
177      * @param facesContext
178      * @return
179      */

180     public static String JavaDoc getJavascriptCalls(FacesContext facesContext) {
181         Map JavaDoc map = facesContext.getExternalContext().getRequestMap();
182         return getJavascriptCalls(map);
183     }
184
185     /**
186      * Get javascript calls from the Request map
187      * @param map
188      * @return
189      */

190     public static String JavaDoc getJavascriptCalls(Map JavaDoc map) {
191         addtEffectJavascriptCalls(map);
192         String JavaDoc code = (String JavaDoc) map.get(REQUEST_KEY);
193         map.put(REQUEST_KEY, "");
194         String JavaDoc focus = getFocusCall(map);
195         code = replaceDupes(
196                 code == null || "".equals(code) ? focus : code + ';' + focus);
197         // Hack so that javascript will be called from both the bridge and the html parser
198
// Remove when we have a better way
199
if ("".equals(code)) {
200             return "";
201         } else {
202             return "var c = function(){" + code +
203                    "};if(window.application){c();}else{window.onLoad(c)};"
204                     + randomComment();
205         }
206     }
207
208     /**
209      * Get the focus call from the request map
210      * @param map
211      * @return
212      */

213     private static String JavaDoc getFocusCall(Map JavaDoc map) {
214         String JavaDoc focus = (String JavaDoc) map.get(FOCUS_APP_KEY);
215         if (focus == null) {
216             focus = (String JavaDoc) map.get(FOCUS_COMP_KEY);
217         }
218         if (focus == null) {
219             return "";
220         } else {
221             map.remove(FOCUS_APP_KEY);
222             map.remove(FOCUS_COMP_KEY);
223             return "Ice.Focus.setFocus('" + focus + "');";
224         }
225     }
226
227
228     /**
229      * Wrap the effect in a javascript method to be called later. Returns the
230      * method name. Used in local effects.
231      *
232      * @param effect
233      * @param id
234      * @param context
235      * @return The name of the method that wraps the effect
236      */

237     public static String JavaDoc applyEffect(Effect effect, String JavaDoc id,
238                                      FacesContext context) {
239         //Get the real ID if a JSF component
240
//UIComponent uiComponent = context.getViewRoot().findComponent(id);
241

242         UIComponent uiComponent = D2DViewHandler.findComponent(id, context.getViewRoot());
243         if (uiComponent != null) {
244             id = uiComponent.getClientId(context);
245         }
246
247         String JavaDoc name = genFunctionName(id, effect);
248
249         String JavaDoc call = "window['" + name + "'] = function (){" +
250                       "id = '" + id + "';" + effect.toString() + "};";
251
252         addJavascriptCall(context, call);
253         return name + "();";
254     }
255
256     /**
257      * Fire an effect at the end of the current render cycle. Fired from server, non local.
258      *
259      * @param effect
260      * @param id Target element of the effect
261      * @param context
262      */

263     public static void fireEffect(Effect effect, String JavaDoc id,
264                                   FacesContext context) {
265         if (effect == null || effect.isFired()) return;
266         effect.setFired(true);
267         Object JavaDoc viewRoot = context.getViewRoot();
268         try{
269
270             
271        UIComponent uiComponent = D2DViewHandler.findComponent(id, context.getViewRoot());
272         if (uiComponent != null) {
273             id = uiComponent.getClientId(context);
274         }
275         }catch(Exception JavaDoc e){
276             /*Class clazz = context.getViewRoot().getClass();
277             Method[] methods =clazz.getMethods();
278             for(int i = 0; i < methods.length; i++){
279                 Method m = methods[i];
280                 System.err.println("Method [" + m.getName() + "]");
281                 Class[] args = m.getParameterTypes();
282                 for(int a =0; a<args.length;a++){
283                     System.err.println("Arg [" + args[a].getName() + "]");
284                 }
285             } */

286             System.err.println("View Root is [" + viewRoot.getClass().getName() + "]");
287             e.printStackTrace();
288         }
289         effect.setId(id);
290         addEffect(effect, context);
291
292     }
293
294     /**
295      * Fire an effect at the end of the current render cycle
296      *
297      * @param effect
298      * @param component
299      */

300     public static void fireEffect(Effect effect, UIComponent component) {
301         if (effect == null || effect.isFired()) return;
302         FacesContext facesContext = FacesContext.getCurrentInstance();
303         fireEffect(effect, component, facesContext);
304     }
305
306     /**
307      * Fire an effect at the end of the current render cycle
308      *
309      * @param effect
310      * @param component
311      * @param facesContext
312      */

313     public static void fireEffect(Effect effect, UIComponent component,
314                                   FacesContext facesContext) {
315         if (effect == null || effect.isFired()) return;
316         String JavaDoc id = component.getClientId(facesContext);
317         fireEffect(effect, id, facesContext);
318     }
319
320     /**
321      * Fire an effect at the end of the current render cycle
322      *
323      * @param uiComponent
324      * @param facesContext
325      */

326
327     public static void fireEffect(UIComponent uiComponent,
328                                   FacesContext facesContext) {
329         Effect effect = (Effect) uiComponent.getAttributes().get("effect");
330         if (effect != null)
331             fireEffect(effect, uiComponent, facesContext);
332     }
333
334     /**
335      * Get the Effect function for a given event
336      * @param uiComponent
337      * @param event
338      * @param id
339      * @param facesContext
340      * @return
341      */

342     public static String JavaDoc getEffectFunctionForEvent(UIComponent uiComponent,
343                                                    String JavaDoc event, String JavaDoc id,
344                                                    FacesContext facesContext) {
345         String JavaDoc result = null;
346         Effect fx = getEffectForEvent(uiComponent, event);
347         if (fx != null) {
348             result = applyEffect(fx, id, facesContext);
349         }
350         return result;
351     }
352
353     /**
354      * Get the Effect for a givin function
355      * @param uiComponent
356      * @param event
357      * @return
358      */

359     private static Effect getEffectForEvent(UIComponent uiComponent,
360                                             String JavaDoc event) {
361         Effect result = null;
362         Object JavaDoc o = uiComponent.getAttributes().get(event);
363         if (o != null && o instanceof Effect) {
364             result = (Effect) o;
365         }
366         return result;
367     }
368
369
370     /**
371      * Generate a unique function name for local effects
372      *
373      * @param id
374      * @param effect
375      * @return
376      */

377     private static String JavaDoc genFunctionName(String JavaDoc id, Effect effect) {
378         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("iceEffect");
379         char[] ca = id.toCharArray();
380         // Make sure no invalid characters are in the function name
381
//65 - 90 A - Z
382
//97 - 122 a - z
383
//48 - 57 / 0 - 9
384
for (int i = 0; i < ca.length; i++) {
385             int c = (int) ca[i];
386             if ((c > 64 && c < 91) || (c > 96 && c < 123) || (c > 47 && c < 58))
387             {
388                 sb.append(ca[i]);
389             } else {
390                 sb.append('_');
391             }
392         }
393         sb.append(effect.hashCode());
394         return sb.toString();
395     }
396
397     /**
398      * Remove duplicate semi-colons from a givin string
399      * @param s
400      * @return
401      */

402     private static String JavaDoc replaceDupes(String JavaDoc s) {
403         if (s.indexOf(";;") == -1) return s;
404         s = s.replaceAll(";;", ";");
405         return s;
406     }
407
408     /**
409      * \ Set focus on an HTML element.
410      *
411      * @param context
412      * @param id
413      */

414     public static void focus(FacesContext context, String JavaDoc id) {
415         //this method relies on XMLRenderer to create these "script" elements
416
if (!id.equals("")) {
417             Map JavaDoc map = context.getExternalContext().getRequestMap();
418             map.put(FOCUS_COMP_KEY, id);
419         }
420     }
421
422     /**
423      * Set the application focus for the current request, overrides and setFocus call.
424      * Generally setFocus is used by components, while setApplicationFocus is used by the application.
425      * @param id
426      */

427     public static void applicationFocus(FacesContext facesContext, String JavaDoc id) {
428         if (!id.equals("")) {
429
430             Map JavaDoc map = facesContext.getExternalContext().getRequestMap();
431             map.put(FOCUS_APP_KEY, id);
432         }
433     }
434
435     /**
436      * Get the focus for the current request
437      * @param context
438      * @return
439      */

440     public static String JavaDoc getFocus(FacesContext context) {
441         String JavaDoc focusId = ((BridgeFacesContext) context).getFocusId();
442         Map JavaDoc map = context.getExternalContext().getRequestMap();
443         if (map.containsKey(FOCUS_COMP_KEY))
444             focusId = (String JavaDoc) map.get(FOCUS_COMP_KEY);
445         if (map.containsKey(FOCUS_APP_KEY))
446             focusId = (String JavaDoc) map.get(FOCUS_APP_KEY);
447         return focusId;
448     }
449
450     /**
451      * Add an effect call for the current request
452      * @param effect
453      * @param facesContext
454      */

455     private static void addEffect(Effect effect, FacesContext facesContext) {
456         Map JavaDoc map = facesContext.getExternalContext().getRequestMap();
457         List JavaDoc list = (ArrayList JavaDoc) map.get(EFFECTS_REQUEST_KEY);
458         if (list == null) {
459             list = new ArrayList JavaDoc();
460             map.put(EFFECTS_REQUEST_KEY, list);
461         }
462         list.add(effect);
463     }
464
465     /**
466      * Add fired effects as javascript calls
467      * @param map
468      */

469     private static void addtEffectJavascriptCalls(Map JavaDoc map) {
470
471         List JavaDoc list = (ArrayList JavaDoc) map.get(EFFECTS_REQUEST_KEY);
472         if (list == null) {
473             return;
474         }
475         Map JavaDoc sequencedEffects = new HashMap JavaDoc();
476         Iterator JavaDoc iter = list.iterator();
477         while (iter.hasNext()) {
478             Effect effect = (Effect) iter.next();
479             if (effect.getSequence() == null &&
480                 !(effect instanceof EffectQueue)) {
481                 String JavaDoc call =
482                         "id = '" + effect.getId() + "';" + effect.toString();
483                 addJavascriptCall(map, call);
484             } else {
485
486                 extractEffectSequence(effect, sequencedEffects);
487             }
488         }
489
490         if (sequencedEffects.size() > 0) {
491             iter = sequencedEffects.values().iterator();
492             int sequence = 0;
493             while (iter.hasNext()) {
494                 list = (List JavaDoc) iter.next();
495                 Collections.sort(list, new EffectComparator());
496                 String JavaDoc call = buildSequenceEffectCall(list, sequence);
497                 addJavascriptCall(map, call);
498                 sequence++;
499             }
500         }
501         map.remove(EFFECTS_REQUEST_KEY);
502     }
503
504     /**
505      * Build sequence of javascript effect calls
506      * @param list
507      * @param sequence
508      * @return
509      */

510     private static String JavaDoc buildSequenceEffectCall(List JavaDoc list, int sequence) {
511         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
512         Iterator JavaDoc effectIter = list.iterator();
513         int effect = 0;
514         String JavaDoc lastCall = null;
515         while (effectIter.hasNext()) {
516             Effect fx = (Effect) effectIter.next();
517             String JavaDoc var = getVariableName(sequence, effect);
518             lastCall = "var " + var + " = '" + fx.getId() + "';" +
519                        fx.toString(var, lastCall);
520             effect++;
521         }
522         return lastCall;
523     }
524
525     /**
526      * Extra Javascript Effect Sequence from a map of effects
527      * @param effect
528      * @param sequencedEffects
529      */

530     private static void extractEffectSequence(Effect effect,
531                                               Map JavaDoc sequencedEffects) {
532         String JavaDoc seqName = effect.getSequence();
533
534         List JavaDoc seq = (List JavaDoc) sequencedEffects.get(seqName);
535         if (seq == null) {
536             seq = new ArrayList JavaDoc();
537             sequencedEffects.put(seqName, seq);
538         }
539         if (effect instanceof EffectQueue) {
540             List JavaDoc eqList = ((EffectQueue) effect).getEffects();
541             Iterator JavaDoc eqIter = eqList.iterator();
542             int seqId = 0;
543             while (eqIter.hasNext()) {
544                 Effect fx = (Effect) eqIter.next();
545                 fx.setSequence(seqName);
546                 fx.setSequenceId(seqId);
547                 fx.setId(effect.getId());
548                 seq.add(fx);
549                 seqId++;
550
551             }
552         } else {
553             seq.add(effect);
554         }
555     }
556
557     /**
558      * Get variable name for an effect in a sequence
559      * @param sequence
560      * @param effect
561      * @return
562      */

563     private static String JavaDoc getVariableName(int sequence, int effect) {
564         return "s" + sequence + "e" + effect;
565     }
566
567     /**
568      * Generate random Javascript comment to force a diff on the 'script'
569      * elements, thus triggering their evaluation in the browser.
570      */

571     private static String JavaDoc randomComment() {
572         return "//" + RANDOM.nextInt();
573     }
574 }
575
Popular Tags