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.renderkit.dom_html_basic;
035:
036: import com.icesoft.faces.context.DOMContext;
037: import com.icesoft.faces.context.effects.CurrentStyle;
038: import com.icesoft.faces.context.effects.LocalEffectEncoder;
039: import org.w3c.dom.Element;
040:
041: import javax.faces.FacesException;
042: import javax.faces.component.UIComponent;
043: import javax.faces.component.html.HtmlSelectManyCheckbox;
044: import javax.faces.context.FacesContext;
045: import java.util.ArrayList;
046: import java.util.Arrays;
047: import java.util.Iterator;
048: import java.util.List;
049: import java.util.Map;
050:
051: /**
052: * This class is responsible for the rendering of html pass thru attributes.
053: */
054: public class PassThruAttributeRenderer {
055:
056: private static List passThruAttributeNames = new ArrayList();
057: private static List booleanPassThruAttributeNames = new ArrayList();
058:
059: static {
060: passThruAttributeNames.add("accept");
061: passThruAttributeNames.add("accesskey");
062: passThruAttributeNames.add("alt");
063: passThruAttributeNames.add("bgcolor");
064: passThruAttributeNames.add("border");
065: passThruAttributeNames.add("cellpadding");
066: passThruAttributeNames.add("cellspacing");
067: passThruAttributeNames.add("charset");
068: passThruAttributeNames.add("cols");
069: passThruAttributeNames.add("coords");
070: passThruAttributeNames.add("dir");
071: passThruAttributeNames.add("enctype");
072: passThruAttributeNames.add("frame");
073: passThruAttributeNames.add("height");
074: passThruAttributeNames.add("hreflang");
075: passThruAttributeNames.add("lang");
076: passThruAttributeNames.add("longdesc");
077: passThruAttributeNames.add("maxlength");
078: passThruAttributeNames.add("onblur");
079: passThruAttributeNames.add("onchange");
080: passThruAttributeNames.add("onclick");
081: passThruAttributeNames.add("ondblclick");
082: passThruAttributeNames.add("onfocus");
083: passThruAttributeNames.add("onkeydown");
084: passThruAttributeNames.add("onkeypress");
085: passThruAttributeNames.add("onkeyup");
086: passThruAttributeNames.add("onload");
087: passThruAttributeNames.add("onmousedown");
088: passThruAttributeNames.add("onmousemove");
089: passThruAttributeNames.add("onmouseout");
090: passThruAttributeNames.add("onmouseover");
091: passThruAttributeNames.add("onmouseup");
092: passThruAttributeNames.add("onreset");
093: passThruAttributeNames.add("onselect");
094: passThruAttributeNames.add("onsubmit");
095: passThruAttributeNames.add("onunload");
096: passThruAttributeNames.add("rel");
097: passThruAttributeNames.add("rev");
098: passThruAttributeNames.add("rows");
099: passThruAttributeNames.add("rules");
100: passThruAttributeNames.add("shape");
101: passThruAttributeNames.add("size");
102: passThruAttributeNames.add("style");
103: passThruAttributeNames.add("summary");
104: passThruAttributeNames.add("tabindex");
105: passThruAttributeNames.add("target");
106: passThruAttributeNames.add("title");
107: passThruAttributeNames.add("usemap");
108: passThruAttributeNames.add("width");
109: passThruAttributeNames.add("width");
110: passThruAttributeNames.add("onclickeffect");
111: passThruAttributeNames.add("ondblclickeffect");
112: passThruAttributeNames.add("onmousedowneffect");
113: passThruAttributeNames.add("onmouseupeffect");
114: passThruAttributeNames.add("onmousemoveeffect");
115: passThruAttributeNames.add("onmouseovereffect");
116: passThruAttributeNames.add("onmouseouteffect");
117: passThruAttributeNames.add("onchangeeffect");
118: passThruAttributeNames.add("onreseteffect");
119: passThruAttributeNames.add("onsubmiteffect");
120: passThruAttributeNames.add("onkeypresseffect");
121: passThruAttributeNames.add("onkeydowneffect");
122: passThruAttributeNames.add("onkeyupeffect");
123: passThruAttributeNames.add("autocomplete");
124:
125: booleanPassThruAttributeNames.add("disabled");
126: booleanPassThruAttributeNames.add("readonly");
127: booleanPassThruAttributeNames.add("ismap");
128: }
129:
130: /**
131: * Render pass thru attributes to the root element of the DOMContext
132: * associated with the UIComponent parameter. The excludedAttributes
133: * argument is a String array of the names of attributes to omit. Do not
134: * render attributes contained in the excludedAttributes argument.
135: *
136: * @param facesContext
137: * @param uiComponent
138: * @param excludedAttributes attributes to exclude
139: */
140: public static void renderAttributes(FacesContext facesContext,
141: UIComponent uiComponent, String[] excludedAttributes) {
142: renderAttributes(facesContext, uiComponent, null, null,
143: excludedAttributes);
144: }
145:
146: /**
147: * Render pass thru attributes to the attributeElement (instead of root)
148: * associated with the UIComponent parameter. The excludedAttributes
149: * argument is a String array of the names of attributes to omit. Do not
150: * render attributes contained in the excludedAttributes argument.
151: *
152: * @param facesContext
153: * @param uiComponent
154: * @param attributeElement
155: * @param styleElement The Element to apply styling on
156: * @param excludedAttributes attributes to exclude
157: */
158: public static void renderAttributes(FacesContext facesContext,
159: UIComponent uiComponent, Element attributeElement,
160: Element styleElement, String[] excludedAttributes) {
161: renderNonBooleanAttributes(facesContext, uiComponent,
162: attributeElement, excludedAttributes);
163: renderBooleanAttributes(facesContext, uiComponent,
164: attributeElement, excludedAttributes);
165: CurrentStyle.apply(facesContext, uiComponent, styleElement,
166: null);
167:
168: if (attributeElement == null) {
169: DOMContext domContext = DOMContext.getDOMContext(
170: facesContext, uiComponent);
171: Element rootElement = (Element) domContext.getRootNode();
172: attributeElement = rootElement;
173: }
174: LocalEffectEncoder.encodeLocalEffects(uiComponent,
175: attributeElement, facesContext);
176: renderOnFocus(uiComponent, attributeElement);
177: renderOnBlur(attributeElement);
178: }
179:
180: /**
181: * Render the icefaces onfocus handler to the root element. This should be
182: * restricted to input type elements and commandlinks.
183: *
184: * @param uiComponent
185: * @param root
186: */
187: public static void renderOnFocus(UIComponent uiComponent,
188: Element root) {
189: // check the type of the root node
190: String nodeName = root.getNodeName();
191:
192: if (nodeName.equalsIgnoreCase(HTML.ANCHOR_ELEM)
193: || nodeName.equalsIgnoreCase(HTML.INPUT_ELEM)
194: || nodeName.equalsIgnoreCase(HTML.SELECT_ELEM)) {
195: String original = (String) uiComponent.getAttributes().get(
196: "onfocus");
197: String onfocus = "setFocus(this.id);";
198:
199: if (original == null) {
200: original = "";
201: }
202: root.setAttribute(HTML.ONFOCUS_ATTR, onfocus + original);
203: }
204: }
205:
206: /**
207: * Render the icefaces onblur handler to the root element. This should be
208: * restricted to input type elements and commandlinks.
209: *
210: * @param root
211: */
212: public static void renderOnBlur(Element root) {
213: // check the type of the root node
214: // onblur will clear focus id
215: String nodeName = root.getNodeName();
216:
217: if (nodeName.equalsIgnoreCase(HTML.ANCHOR_ELEM)
218: || nodeName.equalsIgnoreCase(HTML.INPUT_ELEM)
219: || nodeName.equalsIgnoreCase(HTML.SELECT_ELEM)) {
220: String original = root.getAttribute("onblur");
221: String onblur = "setFocus('');";
222:
223: if (original == null) {
224: original = "";
225: }
226: root.setAttribute(HTML.ONBLUR_ATTR, onblur + original);
227: }
228: }
229:
230: private static void renderBooleanAttributes(
231: FacesContext facesContext, UIComponent uiComponent,
232: Element targetElement, String[] excludedAttributes) {
233:
234: if (facesContext == null) {
235: throw new FacesException("Null pointer exception");
236: }
237: if (uiComponent == null) {
238: throw new FacesException("Null pointer exception");
239: }
240:
241: if (targetElement == null) {
242: DOMContext domContext = DOMContext.getDOMContext(
243: facesContext, uiComponent);
244: Element rootElement = (Element) domContext.getRootNode();
245: if (rootElement == null) {
246: throw new FacesException("DOMContext is null");
247: }
248: targetElement = rootElement;
249: }
250:
251: List excludedAttributesList = null;
252: if (excludedAttributes != null && excludedAttributes.length > 0) {
253: excludedAttributesList = Arrays.asList(excludedAttributes);
254: }
255:
256: Object nextPassThruAttributeName;
257: Object nextPassThruAttributeValue = null;
258: Iterator passThruNameIterator = booleanPassThruAttributeNames
259: .iterator();
260: boolean primitiveAttributeValue;
261:
262: while (passThruNameIterator.hasNext()) {
263: nextPassThruAttributeName = (passThruNameIterator.next());
264: if (excludedAttributesList != null) {
265: if (excludedAttributesList
266: .contains(nextPassThruAttributeName)) {
267: continue;
268: }
269: }
270: nextPassThruAttributeValue = uiComponent.getAttributes()
271: .get(nextPassThruAttributeName);
272: if (nextPassThruAttributeValue != null) {
273: if (nextPassThruAttributeValue instanceof Boolean) {
274: primitiveAttributeValue = ((Boolean) nextPassThruAttributeValue)
275: .booleanValue();
276: } else {
277: if (!(nextPassThruAttributeValue instanceof String)) {
278: nextPassThruAttributeValue = nextPassThruAttributeValue
279: .toString();
280: }
281: primitiveAttributeValue = (new Boolean(
282: (String) nextPassThruAttributeValue))
283: .booleanValue();
284: }
285: if (primitiveAttributeValue) {
286: targetElement.setAttribute(
287: nextPassThruAttributeName.toString(),
288: nextPassThruAttributeName.toString());
289: } else {
290: targetElement
291: .removeAttribute(nextPassThruAttributeName
292: .toString());
293: }
294:
295: } else {
296: targetElement.removeAttribute(nextPassThruAttributeName
297: .toString());
298: }
299: }
300: }
301:
302: private static void renderNonBooleanAttributes(
303: FacesContext facesContext, UIComponent uiComponent,
304: Element targetElement, String[] excludedAttributes) {
305:
306: if (uiComponent == null) {
307: throw new FacesException("Component instance is null");
308: }
309:
310: if (targetElement == null) {
311: DOMContext domContext = DOMContext.getDOMContext(
312: facesContext, uiComponent);
313:
314: Element rootElement = (Element) domContext.getRootNode();
315: if (rootElement == null) {
316: throw new FacesException(
317: "DOMContext is not initialized");
318: }
319: targetElement = rootElement;
320: }
321:
322: List excludedAttributesList = null;
323: if (excludedAttributes != null && excludedAttributes.length > 0) {
324: excludedAttributesList = Arrays.asList(excludedAttributes);
325: }
326:
327: Object nextPassThruAttributeName = null;
328: Object nextPassThruAttributeValue = null;
329: Iterator passThruNameIterator = passThruAttributeNames
330: .iterator();
331: while (passThruNameIterator.hasNext()) {
332: nextPassThruAttributeName = (passThruNameIterator.next());
333: if (excludedAttributesList != null) {
334: if (excludedAttributesList
335: .contains(nextPassThruAttributeName)) {
336: continue;
337: }
338: }
339: nextPassThruAttributeValue = uiComponent.getAttributes()
340: .get(nextPassThruAttributeName);
341: // Only render non-null attributes.
342: // Some components have attribute values
343: // set to the Wrapper classes' minimum value - don't render
344: // an attribute with this sentinel value.
345: if (nextPassThruAttributeValue != null
346: && !attributeValueIsSentinel(nextPassThruAttributeValue)) {
347: targetElement.setAttribute(nextPassThruAttributeName
348: .toString(), nextPassThruAttributeValue
349: .toString());
350: } else {
351: targetElement.removeAttribute(nextPassThruAttributeName
352: .toString());
353: }
354: }
355: }
356:
357: /**
358: * Determine whether any of the attributes defined for the UIComponent
359: * instance are pass thru attributes.
360: *
361: * @param uiComponent
362: * @return true if the UIComponent parameter has one or more attributes
363: * defined that are pass thru attributes
364: */
365: public static boolean passThruAttributeExists(
366: UIComponent uiComponent) {
367: if (uiComponent == null) {
368: return false;
369: }
370: Map componentAttributes = uiComponent.getAttributes();
371: if (componentAttributes.size() <= 0) {
372: return false;
373: }
374: if (componentAttributesIncludePassThruAttribute(
375: componentAttributes, passThruAttributeNames)) {
376: return true;
377: }
378: if (componentAttributesIncludePassThruAttribute(
379: componentAttributes, booleanPassThruAttributeNames)) {
380: return true;
381: }
382: return false;
383: }
384:
385: private static boolean attributeValueIsSentinel(Object value) {
386: if (value == null) {
387: return false;
388: }
389: if (value instanceof Boolean) {
390: if (((Boolean) value).booleanValue() == false) {
391: return true;
392: }
393: return false;
394: }
395: if (value instanceof Number) {
396: if (value instanceof Integer) {
397: if (((Integer) value).intValue() == Integer.MIN_VALUE) {
398: return true;
399: }
400: return false;
401: }
402: if (value instanceof Long) {
403: if (((Long) value).longValue() == Long.MIN_VALUE) {
404: return true;
405: }
406: return false;
407: }
408: if (value instanceof Short) {
409: if (((Short) value).shortValue() == Short.MIN_VALUE) {
410: return true;
411: }
412: return false;
413: }
414: if (value instanceof Float) {
415: if (((Float) value).floatValue() == Float.MIN_VALUE) {
416: return true;
417: }
418: return false;
419: }
420: if (value instanceof Double) {
421: if (((Double) value).doubleValue() == Double.MIN_VALUE) {
422: return true;
423: }
424: return false;
425: }
426: if (value instanceof Byte) {
427: if (((Byte) value).byteValue() == Byte.MIN_VALUE) {
428: return true;
429: }
430: return false;
431: }
432: }
433: if (value instanceof Character) {
434: if (((Character) value).charValue() == Character.MIN_VALUE) {
435: return true;
436: }
437: return false;
438: }
439: return false;
440: }
441:
442: private static boolean componentAttributesIncludePassThruAttribute(
443: Map componentAttributes, List passThru) {
444: Object componentAttributeKey;
445: Object componentAttributeValue;
446: Iterator attributeKeys = componentAttributes.keySet()
447: .iterator();
448: while (attributeKeys.hasNext()) {
449: componentAttributeKey = attributeKeys.next();
450: if (passThru.contains(componentAttributeKey)) {
451: componentAttributeValue = componentAttributes
452: .get(componentAttributeKey);
453: if ((componentAttributeValue != null)
454: && (componentAttributeValue != "")) {
455: return true;
456: }
457: }
458: }
459: return false;
460: }
461:
462: static final List getpassThruAttributeNames() {
463: return passThruAttributeNames;
464: }
465: }
|