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