1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.custom.focus2;
20
21 import java.io.IOException;
22 import java.util.Iterator;
23 import java.util.Map;
24
25 import javax.faces.component.ContextCallback;
26 import javax.faces.component.EditableValueHolder;
27 import javax.faces.component.UIComponent;
28 import javax.faces.component.UIForm;
29 import javax.faces.context.FacesContext;
30 import javax.faces.context.ResponseWriter;
31 import javax.faces.render.Renderer;
32
33 import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
34
35
36
37
38
39
40
41
42 public class HtmlFocusRenderer extends Renderer
43 {
44
45 protected void setSubmittedValue(UIComponent component, Object value)
46 {
47 ((EditableValueHolder) component).setSubmittedValue(value);
48 }
49
50 public void decode(FacesContext context, UIComponent component)
51 {
52 super.decode(context, component);
53 RendererUtils.checkParamValidity(context, component, HtmlFocus.class);
54 HtmlFocus focus = (HtmlFocus) component;
55 focus.setSubmittedValue(getCurrentFocusedClientId(context, component));
56 }
57
58 private Object getCurrentFocusedClientId(FacesContext context, UIComponent component)
59 {
60 Map paramMap = context.getExternalContext().getRequestParameterMap();
61 String clientId = component.getClientId(context);
62 return paramMap.get(clientId);
63 }
64
65 public void encodeEnd(FacesContext context, UIComponent component)
66 throws IOException
67 {
68 HtmlFocus focus = (HtmlFocus) component;
69
70 String focusForId = getFocusForId(context, focus);
71
72 ResponseWriter writer = context.getResponseWriter();
73
74 writeForElementStore(context, component, focusForId);
75
76 startScript(component, writer);
77 if (focusForId != null && focusForId.length() > 0)
78 {
79 writeSetFocusScript(component, focusForId, writer);
80 }
81 String focusAndSubmitOnEnter = focus.getFocusAndSubmitOnEnter();
82 if (focusAndSubmitOnEnter != null && focusAndSubmitOnEnter.length() > 0)
83 {
84 UIComponent targetComponent = focus
85 .findComponent(focusAndSubmitOnEnter);
86 if (targetComponent == null)
87 throw new IllegalStateException("Button component for id :"
88 + focusAndSubmitOnEnter + " not found.");
89 writeSetDefaultButtonScript(component, targetComponent
90 .getClientId(context), context);
91 }
92 writeUpdateFocusScript(context, component);
93 endScript(writer);
94
95 }
96
97 private void writeUpdateFocusScript(FacesContext context,
98 UIComponent component) throws IOException
99 {
100
101 UIComponent formParent = getFormParent(component);
102
103 if (formParent == null)
104 throw new IllegalStateException("parent form for component: "
105 + component.getClientId(context) + " not found. ");
106
107 String compClientId = component.getClientId(context);
108 String formParentClientId = formParent.getClientId(context);
109
110 StringBuilder b = new StringBuilder();
111
112 b.append("\nfunction csDomTrackActiveElement(evt) {\n");
113 b.append(" if (evt && evt.target) { \n");
114 b.append(" if (evt.target == document) {\n");
115 b.append(" document.activeElement = null;\n");
116 b.append(" } else {\n");
117 b.append(" if (evt.target.type != 'submit') {\n");
118 b.append(" document.activeElement = evt.target; ;\n");
119 b.append(" }\n");
120 b.append(" }\n");
121 b.append(" }\n");
122 b.append("}\n");
123 b.append("if (document.addEventListener) { \n");
124 b
125 .append("document.addEventListener('focus',csDomTrackActiveElement,true);\n");
126 b.append("}\n");
127 b.append(" var csFocusParentForm =document.getElementById(\"").append(
128 formParentClientId).append("\");\n");
129 b
130 .append(" csFocusParentForm.csFocusSubmitSaver =csFocusParentForm.submit;\n");
131 b
132 .append(" csFocusParentForm.csFocusOnsubmitSaver =csFocusParentForm.onsubmit;\n");
133
134 b.append(" csFocusParentForm.submit=function() {\n");
135 transferId(compClientId, b);
136 b.append(" if(csFocusParentForm.csFocusSubmitSaver) ");
137 b.append(" return csFocusParentForm.csFocusSubmitSaver();\n");
138 b.append(" }\n");
139 b.append(" csFocusParentForm.onsubmit=function() {\n");
140 transferId(compClientId, b);
141 b.append(" if(csFocusParentForm.csFocusOnsubmitSaver) ");
142 b.append(" return csFocusParentForm.csFocusOnsubmitSaver();\n");
143 b.append(" }\n");
144
145 context.getResponseWriter().write(b.toString());
146 }
147
148 private void transferId(String compClientId, StringBuilder b)
149 {
150 b.append(" if(document.activeElement) {\n");
151 b
152 .append("document.getElementById(\"")
153 .append(compClientId)
154 .append(
155 "\").value=document.activeElement.id?document.activeElement.id:document.activeElement.name;\n");
156 b.append(" }\n");
157 }
158
159 private UIComponent getFormParent(UIComponent component)
160 {
161 UIComponent parent = component;
162
163 while (parent != null && !(parent instanceof UIForm))
164 {
165 parent = parent.getParent();
166 }
167
168 return parent;
169 }
170
171 private void writeForElementStore(FacesContext context,
172 UIComponent component, String currentFocusClientId)
173 throws IOException
174 {
175 ResponseWriter writer = context.getResponseWriter();
176 String clientId = component.getClientId(context);
177 writer.startElement("input", component);
178 writer.writeAttribute("type", "hidden", "type");
179 writer.writeAttribute("name", clientId, "clientId");
180 writer.writeAttribute("id", clientId, "clientId");
181 writer.writeAttribute("value", currentFocusClientId, "defaultFocusId");
182 writer.endElement("input");
183 }
184
185 private void writeSetFocusScript(UIComponent component, String clientId,
186 ResponseWriter writer) throws IOException
187 {
188 writer.writeText("setTimeout(\"document.getElementById('" + clientId
189 + "').focus()\", 100);", null);
190 }
191
192 private void writeSetDefaultButtonScript(UIComponent component,
193 String clientId, FacesContext context) throws IOException
194 {
195
196 String formClientId = getFormParent(component).getClientId(context);
197
198 StringBuilder b = new StringBuilder(3000);
199
200 b.append(" var csFocusKeyParentForm =document.getElementById(\"")
201 .append(formClientId).append("\");\n");
202 b
203 .append("\n\ncsFocusKeyParentForm.csFocusOnkeypressSaver =csFocusKeyParentForm.onkeypress;\n");
204
205 b.append("csFocusKeyParentForm.onkeypress=function(evt) {\n");
206 b.append(" var retValue = csSubmitOnEnter(evt,'" + formClientId
207 + "','" + clientId + "'); \n");
208 b.append(" if(csFocusKeyParentForm.csFocusOnkeypressSaver) {\n");
209 b
210 .append(" retValue =csFocusKeyParentForm.csFocusOnkeypressSaver(evt) && retValue;\n");
211 b.append(" }\n");
212 b.append(" return retValue;\n");
213 b.append("}\n");
214 b.append("\n");
215
216 b.append("function csGetKC(evt)\n");
217 b.append("{\n");
218 b.append("if(window.event)\n");
219 b.append(" return window.event.keyCode;\n");
220 b.append(" else if(evt)\n");
221 b.append(" return evt.which;\n");
222 b.append(" return -1;\n");
223 b.append("}\n\n");
224
225 b.append("function csSubmitOnEnter(evt,formId,buttonId)\n");
226 b.append("{\n");
227 b.append(" if(window.event!=(void 0))\n");
228 b.append(" evt=window.event;\n");
229 b.append(" var fromElement;\n");
230 b.append(" if(evt.srcElement==undefined)\n");
231 b.append(" fromElement=evt.target;\n");
232 b.append(" else\n");
233 b.append(" fromElement=evt.srcElement;\n");
234 b.append(" if(!fromElement) return true;\n");
235 b.append(" if(fromElement.tagName.toUpperCase()=='A') return true;\n");
236 b.append(" if((fromElement.tagName.toUpperCase()=='INPUT')&&\n");
237 b.append(" (fromElement.type!='submit')&&\n");
238 b.append(" (fromElement.type!='reset'))\n");
239 b.append(" {\n");
240 b.append(" if(csGetKC(evt)==13)\n");
241 b.append(" {\n");
242 b.append(" if(buttonId!=(void 0))\n");
243 b.append(" {\n");
244 b.append(" document.getElementById(buttonId).click();\n");
245 b.append(" }\n");
246 b.append(" return false;\n");
247 b.append(" }\n");
248 b.append(" }\n");
249 b.append(" return true;\n");
250 b.append("}\n");
251
252 context.getResponseWriter().writeText(b.toString(), null);
253 }
254
255 private void endScript(ResponseWriter writer) throws IOException
256 {
257 writer.writeText("/*]]>*/", null);
258 writer.endElement("script");
259 }
260
261 private void startScript(UIComponent component, ResponseWriter writer)
262 throws IOException
263 {
264 writer.startElement("script", component);
265 writer.writeAttribute("type", "text/javascript", null);
266 writer.writeText("/*<![CDATA[*/", null);
267 }
268
269
270
271
272
273
274
275 private String getFocusForId(FacesContext context, HtmlFocus focus)
276 {
277
278
279 String forId = focus.getOverrideFocusId();
280 if (forId != null && forId.length() > 0)
281 {
282 UIComponent targetComponent = focus.findComponent(forId);
283
284 if (targetComponent == null)
285 {
286 throw new IllegalStateException("target-component for id :"
287 + forId + " not found.");
288 }
289 return targetComponent.getClientId(context);
290 }
291
292
293 if (focus.isFocusOnError())
294 {
295 Iterator it = context.getMessages();
296 Iterator msgs = context.getClientIdsWithMessages();
297 if (msgs.hasNext())
298 {
299 String clientId = (String) msgs.next();
300 return clientId;
301 }
302 }
303
304
305 String clientId = (String) focus.getValue();
306 if (clientId != null && clientId.length() > 0)
307 {
308 boolean isPostBack = context.getRenderKit().getResponseStateManager().isPostback(context);
309 if(isPostBack)
310 {
311 final StringHolder nextClientId = new StringHolder();
312 context.getViewRoot().invokeOnComponent(context, clientId,
313 new ContextCallback()
314 {
315
316 public void invokeContextCallback(FacesContext context,
317 UIComponent target)
318 {
319 String nextClientIdString = getNextValueHolder(
320 context, target);
321 if (nextClientIdString != null)
322 nextClientId.string = nextClientIdString;
323 }
324 });
325
326 if (nextClientId.string != null && nextClientId.string.length() > 0)
327 return nextClientId.string;
328 }
329 return clientId;
330 }
331
332
333 if (focus.isFocusOnFirst())
334 {
335 UIComponent comp = getFormParent(focus);
336 String firstClientId = getNextValueHolder(context, comp);
337 if (firstClientId != null)
338 return firstClientId;
339 }
340
341 return clientId;
342 }
343
344 private static class StringHolder
345 {
346 public String string;
347 }
348
349 private static String getNextValueHolder(FacesContext context,
350 UIComponent comp)
351 {
352
353 final StringHolder holder = new StringHolder();
354
355 TreeVisitor.traverseTree(context,
356 new TreeVisitor.TreeTraversalListener()
357 {
358
359 private int count = 0;
360
361 public boolean traverse(FacesContext context, int level,
362 UIComponent component)
363 {
364 if (count > 0)
365 {
366 if (!(component instanceof HtmlFocus)
367 && (component instanceof EditableValueHolder && component.isRendered())
368
369 )
370 {
371 holder.string = component.getClientId(context);
372 return false;
373 }
374 }
375
376 count++;
377 return true;
378 }
379
380 private boolean isVisible(UIComponent component)
381 {
382
383
384
385
386
387 return true;
388 }
389 }, comp);
390
391 return holder.string;
392 }
393
394 }