001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/msgcntr/trunk/messageforums-app/src/java/org/sakaiproject/tool/messageforums/jsf/RendererUtil.java $
003: * $Id: RendererUtil.java 9227 2006-05-15 15:02:42Z cwen@iupui.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.tool.messageforums.jsf;
021:
022: import java.io.IOException;
023: import java.util.Collection;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Locale;
028: import java.util.Map;
029: import javax.faces.component.UIComponent;
030: import javax.faces.component.UIForm;
031: import javax.faces.component.UIViewRoot;
032: import javax.faces.context.FacesContext;
033: import javax.faces.context.ResponseWriter;
034: import javax.faces.el.ValueBinding;
035: import javax.faces.model.SelectItem;
036:
037: /**
038: * Common static utility methods that help in implementing JSF tags.
039: */
040: public class RendererUtil {
041:
042: /** This class is meant for static use only */
043: private RendererUtil() {
044: }
045:
046: /**
047: * Sets component attribute value - if a ValueBinding exists for that
048: * attribute, set through the binding; otherwise, set the value directly on
049: * the component.
050: */
051: public static void setAttribute(FacesContext context,
052: UIComponent component, String name, Object value) {
053: ValueBinding binding = component.getValueBinding(name);
054: if (binding != null) {
055: try {
056: binding.setValue(context, value);
057: } catch (IllegalArgumentException e) {
058: // try setting the value as a String
059: binding.setValue(context, String.valueOf(value));
060: }
061: } else {
062: component.getAttributes().put(name, value);
063: }
064: }
065:
066: /**
067: * Return the attribute value - handles getting the value from a
068: * ValueBinding if necessary. This is necessary because of a difference in
069: * the Sun JSF RI versus the MyFaces RI. The Sun RI
070: * component.getAttributes().get(attrName) will automatically return value
071: * bindings, whereas the MyFaces implmentation requires getting values from
072: * ValueBinding seperately.
073: */
074: public static Object getAttribute(FacesContext context,
075: UIComponent component, String name) {
076: // first check the attributes
077: Object ret = component.getAttributes().get(name);
078: if (ret != null)
079: return ret;
080:
081: // next check the value bindings
082: ValueBinding vb = component.getValueBinding(name);
083: if (vb != null)
084: ret = vb.getValue(context);
085:
086: return ret;
087: }
088:
089: /**
090: * Same as getAttribute, but if not found, we return a default value.
091: */
092: public static Object getDefaultedAttribute(FacesContext context,
093: UIComponent component, String name, Object defaultValue) {
094: Object o = getAttribute(context, component, name);
095: if (o == null)
096: o = defaultValue;
097: return o;
098: }
099:
100: /**
101: * Helper method for recursively encoding a component.
102: *
103: * @param context
104: * the given FacesContext
105: * @param component
106: * the UIComponent to render
107: * @throws IOException
108: */
109: public static void encodeRecursive(FacesContext context,
110: UIComponent component) throws IOException {
111: if (!component.isRendered()) {
112: return;
113: }
114:
115: component.encodeBegin(context);
116:
117: if (component.getRendersChildren()) {
118: component.encodeChildren(context);
119: } else {
120: Iterator iter = component.getChildren().iterator();
121:
122: while (iter.hasNext()) {
123: UIComponent child = (UIComponent) iter.next();
124: encodeRecursive(context, child);
125: }
126: }
127: component.encodeEnd(context);
128: }
129:
130: /**
131: * If renderer supports disabled or readonly attributes use this method to
132: * obtain an early exit from decode method. Good idea to include it anyway,
133: * compnent will continue to work when these properties are added.
134: */
135: public static boolean isDisabledOrReadonly(FacesContext context,
136: UIComponent component) {
137: boolean disabled = false;
138: boolean readOnly = false;
139:
140: Object disabledAttr = getAttribute(context, component,
141: "disabled");
142: if (disabledAttr != null) {
143: disabled = disabledAttr.equals(Boolean.TRUE);
144: }
145:
146: Object readOnlyAttr = getAttribute(context, component,
147: "readonly");
148: if (readOnlyAttr != null) {
149: readOnly = readOnlyAttr.equals(Boolean.TRUE);
150: }
151:
152: return readOnly | disabled;
153: }
154:
155: /**
156: * Write default HTML passthrough attributes
157: */
158: public static void writePassthroughs(FacesContext context,
159: UIComponent component) throws IOException {
160: String[] passthrus = { "ondblclick", "onclick", "onkeydown",
161: "onkeypress", "onkeyup", "onmousedown", "onmousemove",
162: "onmouseout", "onmouseover", "onmouseup" };
163: writePassthroughAttributes(passthrus, true, context, component);
164: }
165:
166: /**
167: * write passthough attributes on the current element
168: */
169: public static void writePassthroughAttributes(String[] passthrus,
170: boolean writeNullAttrs, FacesContext context,
171: UIComponent component) throws IOException {
172: ResponseWriter writer = context.getResponseWriter();
173: for (int i = 0; i < passthrus.length; i++) {
174: String key = passthrus[i];
175: String value = (String) getAttribute(context, component,
176: key);
177: if (writeNullAttrs && value == null)
178: value = "";
179: if (value != null)
180: writer.writeAttribute(key, value, null);
181: }
182: }
183:
184: /**
185: * @param attributeMap
186: * String key/value pairs
187: * @param writer
188: * response writer
189: */
190: public static void writeAttributes(Map attributeMap,
191: ResponseWriter writer) throws IOException {
192: Iterator iter = attributeMap.keySet().iterator();
193: while (iter.hasNext()) {
194: String key = (String) iter.next();
195: String value = (String) attributeMap.get(key);
196: if (value == null)
197: value = "";
198: writer.writeAttribute(key, value, key);
199: }
200:
201: }
202:
203: /**
204: * @param attributeMap
205: * String key/value pairs
206: * @param context
207: * Faces context
208: * @param component
209: * the UIComponent
210: * @throws IOException
211: */
212: public static void writeAttributes(Map attributeMap,
213: FacesContext context) throws IOException {
214: ResponseWriter writer = context.getResponseWriter();
215: writeAttributes(attributeMap, writer);
216: }
217:
218: /**
219: * Renders a script that includes an external JavaScript that gets added to
220: * the document through a document.write() if a gatekeeper value is NOT set.
221: * This effectively makes the script inclusion a per request JavaScript
222: * singleton.
223: *
224: * @param gateKey
225: * for key value pair
226: * @param gateValue
227: * value for key value pair for gatekeeper
228: * @param contextBasePath
229: * the web app with the script
230: * @param scriptPath
231: * the webapp-relative path
232: * @throws IOException
233: */
234: public static void writeSmartExternalScripts(FacesContext context,
235: String gateKey, String gateValue, String contextBasePath,
236: String[] scriptPaths) throws IOException {
237: ResponseWriter writer = context.getResponseWriter();
238: writeSmartExternalScripts(writer, gateKey, gateValue,
239: contextBasePath, scriptPaths);
240: }
241:
242: /**
243: * Renders a script that includes an external JavaScript that gets added to
244: * the document through a document.write() if a gatekeeper value is NOT set.
245: * This effectively makes the script inclusion a per request JavaScript
246: * singleton.
247: *
248: * @param writer
249: * the ResponseWriter
250: * @param gateKey
251: * for key value pair
252: * @param gateValue
253: * value for key value pair for gatekeeper
254: * @param contextBasePath
255: * the web app with the script
256: * @param scriptPath
257: * the webapp-relative path
258: * @throws IOException
259: */
260: public static void writeSmartExternalScripts(ResponseWriter writer,
261: String gateKey, String gateValue, String contextBasePath,
262: String[] scriptPaths) throws IOException {
263: writer.write("<script>");
264: writer.write(" if (typeof window['" + gateKey + "'] == '"
265: + gateValue + "')");
266: writer.write(" {");
267:
268: for (int i = 0; i < scriptPaths.length; i++) {
269: writer.write(" document.write(");
270: writer
271: .write(" \"<\" + \"script type='text/javascript' src='/'\" + "
272: + contextBasePath + " +");
273: writer.write(" \"'" + scriptPaths[i]
274: + "'><\" + \"/script>);");
275: }
276:
277: writer.write(" var " + gateKey + " = '" + gateValue + "';");
278:
279: writer.write(" }");
280: writer.write("</script>");
281: writer.write("");
282: writer.write("");
283: }
284:
285: /**
286: * Get a Map of String key/value pairs from a UIComponent for all attributes
287: * keys in a collection
288: *
289: * @param collection
290: * @param component
291: * @return Map of String key/value pairs from a UIComponent for all keys in
292: * a collection
293: */
294: public static Map mapComponentAttributes(Collection collection,
295: UIComponent component) {
296: Map attributeMap = new HashMap();
297: if (collection == null)
298: return attributeMap;
299: String[] attributeNames = new String[collection.size()];
300: Object[] objs = collection.toArray();
301: for (int i = 0; i < objs.length; i++) {
302: attributeNames[i] = (String) objs[i];
303: }
304: return mapComponentAttributes(attributeNames, component);
305: }
306:
307: /**
308: * Get String key/value pairs from a UIComponent for all attributes keys in
309: * an array
310: *
311: * @param attributeNames
312: * @param component
313: * @return Map of String key/value pairs from a UIComponent for all keys in
314: * a collection
315: */
316: public static Map mapComponentAttributes(String[] attributeNames,
317: UIComponent component) {
318: Map attributeMap = new HashMap();
319: for (int i = 0; i < attributeNames.length; i++) {
320: attributeMap.put(attributeNames[i], (String) component
321: .getAttributes().get(attributeNames[i]));
322: }
323: return attributeMap;
324: }
325:
326: /**
327: * Switch handling utility.
328: *
329: * @param rawSwitch
330: * String input string
331: * @param supportOnOff
332: * boolean can input string be on, off?
333: * @param supportTrueFalse
334: * boolean can input string be true, false?
335: * @param supportYesNo
336: * boolean can input string be yes, no?
337: * @param returnOnOff
338: * boolean output on, off instead of true false
339: * @param returnYesNo
340: * boolean output yes, no instead of true false
341: * @param defaultValue
342: * boolean if unknown, return true or false?
343: * @return String raw swrich sring translated to correct switch value or
344: * default
345: */
346: public static String makeSwitchString(String rawSwitch,
347: boolean supportOnOff, boolean supportTrueFalse,
348: boolean supportYesNo, boolean returnOnOff,
349: boolean returnYesNo, boolean defaultValue) {
350: boolean switchValue = defaultValue;
351:
352: String trueString = "true";
353: String falseString = "false";
354:
355: if (returnOnOff) {
356: trueString = "on";
357: falseString = "off";
358: } else if (returnYesNo) {
359: trueString = "yes";
360: falseString = "no";
361: }
362:
363: if (supportOnOff) {
364: if ("on".equalsIgnoreCase(rawSwitch))
365: switchValue = true;
366: if ("off".equalsIgnoreCase(rawSwitch))
367: switchValue = false;
368: } else if (supportTrueFalse) {
369: if ("true".equalsIgnoreCase(rawSwitch))
370: switchValue = true;
371: if ("false".equalsIgnoreCase(rawSwitch))
372: switchValue = false;
373: } else if (supportYesNo) {
374: if ("yes".equalsIgnoreCase(rawSwitch))
375: switchValue = true;
376: if ("no".equalsIgnoreCase(rawSwitch))
377: switchValue = false;
378: }
379:
380: if (switchValue) {
381: return trueString;
382: } else {
383: return falseString;
384: }
385: }
386:
387: /**
388: * Given a List of SelectItems render the select options
389: *
390: * @param out
391: * @param items
392: * List of SelectItems
393: * @param selected
394: * seelcted choice
395: * @param clientId
396: * the id
397: * @param styleClass
398: * the optional style class
399: * @param component
400: * the component being rendered
401: * @throws IOException
402: */
403:
404: public static void renderMenu(ResponseWriter out, List items,
405: int selected, String clientId, String styleClass,
406: UIComponent component) throws IOException {
407: // // debug lines
408: // out.writeText("startElement select", null);
409: // if (true) return;
410: out.startElement("select", component);
411: out.writeAttribute("name", clientId, "id");
412: out.writeAttribute("id", clientId, "id");
413: if (styleClass != null) {
414: out.writeAttribute("class", styleClass, "styleClass");
415: }
416:
417: Iterator iter = items.iterator();
418: while (iter.hasNext()) {
419: SelectItem si = (SelectItem) iter.next();
420: Integer value = (Integer) si.getValue();
421: String label = si.getLabel();
422: out.startElement("option", component);
423: out.writeAttribute("value", value, null);
424: if (value.intValue() == selected) {
425: out.writeAttribute("selected", "selected", null);
426: }
427: out.writeText(label, null);
428: }
429: out.endElement("select");
430: }
431:
432: /** Return the Locale from the FacesContext */
433: public static Locale getLocale(FacesContext context) {
434: Locale locale = null;
435: UIViewRoot viewRoot = context.getViewRoot();
436: if (viewRoot != null)
437: locale = viewRoot.getLocale();
438: if (locale == null)
439: locale = Locale.getDefault();
440: return locale;
441: }
442:
443: /** Return the form ID of the form containing the given component */
444: public static String getFormId(FacesContext context,
445: UIComponent component) {
446: while (component != null && !(component instanceof UIForm)) {
447: component = component.getParent();
448: }
449: if (component instanceof UIForm)
450: return ((UIForm) component).getId();
451: return null;
452: }
453:
454: }
|