1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.templating.jsp.taglib;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.core.Content.ContentFilter;
38 import info.magnolia.cms.core.ItemType;
39 import info.magnolia.cms.core.NodeData;
40 import info.magnolia.cms.i18n.I18nContentSupportFactory;
41 import info.magnolia.context.MgnlContext;
42
43 import java.io.IOException;
44 import java.util.ArrayList;
45 import java.util.Collection;
46 import java.util.Iterator;
47 import java.util.List;
48
49 import javax.jcr.RepositoryException;
50 import javax.servlet.http.HttpServletRequest;
51 import javax.servlet.jsp.JspException;
52 import javax.servlet.jsp.JspWriter;
53 import javax.servlet.jsp.tagext.TagSupport;
54
55 import org.apache.commons.lang.StringEscapeUtils;
56 import org.apache.commons.lang.StringUtils;
57 import org.apache.commons.lang.exception.NestableRuntimeException;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60 import org.tldgen.annotations.BodyContent;
61 import org.tldgen.annotations.Tag;
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95 @Tag(name = "simpleNavigation", bodyContent = BodyContent.EMPTY)
96 public class SimpleNavigationTag extends TagSupport {
97
98
99
100
101 private static final String CSS_LI_ACTIVE = "active";
102
103
104
105
106 private static final String CSS_LI_TRAIL = "trail";
107
108
109
110
111 private static final String CSS_LI_LEAF = "leaf";
112
113
114
115
116 private static final String CSS_LI_CLOSED = "closed";
117
118
119
120
121 private static final String CSS_LI_OPEN = "open";
122
123
124
125
126 private static final String CSS_LI_FIRST = "first";
127
128
129
130
131 private static final String CSS_LI_LAST = "last";
132
133
134
135
136 private static final String NODEDATA_NAVIGATIONTITLE = "navTitle";
137
138
139
140
141 public static final String NODEDATA_ACCESSKEY = "accessKey";
142
143
144
145
146 public static final String DEFAULT_OPENMENU_NODEDATA = "openMenu";
147
148
149
150
151 public static final String DEFAULT_HIDEINNAV_NODEDATA = "hideInNav";
152
153
154
155
156 public static final String DEFAULT_WRAPPERELEMENT_NODEDATA = "";
157
158
159
160
161 public static final String EXPAND_ALL = "all";
162
163
164
165
166 public static final String EXPAND_SHOW = "show";
167
168
169
170
171 public static final String EXPAND_NONE = "none";
172
173
174
175
176 private static final long serialVersionUID = 224L;
177
178
179
180
181 private static Logger log = LoggerFactory.getLogger(SimpleNavigationTag.class);
182
183
184
185
186 private int startLevel;
187
188
189
190
191 private int endLevel;
192
193
194
195
196 private String hideInNav;
197
198
199
200
201 private String openMenu;
202
203
204
205
206 private String style;
207
208
209
210
211 public String wrapperElement;
212
213
214
215
216 private String expandAll = EXPAND_NONE;
217
218 private boolean relativeLevels = false;
219
220
221
222
223 private String classProperty;
224
225
226
227
228 private String nofollow;
229
230
231
232
233 private ContentFilter filter;
234
235 private String contentFilter = "";
236
237
238
239
240 private boolean markFirstAndLastElement = false;
241
242
243
244
245
246
247 public void setStartLevel(int startLevel) {
248 this.startLevel = startLevel;
249 }
250
251
252
253
254
255
256 public void setEndLevel(int endLevel) {
257 this.endLevel = endLevel;
258 }
259
260
261
262
263
264
265 public void setStyle(String style) {
266 this.style = style;
267 }
268
269
270
271
272
273
274
275 public void setHideInNav(String hideInNav) {
276 this.hideInNav = hideInNav;
277 }
278
279
280
281
282
283
284
285
286 public void setOpenMenu(String openMenu) {
287 this.openMenu = openMenu;
288 }
289
290
291
292
293
294
295
296
297 public void setNofollow(String nofollow) {
298 this.nofollow = nofollow;
299 }
300
301
302
303
304
305
306 public void setContentFilter(String contentFilter) {
307 this.contentFilter = contentFilter;
308 }
309
310
311
312
313
314
315
316 public void setExpandAll(String expandAll) {
317 if (expandAll.equalsIgnoreCase(EXPAND_SHOW)) {
318 this.expandAll = expandAll;
319 }
320 else {
321 this.expandAll = EXPAND_ALL;
322 }
323 }
324
325
326
327
328
329
330
331 public void setRelativeLevels(boolean relativeLevels) {
332 this.relativeLevels = relativeLevels;
333 }
334
335
336
337
338
339
340 public void setClassProperty(String classProperty) {
341 this.classProperty = classProperty;
342 }
343
344
345
346
347
348
349
350 public void setWrapperElement(String wrapperElement) {
351 this.wrapperElement = wrapperElement;
352 }
353
354
355
356
357
358
359
360 public void setMarkFirstAndLastElement(boolean flag) {
361 markFirstAndLastElement = flag;
362 }
363
364 @Override
365 public int doEndTag() throws JspException {
366 Content activePage = getCurrentActivePage();
367 try {
368 while (!ItemType.PAGE.getSystemName().equals(activePage.getNodeTypeName()) && activePage.getLevel() != 0) {
369 activePage = activePage.getParent();
370 }
371 } catch (RepositoryException e) {
372 log.error("Failed to obtain parent page for " + getCurrentActivePage().getHandle(), e);
373 activePage = getCurrentActivePage();
374 }
375 JspWriter out = this.pageContext.getOut();
376
377 if (StringUtils.isNotEmpty(this.contentFilter)) {
378 try {
379 filter = (ContentFilter) this.pageContext.getAttribute(this.contentFilter);
380 } catch (ClassCastException e) {
381 log.error("contentFilter assigned was not a content filter", e);
382 }
383 } else {
384 filter = null;
385 }
386
387 if (startLevel > endLevel) {
388 endLevel = 0;
389 }
390
391 try {
392 final int activePageLevel = activePage.getLevel();
393
394
395 if (relativeLevels) {
396 this.startLevel += activePageLevel;
397 this.endLevel += activePageLevel;
398 }
399 if (this.startLevel <= activePageLevel) {
400 Content startContent = activePage.getAncestor(this.startLevel);
401 drawChildren(startContent, activePage, out);
402 }
403
404 } catch (RepositoryException e) {
405 log.error("RepositoryException caught while drawing navigation: " + e.getMessage(), e);
406 return EVAL_PAGE;
407 } catch (IOException e) {
408
409 throw new NestableRuntimeException(e);
410 }
411
412 return EVAL_PAGE;
413 }
414
415 @Override
416 public void release() {
417 this.startLevel = 0;
418 this.endLevel = 0;
419 this.hideInNav = null;
420 this.openMenu = null;
421 this.style = null;
422 this.classProperty = null;
423 this.expandAll = EXPAND_NONE;
424 this.relativeLevels = false;
425 this.wrapperElement = "";
426 this.contentFilter = "";
427 this.filter = null;
428 this.nofollow = null;
429 this.markFirstAndLastElement = false;
430 super.release();
431 }
432
433
434
435
436
437
438
439
440
441
442 private void drawChildren(Content page, Content activePage, JspWriter out) throws IOException, RepositoryException {
443
444 Collection<Content> children = new ArrayList<Content>(page.getChildren(ItemType.CONTENT));
445
446 if (children.size() == 0) {
447 return;
448 }
449
450 out.print("<ul class=\"level");
451 out.print(page.getLevel());
452 if (style != null && page.getLevel() == startLevel) {
453 out.print(" ");
454 out.print(style);
455 }
456 out.print("\">");
457
458 Iterator<Content> iter = children.iterator();
459
460 while (iter.hasNext()) {
461 final Content child = iter.next();
462
463 if (expandAll.equalsIgnoreCase(EXPAND_NONE) || expandAll.equalsIgnoreCase(EXPAND_SHOW)) {
464 if (child
465 .getNodeData(StringUtils.defaultString(this.hideInNav, DEFAULT_HIDEINNAV_NODEDATA)).getBoolean()) {
466 iter.remove();
467 continue;
468 }
469
470 if (filter != null) {
471 if (!filter.accept(child)) {
472 iter.remove();
473 continue;
474 }
475 }
476 } else {
477 if (child.getNodeData(StringUtils.defaultString(this.hideInNav, DEFAULT_HIDEINNAV_NODEDATA)).getBoolean()) {
478 iter.remove();
479 continue;
480 }
481 }
482 }
483
484 boolean isFirst = true;
485 Iterator<Content> visibleIt = children.iterator();
486 while (visibleIt.hasNext()) {
487 Content child = visibleIt.next();
488 List<String> cssClasses = new ArrayList<String>(4);
489
490 NodeData nodeData = I18nContentSupportFactory.getI18nSupport().getNodeData(child, NODEDATA_NAVIGATIONTITLE);
491 String title = null;
492 if(nodeData != null){
493 title = nodeData.getString(StringUtils.EMPTY);
494 }
495
496
497 if (StringUtils.isEmpty(title)) {
498 title = child.getTitle();
499 }
500
501
502 if (StringUtils.isEmpty(title)) {
503 title = child.getName();
504 }
505
506 boolean showChildren = false;
507 boolean self = false;
508
509 if (!expandAll.equalsIgnoreCase(EXPAND_NONE)) {
510 showChildren = true;
511 }
512
513 if (activePage.getHandle().equals(child.getHandle())) {
514
515 showChildren = true;
516 self = true;
517 cssClasses.add(CSS_LI_ACTIVE);
518 }
519 else if (!showChildren) {
520 showChildren = child.getLevel() <= activePage.getAncestors().size() && StringUtils.equals(activePage.getAncestor(child.getLevel()).getHandle(), child.getHandle());
521 }
522
523 if (!showChildren) {
524 showChildren = child
525 .getNodeData(StringUtils.defaultString(this.openMenu, DEFAULT_OPENMENU_NODEDATA))
526 .getBoolean();
527 }
528
529 if (endLevel > 0) {
530 showChildren &= child.getLevel() < endLevel;
531 }
532
533 cssClasses.add(hasVisibleChildren(child) ? showChildren ? CSS_LI_OPEN : CSS_LI_CLOSED : CSS_LI_LEAF);
534
535 if (child.getLevel() < activePage.getLevel()
536 && activePage.getAncestor(child.getLevel()).getHandle().equals(child.getHandle())) {
537 cssClasses.add(CSS_LI_TRAIL);
538 }
539
540 if (StringUtils.isNotEmpty(classProperty) && child.hasNodeData(classProperty)) {
541 cssClasses.add(child.getNodeData(classProperty).getString(StringUtils.EMPTY));
542 }
543
544 if (markFirstAndLastElement && isFirst) {
545 cssClasses.add(CSS_LI_FIRST);
546 isFirst = false;
547 }
548
549 if (markFirstAndLastElement && !visibleIt.hasNext()) {
550 cssClasses.add(CSS_LI_LAST);
551 }
552
553 StringBuffer css = new StringBuffer(cssClasses.size() * 10);
554 Iterator<String> iterator = cssClasses.iterator();
555 while (iterator.hasNext()) {
556 css.append(iterator.next());
557 if (iterator.hasNext()) {
558 css.append(" ");
559 }
560 }
561
562 out.print("<li class=\"");
563 out.print(css.toString());
564 out.print("\">");
565
566 if (self) {
567 out.println("<strong>");
568 }
569
570 String accesskey = null;
571 if(child.getNodeData(NODEDATA_ACCESSKEY) != null){
572 accesskey = child.getNodeData(NODEDATA_ACCESSKEY).getString(StringUtils.EMPTY);
573 }
574
575 out.print("<a href=\"");
576 out.print(((HttpServletRequest) this.pageContext.getRequest()).getContextPath());
577 out.print(I18nContentSupportFactory.getI18nSupport().toI18NURI(child.getHandle()));
578 out.print(".html\"");
579
580 if (StringUtils.isNotEmpty(accesskey)) {
581 out.print(" accesskey=\"");
582 out.print(accesskey);
583 out.print("\"");
584 }
585
586 if (nofollow != null && child.getNodeData(this.nofollow).getBoolean())
587 {
588 out.print(" rel=\"nofollow\"");
589 }
590
591 out.print(">");
592
593 if (StringUtils.isNotEmpty(this.wrapperElement)) {
594 out.print("<" + this.wrapperElement + ">");
595 }
596
597 out.print(StringEscapeUtils.escapeHtml(title));
598
599 if (StringUtils.isNotEmpty(this.wrapperElement)) {
600 out.print("</" + this.wrapperElement + ">");
601 }
602
603 out.print(" </a>");
604
605 if (self) {
606 out.println("</strong>");
607 }
608
609 if (showChildren) {
610 drawChildren(child, activePage, out);
611 }
612 out.print("</li>");
613 }
614
615 out.print("</ul>");
616 }
617
618
619
620
621
622
623
624 private boolean hasVisibleChildren(Content page) {
625 Collection<Content> children = page.getChildren();
626 if (children.size() > 0 && expandAll.equalsIgnoreCase(EXPAND_ALL)) {
627 return true;
628 }
629 for (Content ch : children) {
630 if (!ch.getNodeData(StringUtils.defaultString(this.hideInNav, DEFAULT_HIDEINNAV_NODEDATA)).getBoolean()) {
631 return true;
632 }
633 }
634 return false;
635 }
636
637 protected Content getCurrentActivePage() {
638 Content currentActpage = MgnlContext.getAggregationState().getCurrentContent();
639 if (currentActpage == null) {
640 currentActpage = MgnlContext.getAggregationState().getMainContent();
641 }
642 return currentActpage;
643 }
644
645 }