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