1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.custom.navmenu.htmlnavmenu;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.apache.myfaces.custom.navmenu.NavigationMenuItem;
24 import org.apache.myfaces.custom.navmenu.NavigationMenuUtils;
25 import org.apache.myfaces.custom.navmenu.UINavigationMenuItem;
26 import org.apache.myfaces.renderkit.html.ext.HtmlLinkRenderer;
27 import org.apache.myfaces.renderkit.html.util.AddResource;
28 import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
29 import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
30 import org.apache.myfaces.shared_tomahawk.renderkit.html.HTML;
31 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
32
33 import javax.faces.component.*;
34 import javax.faces.context.FacesContext;
35 import javax.faces.context.ResponseWriter;
36 import javax.faces.event.ActionListener;
37 import javax.faces.el.ValueBinding;
38 import java.io.IOException;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.List;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60 public class HtmlNavigationMenuRenderer extends HtmlLinkRenderer {
61 private static final Log log = LogFactory.getLog(HtmlNavigationMenuRenderer.class);
62
63 public static final String RENDERER_TYPE = "org.apache.myfaces.NavigationMenu";
64
65 private static final Integer ZERO_INTEGER = new Integer(0);
66
67 private static final String HORIZ_MENU_SCRIPT = "HMenuIEHover.js";
68
69 public boolean getRendersChildren() {
70 return true;
71 }
72
73 public void decode(FacesContext facesContext, UIComponent component) {
74 if (component instanceof HtmlCommandNavigationItem) {
75
76 super.decode(facesContext, component);
77 }
78 }
79
80 public void encodeBegin(FacesContext facesContext, UIComponent component) throws IOException {
81 if (component instanceof HtmlCommandNavigationItem) {
82
83 super.encodeBegin(facesContext, component);
84 }
85 }
86
87 public void encodeChildren(FacesContext facesContext, UIComponent component) throws IOException {
88 if (component instanceof HtmlCommandNavigationItem) {
89
90 super.encodeChildren(facesContext, component);
91 }
92 }
93
94 public void encodeEnd(FacesContext facesContext, UIComponent component) throws IOException {
95 if (component instanceof HtmlCommandNavigationItem) {
96
97 super.encodeEnd(facesContext, component);
98 return;
99 }
100 RendererUtils.checkParamValidity(facesContext, component, HtmlPanelNavigationMenu.class);
101 HtmlPanelNavigationMenu panelNav = (HtmlPanelNavigationMenu) component;
102
103 if (HtmlNavigationMenuRendererUtils.isListLayout(panelNav)) {
104 boolean preprocess = true;
105 boolean clientStateSaving = facesContext.getApplication().getStateManager().isSavingStateInClient(facesContext);
106 if (clientStateSaving) {
107
108 HtmlPanelNavigationMenu panelNavPrev = findPreviousPanelNav(facesContext, panelNav);
109 if (panelNavPrev != null) {
110 preprocess = false;
111 if (!panelNavPrev.equals(panelNav)) {
112
113 UIComponent parent = panelNav.getParent();
114 int insertPos = parent.getChildren().indexOf(panelNav);
115 parent.getChildren().set(insertPos, panelNavPrev);
116 panelNavPrev.setParent(parent);
117 panelNav.setParent(null);
118 panelNav = panelNavPrev;
119 }
120 }
121 }
122 else {
123
124 if (panelNav.getPreprocessed() != null && panelNav.getPreprocessed().booleanValue())
125 preprocess = false;
126 }
127 if (preprocess) {
128 panelNav.setPreprocessed(Boolean.TRUE);
129 preprocessNavigationItems(facesContext, panelNav, panelNav.getChildren(), new UniqueId());
130 if (!clientStateSaving) {
131 HtmlPanelNavigationMenu panelNavPrev = findPreviousPanelNav(facesContext, panelNav);
132 if (panelNavPrev != null) {
133 restoreOpenActiveStates(facesContext, panelNav, panelNavPrev.getChildren());
134 }
135 }
136 }
137
138 if (log.isDebugEnabled())
139 HtmlNavigationMenuRendererUtils.debugTree(log, facesContext, panelNav.getChildren(), 0);
140 renderListLayout(facesContext, panelNav);
141 }
142 else {
143 renderTableLayout(facesContext, panelNav);
144 }
145 }
146
147 private void restoreOpenActiveStates(FacesContext facesContext,
148 HtmlPanelNavigationMenu panelNav, List children) {
149 for (int i = 0, size = children.size(); i < size; i++) {
150 UIComponent uiComponent = (UIComponent) children.get(i);
151 if (uiComponent instanceof HtmlCommandNavigationItem) {
152 HtmlCommandNavigationItem prevItem = (HtmlCommandNavigationItem) uiComponent;
153 if (prevItem.isOpen() || prevItem.isActive()) {
154 HtmlCommandNavigationItem item = (HtmlCommandNavigationItem) panelNav.findComponent(uiComponent.getClientId(facesContext));
155 if (item != null) {
156 if (item.getActiveDirectly() != null && item.getActiveDirectly().booleanValue()) {
157 item.setActive(prevItem.isActive());
158 }
159 else {
160 copyValueBinding(prevItem, item, "active");
161 }
162
163 if (item.getOpenDirectly() != null && item.getOpenDirectly().booleanValue()) {
164 item.setOpen(prevItem.isOpen());
165 }
166 else {
167 copyValueBinding(prevItem, item, "open");
168 }
169 if (!panelNav.isExpandAll() || prevItem.isActive())
170 item.toggleOpen();
171 if (prevItem.isOpen())
172 restoreOpenActiveStates(facesContext, panelNav, prevItem.getChildren());
173 }
174 }
175 }
176 }
177 }
178
179 private HtmlPanelNavigationMenu findPreviousPanelNav(FacesContext facesContext, HtmlPanelNavigationMenu panelNav) {
180 UIViewRoot previousViewRoot = findPreviousRoot(facesContext);
181 if (previousViewRoot != null) {
182 return (HtmlPanelNavigationMenu) previousViewRoot.findComponent(panelNav.getClientId(facesContext));
183 }
184 return null;
185 }
186
187 private UIViewRoot findPreviousRoot(FacesContext facesContext) {
188 return (UIViewRoot) facesContext.getExternalContext().getRequestMap().get(HtmlPanelNavigationMenu.PREVIOUS_VIEW_ROOT);
189 }
190
191 protected void renderListLayout(FacesContext facesContext, HtmlPanelNavigationMenu panelNav) throws IOException {
192 if (panelNav.isRenderAll())
193 addResourcesToHeader(facesContext);
194
195 ResponseWriter writer = facesContext.getResponseWriter();
196 if (panelNav.getChildCount() > 0) {
197 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
198 writer.startElement(HTML.UL_ELEM, panelNav);
199
200 HtmlRendererUtils.writeIdIfNecessary(writer, panelNav, facesContext);
201
202 HtmlRendererUtils.renderHTMLAttributes(writer, panelNav, HTML.UL_PASSTHROUGH_ATTRIBUTES);
203
204
205 activeOnViewId(panelNav, facesContext.getViewRoot().getViewId());
206
207 if (panelNav.isExpandAll()) {
208 expandAll(panelNav);
209 }
210
211 HtmlNavigationMenuRendererUtils.renderChildrenListLayout(facesContext, writer, panelNav, panelNav.getChildren(), 0);
212
213 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
214 writer.endElement(HTML.UL_ELEM);
215 }
216 else {
217 if (log.isWarnEnabled()) log.warn("PanelNavaigationMenu without children.");
218 }
219 }
220
221 private void renderTableLayout(FacesContext facesContext, HtmlPanelNavigationMenu panelNav) throws IOException {
222 ResponseWriter writer = facesContext.getResponseWriter();
223
224 if (panelNav.getChildCount() > 0) {
225 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
226 writer.startElement(HTML.TABLE_ELEM, panelNav);
227
228 HtmlRendererUtils.writeIdIfNecessary(writer, panelNav, facesContext);
229
230 HtmlRendererUtils.renderHTMLAttributes(writer, panelNav, HTML.TABLE_PASSTHROUGH_ATTRIBUTES);
231 if (panelNav.getStyle() == null && panelNav.getStyleClass() == null) {
232 writer.writeAttribute(HTML.BORDER_ATTR, ZERO_INTEGER, null);
233 }
234
235 HtmlNavigationMenuRendererUtils.renderChildrenTableLayout(facesContext, writer, panelNav, panelNav.getChildren(), 0);
236
237 HtmlRendererUtils.writePrettyLineSeparator(facesContext);
238 writer.endElement(HTML.TABLE_ELEM);
239 }
240 else {
241 if (log.isWarnEnabled()) log.warn("PanelNavaigationMenu without children.");
242 }
243 }
244
245 private void addResourcesToHeader(FacesContext context) {
246 AddResource addResource = AddResourceFactory.getInstance(context);
247 addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN, HtmlPanelNavigationMenu.class, HORIZ_MENU_SCRIPT);
248 }
249
250
251
252
253 private void preprocessNavigationItems(FacesContext facesContext, UIComponent parent,
254 List children, UniqueId uniqueId) {
255 for (int i = 0; i < children.size(); i++) {
256 UIComponent child = (UIComponent) children.get(i);
257
258 if (child instanceof HtmlCommandNavigationItem) {
259 HtmlCommandNavigationItem navMenuItem = (HtmlCommandNavigationItem) child;
260 preprocessNavigationItems(facesContext, navMenuItem, navMenuItem.getChildren(), uniqueId);
261 }
262 else if (child instanceof UINavigationMenuItem) {
263 UINavigationMenuItem uiNavMenuItem = (UINavigationMenuItem) child;
264 createHtmlCommandNavigationItem(facesContext, parent, i, uiNavMenuItem, uniqueId);
265 }
266 else if (child instanceof UISelectItems) {
267 List list = new ArrayList();
268 if (child.getId() == null) {
269 child.setId("testit");
270 }
271 NavigationMenuUtils.addNavigationMenuItems((UISelectItems) child, list);
272 addUINavigationMenuItems(facesContext, parent, children, i + 1, list);
273 }
274 }
275 }
276
277 private void addUINavigationMenuItems(FacesContext facesContext, UIComponent parent, List children, int startIndex, List menuItems) {
278 String clientId = parent.getClientId(facesContext);
279 clientId = clientId.replaceAll(":", "_");
280 for (int j = 0, sizej = menuItems.size(); j < sizej; j++) {
281 NavigationMenuItem navigationMenuItem = (NavigationMenuItem) menuItems.get(j);
282 UINavigationMenuItem uiNavigationMenuItem =
283 (UINavigationMenuItem) facesContext.getApplication().createComponent(UINavigationMenuItem.COMPONENT_TYPE);
284 uiNavigationMenuItem.setId(clientId + "_uinavmitem" + (startIndex + j));
285 uiNavigationMenuItem.getClientId(facesContext);
286 children.add(startIndex++, uiNavigationMenuItem);
287 uiNavigationMenuItem.setParent(parent);
288 if (navigationMenuItem.getAction() != null) {
289 uiNavigationMenuItem.setAction(HtmlNavigationMenuRendererUtils.getMethodBinding(facesContext, navigationMenuItem.getAction(), false));
290 }
291 if (navigationMenuItem.getActionListener() != null) {
292 uiNavigationMenuItem.setActionListener(HtmlNavigationMenuRendererUtils.getMethodBinding(facesContext,
293 navigationMenuItem.getActionListener(), true));
294 }
295 uiNavigationMenuItem.setIcon(navigationMenuItem.getIcon());
296 uiNavigationMenuItem.setRendered(navigationMenuItem.isRendered());
297 uiNavigationMenuItem.setActiveOnViewIds(navigationMenuItem.getActiveOnViewIds());
298 uiNavigationMenuItem.setSplit(navigationMenuItem.isSplit());
299 uiNavigationMenuItem.setItemLabel(navigationMenuItem.getLabel());
300 uiNavigationMenuItem.setOpen(navigationMenuItem.isOpen());
301 uiNavigationMenuItem.setActive(navigationMenuItem.isActive());
302 uiNavigationMenuItem.setValue(navigationMenuItem.getValue());
303 HtmlNavigationMenuRendererUtils.setAttributeValue(facesContext, uiNavigationMenuItem,
304 "externalLink", navigationMenuItem.getExternalLink());
305
306 uiNavigationMenuItem.setTransient(false);
307 uiNavigationMenuItem.setTarget(navigationMenuItem.getTarget());
308 uiNavigationMenuItem.setDisabled(navigationMenuItem.isDisabled());
309 uiNavigationMenuItem.setDisabledStyle(navigationMenuItem.getDisabledStyle());
310 uiNavigationMenuItem.setDisabledStyleClass(navigationMenuItem.getDisabledStyleClass());
311
312 if (navigationMenuItem.getNavigationMenuItems() != null && navigationMenuItem.getNavigationMenuItems().length > 0)
313 {
314 addUINavigationMenuItems(facesContext, uiNavigationMenuItem, uiNavigationMenuItem.getChildren(), 0,
315 Arrays.asList(navigationMenuItem.getNavigationMenuItems()));
316 }
317 }
318 }
319
320 private HtmlPanelNavigationMenu getParentPanelNavigation(UIComponent uiComponent) {
321 if (uiComponent instanceof HtmlPanelNavigationMenu) {
322 return (HtmlPanelNavigationMenu) uiComponent;
323 }
324 UIComponent parent = uiComponent.getParent();
325
326
327 UIComponent p = parent;
328 while (p != null && !(p instanceof HtmlPanelNavigationMenu)) {
329 p = p.getParent();
330 }
331
332 if (p == null) {
333 log.error("HtmlCommandNavigation without parent HtmlPanelNavigation ?!");
334 return null;
335 }
336 return (HtmlPanelNavigationMenu) p;
337 }
338
339 private void createHtmlCommandNavigationItem(FacesContext facesContext, UIComponent parent, int i,
340 UINavigationMenuItem uiNavMenuItem, UniqueId uniqueId) {
341 HtmlPanelNavigationMenu menu = getParentPanelNavigation(parent);
342
343 HtmlCommandNavigationItem newItem = (HtmlCommandNavigationItem)
344 facesContext.getApplication().createComponent(HtmlCommandNavigationItem.COMPONENT_TYPE);
345 String parentId = parent.getClientId(facesContext);
346 parentId = parentId.replaceAll(":", "_");
347 int id = uniqueId.next();
348 newItem.setId(parentId + "_item" + id);
349 newItem.getClientId(facesContext);
350 newItem.setRendererType(RENDERER_TYPE);
351 parent.getChildren().add(i + 1, newItem);
352 newItem.setParent(parent);
353
354 newItem.setAction(uiNavMenuItem.getAction());
355 newItem.setActionListener(uiNavMenuItem.getActionListener());
356 ActionListener[] listeners = uiNavMenuItem.getActionListeners();
357 for (int j = 0; j < listeners.length; j++) {
358 newItem.addActionListener(listeners[j]);
359 }
360
361 newItem.setValue(uiNavMenuItem.getValue());
362
363 if (!copyValueBinding(uiNavMenuItem, newItem, "immediate"))
364 newItem.setImmediate(uiNavMenuItem.isImmediate());
365
366 if (!copyValueBinding(uiNavMenuItem, newItem, "transient"))
367 newItem.setTransient(uiNavMenuItem.isTransient());
368 if (!copyValueBinding(uiNavMenuItem, newItem, "rendered"))
369 newItem.setRendered(uiNavMenuItem.isRendered());
370 if (!copyValueBinding(uiNavMenuItem, newItem, "externalLink"))
371 newItem.setExternalLink(uiNavMenuItem.getExternalLink());
372 if (!copyValueBinding(uiNavMenuItem, newItem, "activeOnViewIds"))
373 newItem.setActiveOnViewIds(uiNavMenuItem.getActiveOnViewIds());
374
375 if (uiNavMenuItem.isOpen() && ! menu.isExpandAll())
376 newItem.toggleOpen();
377
378 if (uiNavMenuItem.getActiveDirectly() != null) {
379 newItem.setActive(uiNavMenuItem.isActive());
380 }
381 else {
382 newItem.setValueBinding("active", uiNavMenuItem.getValueBinding("active"));
383 }
384
385 if (!copyValueBinding(uiNavMenuItem, newItem, "target"))
386 newItem.setTarget(uiNavMenuItem.getTarget());
387 if (!copyValueBinding(uiNavMenuItem, newItem, "disabled"))
388 newItem.setDisabled(uiNavMenuItem.isDisabled());
389 if (!copyValueBinding(uiNavMenuItem, newItem, "disabledStyle"))
390 newItem.setDisabledStyle(uiNavMenuItem.getDisabledStyle());
391 if (!copyValueBinding(uiNavMenuItem, newItem, "disabledStyleClass"))
392 newItem.setDisabledStyleClass(uiNavMenuItem.getDisabledStyleClass());
393
394 if (uiNavMenuItem.getActiveOnViewIdsDirectly() != null) {
395 newItem.setActiveOnViewIds(uiNavMenuItem.getActiveOnViewIdsDirectly());
396 }
397
398
399 if (parent instanceof HtmlPanelNavigationMenu) {
400 if (newItem.getDisabledStyle() == null) {
401 newItem.setDisabledStyle(
402 ((HtmlPanelNavigationMenu) parent).getDisabledStyle()
403 );
404 }
405 if (newItem.getDisabledStyleClass() == null) {
406 newItem.setDisabledStyleClass(
407 ((HtmlPanelNavigationMenu) parent).getDisabledStyleClass()
408 );
409 }
410 if (((HtmlPanelNavigationMenu) parent).isDisabled()) {
411 newItem.setDisabled(true);
412 }
413 }
414 if (parent instanceof HtmlCommandNavigationItem) {
415 if (newItem.getDisabledStyle() == null) {
416 newItem.setDisabledStyle(
417 ((HtmlCommandNavigationItem) parent).getDisabledStyle()
418 );
419 }
420 if (newItem.getDisabledStyleClass() == null) {
421 newItem.setDisabledStyleClass(
422 ((HtmlCommandNavigationItem) parent).getDisabledStyleClass()
423 );
424 }
425 if (((HtmlCommandNavigationItem) parent).isDisabled()) {
426 newItem.setDisabled(true);
427 }
428 }
429
430 if (uiNavMenuItem.getIcon() != null) {
431 UIGraphic uiGraphic = (UIGraphic) facesContext.getApplication().createComponent(UIGraphic.COMPONENT_TYPE);
432 uiGraphic.setId(parentId + "_img" + id);
433 uiGraphic.getClientId(facesContext);
434 newItem.getChildren().add(uiGraphic);
435 uiGraphic.setParent(newItem);
436 if (NavigationMenuUtils.isValueReference(uiNavMenuItem.getIcon())) {
437 uiGraphic.setValueBinding("value",
438 facesContext.getApplication().createValueBinding(uiNavMenuItem.getIcon()));
439 }
440 else {
441 uiGraphic.setValue(uiNavMenuItem.getIcon());
442 }
443 }
444
445 else {
446
447 UIOutput uiOutput = (UIOutput) facesContext.getApplication().createComponent(UIOutput.COMPONENT_TYPE);
448 uiOutput.setId(parentId + "_txt" + id);
449 uiOutput.getClientId(facesContext);
450 newItem.getChildren().add(uiOutput);
451 uiOutput.setParent(newItem);
452 if (uiNavMenuItem.getItemLabel() != null) {
453 if (NavigationMenuUtils.isValueReference(uiNavMenuItem.getItemLabel())) {
454 uiOutput.setValueBinding("value",
455 facesContext.getApplication().createValueBinding(uiNavMenuItem.getItemLabel()));
456 }
457 else {
458 uiOutput.setValue(uiNavMenuItem.getItemLabel());
459 }
460 }
461 else {
462 Object value = uiNavMenuItem.getValue();
463 if (value != null &&
464 NavigationMenuUtils.isValueReference(value.toString())) {
465 uiOutput.setValueBinding("value",
466 facesContext.getApplication().createValueBinding(value.toString()));
467 }
468 else {
469 uiOutput.setValue(uiNavMenuItem.getValue());
470 }
471 }
472 }
473
474 log.debug("Instance of UINavigationMenuItem, preprocess childrens");
475 preprocessNavigationItems(facesContext, newItem, uiNavMenuItem.getChildren(), uniqueId);
476 }
477
478 private boolean copyValueBinding(UIComponent source, UIComponent target, String binding) {
479 ValueBinding valueBinding = source.getValueBinding(binding);
480 if (valueBinding == null)
481 return false;
482 target.setValueBinding(binding, valueBinding);
483 return true;
484 }
485
486
487
488 protected String getStyle(FacesContext facesContext, UIComponent link) {
489 if (!(link instanceof HtmlCommandNavigationItem)) {
490 throw new IllegalArgumentException("expected instance of " + HtmlCommandNavigationItem.class.getName());
491 }
492
493 UIComponent navPanel = HtmlNavigationMenuRendererUtils.getPanel(link);
494
495 HtmlCommandNavigationItem navItem = (HtmlCommandNavigationItem) link;
496 if (navItem.isActive()) {
497 return ((HtmlPanelNavigationMenu) navPanel).getActiveItemStyle();
498 }
499 else if (navItem.isOpen()) {
500 return ((HtmlPanelNavigationMenu) navPanel).getOpenItemStyle();
501 }
502 else {
503 return ((HtmlPanelNavigationMenu) navPanel).getItemStyle();
504 }
505 }
506
507 protected String getStyleClass(FacesContext facesContext, UIComponent link) {
508 if (!(link instanceof HtmlCommandNavigationItem)) {
509 throw new IllegalArgumentException();
510 }
511
512 UIComponent navPanel = HtmlNavigationMenuRendererUtils.getPanel(link);
513
514 HtmlCommandNavigationItem navItem = (HtmlCommandNavigationItem) link;
515 if (navItem.isActive()) {
516 return ((HtmlPanelNavigationMenu) navPanel).getActiveItemClass();
517 }
518 else if (navItem.isOpen()) {
519 return ((HtmlPanelNavigationMenu) navPanel).getOpenItemClass();
520 }
521 else {
522 return ((HtmlPanelNavigationMenu) navPanel).getItemClass();
523 }
524 }
525
526 private static class UniqueId {
527 private int _id;
528
529 public int next() {
530 return _id++;
531 }
532
533 public void decrease() {
534 _id--;
535 }
536 }
537
538 private void expandAll(UIComponent parent) {
539
540 if (parent instanceof HtmlCommandNavigationItem) {
541 HtmlCommandNavigationItem navItem = (HtmlCommandNavigationItem) parent;
542 navItem.setOpen(true);
543 }
544 List children = parent.getChildren();
545 UIComponent child;
546 for (int i = 0; i < children.size(); i++) {
547 child = (UIComponent) children.get(i);
548 expandAll(child);
549 }
550 }
551
552 private void activeOnViewId(UIComponent parent, String viewId) {
553
554 if (parent instanceof HtmlCommandNavigationItem) {
555 HtmlCommandNavigationItem navItem = (HtmlCommandNavigationItem) parent;
556 String[] viewIds = navItem.getActiveOnVieIds();
557 for (int i = 0; i < viewIds.length; i++) {
558 if (viewId.equals(viewIds[i])) {
559 navItem.toggleOpen();
560 navItem.setActive(true);
561 return;
562 }
563 }
564 ;
565 }
566 List children = parent.getChildren();
567 UIComponent child;
568 for (int i = 0; i < children.size(); i++) {
569 child = (UIComponent) children.get(i);
570 activeOnViewId(child, viewId);
571 }
572 }
573 }