1 package org.apache.turbine.util.template;
2
3
4 /*
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 */
22
23
24 import java.util.ArrayList;
25 import java.util.LinkedHashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import org.apache.commons.lang3.StringUtils;
30 import org.apache.turbine.TurbineConstants;
31 import org.apache.turbine.annotation.TurbineConfiguration;
32 import org.apache.turbine.services.pull.ApplicationTool;
33
34 /**
35 * Template context tool that can be used to set various attributes of a
36 * HTML page. This tool does not automatically make the changes in the HTML
37 * page for you. You must use this tool in your layout template to retrieve
38 * the attributes.
39 * <p>
40 * The set/add methods are can be used from a screen template, action, screen
41 * class, layour template, or anywhere else. The get methods should be used in
42 * your layout template(s) to construct the appropriate HTML tags.
43 * </p>
44 *
45 *<p>
46 * Example usage of this tool to build the HEAD and BODY tags in your layout
47 * templates:
48 * </p>
49 *
50 * <p>
51 * <code>
52 * ## Set defaults for all pages using this layout. Anything set here can<br>
53 * ## be overridden in the screen template.<br>
54 * $page.setTitle("My default page title");<br>
55 * $page.setHttpEquiv("Content-Style-Type","text/css")<br>
56 * $page.addStyleSheet($content.getURI("myStyleSheet.css"))<br>
57 * $page.addScript($content.getURI("globalJavascriptCode.js"))<br>
58 * <br>
59 * ## build the HTML, HEAD, and BODY tags dynamically<br>
60 * <html><br>
61 * <head><br>
62 * #if( $page.Title != "" )<br>
63 * <title>$page.Title</title><br>
64 * #end<br>
65 * #foreach($metaTag in $page.MetaTags.keySet())<br>
66 * <meta name="$metaTag" content="$page.MetaTags.get($metaTag)"><br>
67 * #end<br>
68 * #foreach($httpEquiv in $page.HttpEquivs.keySet())<br>
69 * <meta http-equiv="$httpEquiv" content="$page.HttpEquivs.get($httpEquiv)"><br>
70 * #end<br>
71 * #foreach( $styleSheet in $page.StyleSheets )<br>
72 * <link rel="stylesheet" href="$styleSheet.Url"<br>
73 * #if($styleSheet.Type != "" ) type="$styleSheet.Type" #end<br>
74 * #if($styleSheet.Media != "") media="$styleSheet.Media" #end<br>
75 * #if($styleSheet.Title != "") title="$styleSheet.Title" #end<br>
76 * ><br>
77 * #end<br>
78 * #foreach( $script in $page.Scripts )<br>
79 * <script type="text/javascript" src="$script" language="JavaScript"></script><br>
80 * #end<br>
81 * </head><br>
82 *<br>
83 * ## Construct the body tag. Iterate through the body attributes to build the opening tag<br>
84 * <body<br>
85 * #foreach( $attributeName in $page.BodyAttributes.keySet() )<br>
86 * $attributeName = "$page.BodyAttributes.get($attributeName)"<br>
87 * #end<br>
88 * >
89 * </code>
90 * </p>
91 *
92 * <p>
93 * Example usages of this tool in your screen templates:<br>
94 * <code>$page.addScript($content.getURI("myJavascript.js")<br>
95 * $page.setTitle("My page title")<br>
96 * $page.setHttpEquiv("refresh","5; URL=http://localhost/nextpage.html")</code>
97 * </p>
98 *
99 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
100 * @author <a href="mailto:seade@backstagetech.com.au">Scott Eade</a>
101 * @version $Id$
102 */
103 public class HtmlPageAttributes
104 implements ApplicationTool
105 {
106 /** The title */
107 private String title;
108
109 /** Body Attributes */
110 private final Map<String, String> bodyAttributes = new LinkedHashMap<>();
111
112 /** Script references */
113 private final List<String> scripts = new ArrayList<>();
114
115 /** External references */
116 private final List<LinkTag> linkTags = new ArrayList<>();
117
118 /** Inline styles */
119 private final List<String> styles = new ArrayList<>();
120
121 /** Meta tags for the HEAD */
122 private final Map<String, String> metaTags = new LinkedHashMap<>();
123
124 /** http-equiv tags */
125 private final Map<String, String> httpEquivs = new LinkedHashMap<>();
126
127 /** Doctype */
128 private String doctype = null;
129
130 @TurbineConfiguration( TurbineConstants.DEFAULT_HTML_DOCTYPE_ROOT_ELEMENT_KEY )
131 private String defaultHtmlDoctypeRootElement = TurbineConstants.DEFAULT_HTML_DOCTYPE_ROOT_ELEMENT_DEFAULT;
132
133 @TurbineConfiguration( TurbineConstants.DEFAULT_HTML_DOCTYPE_IDENTIFIER_KEY )
134 private String defaultHtmlDoctypeIdentifier;
135
136 @TurbineConfiguration( TurbineConstants.DEFAULT_HTML_DOCTYPE_URI_KEY )
137 private String defaultHtmlDoctypeUri;
138
139 /**
140 * Construct a new instance
141 */
142 public HtmlPageAttributes()
143 {
144 init(null);
145 }
146
147 /**
148 * Initialize this instance.
149 * (ApplicationTool method)
150 *
151 * @param data not used
152 */
153 @Override
154 public void init(Object data)
155 {
156 this.title = null;
157 this.bodyAttributes.clear();
158 this.scripts.clear();
159 this.linkTags.clear();
160 this.styles.clear();
161 this.metaTags.clear();
162 this.httpEquivs.clear();
163 }
164
165 /**
166 * Refresh method - does nothing
167 */
168 @Override
169 public void refresh()
170 {
171 // empty
172 }
173
174 /**
175 * Set the title in the page. This returns an empty String so
176 * that the template doesn't complain about getting a null return
177 * value. Subsequent calls to this method will replace the current
178 * title.
179 *
180 * @param title A String with the title.
181 * @return a <code>HtmlPageAttributes</code> (self).
182 */
183 public HtmlPageAttributes setTitle(String title)
184 {
185 this.title = title;
186 return this;
187 }
188
189 /**
190 * Get the title in the page. This returns an empty String if
191 * empty so that the template doesn't complain about getting a null
192 * return value.
193 *
194 * @return A String with the title.
195 */
196 public String getTitle()
197 {
198 if (StringUtils.isEmpty(this.title))
199 {
200 return "";
201 }
202 return title;
203 }
204
205 /**
206 * Adds an attribute to the BODY tag.
207 *
208 * @param name A String.
209 * @param value A String.
210 * @return a <code>HtmlPageAttributes</code> (self).
211 */
212 public HtmlPageAttributes addBodyAttribute(String name, String value)
213 {
214 this.bodyAttributes.put(name, value);
215 return this;
216 }
217
218 /**
219 * Returns the map of body attributes
220 *
221 * @return the map
222 */
223 public Map<String, String> getBodyAttributes()
224 {
225 return this.bodyAttributes;
226 }
227
228 /**
229 * Adds a script reference
230 *
231 * @param scriptURL the url
232 * @return a <code>HtmlPageAttributes</code> (self).
233 */
234 public HtmlPageAttributes addScript(String scriptURL)
235 {
236 this.scripts.add(scriptURL);
237 return this;
238 }
239
240 /**
241 * Returns a collection of script URLs
242 *
243 * @return list of String objects containing URLs of javascript files
244 * to include
245 */
246 public List<String> getScripts()
247 {
248 return this.scripts;
249 }
250
251 /**
252 * Adds a style sheet reference
253 *
254 * @param styleSheetURL URL of the style sheet
255 * @return a <code>HtmlPageAttributes</code> (self).
256 */
257 public HtmlPageAttributes addStyleSheet(String styleSheetURL)
258 {
259 addStyleSheet(styleSheetURL, "screen", null, "text/css");
260 return this;
261 }
262
263 /**
264 * Adds a style sheet reference
265 *
266 * @param styleSheetURL URL of the style sheet
267 * @param media name of the media
268 * @param title title of the stylesheet
269 * @param type content type
270 * @return a <code>HtmlPageAttributes</code> (self).
271 */
272 public HtmlPageAttributes addStyleSheet(String styleSheetURL,
273 String media, String title, String type)
274 {
275 LinkTag ss = new LinkTag("stylesheet", styleSheetURL);
276 ss.setMedia(media);
277 ss.setTitle(title);
278 ss.setType(type);
279 this.linkTags.add(ss);
280 return this;
281 }
282
283 /**
284 * Adds a generic external reference
285 *
286 * @param relation type of the reference (prev, next, first, last, top, etc.)
287 * @param linkURL URL of the reference
288 * @return a <code>HtmlPageAttributes</code> (self).
289 */
290 public HtmlPageAttributes addLink(String relation, String linkURL)
291 {
292 return addLink(relation, linkURL, null, null);
293 }
294
295 /**
296 * Adds a generic external reference
297 *
298 * @param relation type of the reference (prev, next, first, last, top, etc.)
299 * @param linkURL URL of the reference
300 * @param title title of the reference
301 * @return a <code>HtmlPageAttributes</code> (self).
302 */
303 public HtmlPageAttributes addLink(String relation, String linkURL, String title)
304 {
305 return addLink(relation, linkURL, title, null);
306 }
307
308 /**
309 * Adds a generic external reference
310 *
311 * @param relation type of the reference (prev, next, first, last, top, etc.)
312 * @param linkURL URL of the reference
313 * @param title title of the reference
314 * @param type content type
315 * @return a <code>HtmlPageAttributes</code> (self).
316 */
317 public HtmlPageAttributes addLink(String relation, String linkURL, String title,
318 String type)
319 {
320 LinkTag ss = new LinkTag(relation, linkURL);
321 ss.setTitle(title);
322 ss.setType(type);
323 this.linkTags.add(ss);
324 return this;
325 }
326
327 /**
328 * Returns a collection of link URLs
329 *
330 * @return list LinkTag objects (inner class)
331 */
332 public List<LinkTag> getLinks()
333 {
334 return this.linkTags;
335 }
336
337 /**
338 * Adds a STYLE element to the HEAD of the page with the provided content.
339 *
340 * @param styleText The contents of the <code>style</code> tag.
341 * @return a <code>HtmlPageAttributes</code> (self).
342 */
343 public HtmlPageAttributes addStyle(String styleText)
344 {
345 this.styles.add(styleText);
346 return this;
347 }
348
349 /**
350 * Returns a collection of styles
351 *
352 * @return list of String objects containing the contents of style tags
353 */
354 public List<String> getStyles()
355 {
356 return this.styles;
357 }
358
359 /**
360 * Set a keywords META tag in the HEAD of the page.
361 *
362 * @param keywords A String.
363 * @return a <code>HtmlPageAttributes</code> (self).
364 */
365 public HtmlPageAttributes setKeywords(String keywords)
366 {
367 this.metaTags.put("keywords", keywords);
368 return this;
369 }
370
371 /**
372 * Sets a HttpEquiv META tag in the HEAD of the page, usage:
373 * <br><code>setHttpEquiv("refresh", "5; URL=http://localhost/nextpage.html")</code>
374 * <br><code>setHttpEquiv("Expires", "Tue, 20 Aug 1996 14:25:27 GMT")</code>
375 *
376 * @param httpEquiv The value to use for the http-equiv attribute.
377 * @param content The text for the content attribute of the meta tag.
378 * @return a <code>HtmlPageAttributes</code> (self).
379 */
380 public HtmlPageAttributes setHttpEquiv(String httpEquiv, String content)
381 {
382 this.httpEquivs.put(httpEquiv, content);
383 return this;
384 }
385
386 /**
387 * Add a description META tag to the HEAD of the page.
388 *
389 * @param description A String.
390 * @return a <code>HtmlPageAttributes</code> (self).
391 */
392 public HtmlPageAttributes setDescription(String description)
393 {
394 this.metaTags.put("description", description);
395 return this;
396 }
397
398 /**
399 * Set the background image for the BODY tag.
400 *
401 * @param url A String.
402 * @return a <code>HtmlPageAttributes</code> (self).
403 */
404 public HtmlPageAttributes setBackground(String url)
405 {
406 this.bodyAttributes.put("background", url);
407 return this;
408 }
409
410 /**
411 * Set the background color for the BODY tag. You can use either
412 * color names or color values (e.g. "white" or "#ffffff" or
413 * "ffffff").
414 *
415 * @param color A String.
416 * @return a <code>HtmlPageAttributes</code> (self).
417 */
418 public HtmlPageAttributes setBgColor(String color)
419 {
420 this.bodyAttributes.put("BGCOLOR", color);
421 return this;
422 }
423
424 /**
425 * Set the text color for the BODY tag. You can use either color
426 * names or color values (e.g. "white" or "#ffffff" or "ffffff").
427 *
428 * @param color A String.
429 * @return a <code>HtmlPageAttributes</code> (self).
430 */
431 public HtmlPageAttributes setTextColor(String color)
432 {
433 this.bodyAttributes.put("TEXT", color);
434 return this;
435 }
436
437 /**
438 * Set the link color for the BODY tag. You can use either color
439 * names or color values (e.g. "white" or "#ffffff" or "ffffff").
440 *
441 * @param color A String.
442 * @return a <code>HtmlPageAttributes</code> (self).
443 */
444 public HtmlPageAttributes setLinkColor(String color)
445 {
446 this.bodyAttributes.put("LINK", color);
447 return this;
448 }
449
450 /**
451 * Set the visited link color for the BODY tag.
452 *
453 * @param color A String.
454 * @return a <code>HtmlPageAttributes</code> (self).
455 */
456 public HtmlPageAttributes setVlinkColor(String color)
457 {
458 this.bodyAttributes.put("VLINK", color);
459 return this;
460 }
461
462 /**
463 * Set the active link color for the BODY tag.
464 *
465 * @param color A String.
466 * @return a <code>HtmlPageAttributes</code> (self).
467 */
468 public HtmlPageAttributes setAlinkColor(String color)
469 {
470 this.bodyAttributes.put("ALINK", color);
471 return this;
472 }
473
474 /**
475 * Gets the map of http equiv tags
476 *
477 * @return Map of http equiv names to the contents
478 */
479 public Map<String, String> getHttpEquivs()
480 {
481 return this.httpEquivs;
482 }
483
484 /**
485 * Gets the map of meta tags
486 *
487 * @return Map of http equiv names to the contents
488 */
489 public Map<String, String> getMetaTags()
490 {
491 return this.metaTags;
492 }
493
494 /**
495 * A dummy toString method that returns an empty string.
496 *
497 * @return An empty String ("").
498 */
499 @Override
500 public String toString()
501 {
502 return "";
503 }
504
505 /**
506 * Helper class to hold data about a <link ... /> html header tag
507 */
508 public static class LinkTag
509 {
510 private String relation;
511 private String url;
512 private String title;
513 private String media;
514 private String type;
515
516 /**
517 * Constructor requiring the URL and relation to be set
518 *
519 * @param relation Relation type the external link such as prev, next,
520 * stylesheet, shortcut icon
521 * @param url URL of the external link
522 */
523 public LinkTag(String relation, String url)
524 {
525 setRelation(relation);
526 setUrl(url);
527 }
528
529 /**
530 * Gets the content type of the style sheet
531 *
532 * @return content type
533 */
534 public String getType()
535 {
536 return (StringUtils.isEmpty(type) ? "" : type);
537 }
538
539 /**
540 * Sets the content type of the style sheet
541 *
542 * @param type content type
543 */
544 public void setType(String type)
545 {
546 this.type = type;
547 }
548
549 /**
550 * @return String representation of the URL
551 */
552 public String getUrl()
553 {
554 return url;
555 }
556
557 /**
558 * Sets the URL of the external style sheet
559 *
560 * @param url The URL of the stylesheet
561 */
562 private void setUrl(String url)
563 {
564 this.url = url;
565 }
566
567 /**
568 * Gets the title of the style sheet
569 *
570 * @return title
571 */
572 public String getTitle()
573 {
574 return (StringUtils.isEmpty(title) ? "" : title);
575 }
576
577 /**
578 * Sets the title of the stylesheet
579 *
580 * @param title of the stylesheet
581 */
582 public void setTitle(String title)
583 {
584 this.title = title;
585 }
586
587 /**
588 * Gets the media for which the stylesheet should be applied.
589 *
590 * @return name of the media
591 */
592 public String getMedia()
593 {
594 return (StringUtils.isEmpty(media) ? "" : media);
595 }
596
597 /**
598 * Sets the media for which the stylesheet should be applied.
599 *
600 * @param media name of the media
601 */
602 public void setMedia(String media)
603 {
604 this.media = media;
605 }
606
607 /**
608 * Gets the relation type of the tag.
609 *
610 * @return name of the relation
611 */
612 public String getRelation()
613 {
614 return (StringUtils.isEmpty(relation) ? "" : relation);
615 }
616
617 /**
618 * Sets the relation type of the tag.
619 *
620 * @param relation name of the relation
621 */
622 public void setRelation(String relation)
623 {
624 this.relation = relation;
625 }
626 }
627
628 /**
629 * Retrieve the default Doctype as configured by the
630 * TurbineResources.peoperties
631 * default.doctype.root.element, default.doctype.identifier and
632 * default.doctype.url properties (defaults are "HTML",
633 * "-//W3C//DTD HTML 4.01 Transitional//EN" and
634 * "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd" respectively).
635 *
636 * @return the DOCTYPE tag constructed from the properties in
637 * TurbineResources.properties.
638 */
639 public String getDefaultDoctype()
640 {
641 if (doctype == null)
642 {
643 String tag = defaultHtmlDoctypeRootElement;
644
645 if (StringUtils.isEmpty(tag))
646 {
647 doctype = "";
648 }
649 else
650 {
651 doctype = getDoctype(tag, defaultHtmlDoctypeIdentifier, defaultHtmlDoctypeUri);
652 }
653 }
654
655 return doctype;
656 }
657
658 /**
659 * Build the doctype element.
660 *
661 * @param tag the tag whose DTD is being declared.
662 * @param identifier the identifier for the doctype declaration.
663 * @param uri the uri for the doctype declaration.
664 * @return the doctype.
665 */
666 public String getDoctype(String tag, String identifier, String uri)
667 {
668 StringBuilder doctypeBuf = new StringBuilder("<!DOCTYPE ");
669 doctypeBuf.append(tag);
670
671 if (StringUtils.isNotEmpty(identifier))
672 {
673 doctypeBuf.append(" PUBLIC \"");
674 doctypeBuf.append(identifier);
675 doctypeBuf.append("\" \"");
676 doctypeBuf.append(uri);
677 doctypeBuf.append('"');
678 }
679 else if (StringUtils.isNotEmpty(uri))
680 {
681 doctypeBuf.append(" SYSTEM \"");
682 doctypeBuf.append(uri);
683 doctypeBuf.append('"');
684 }
685
686 doctypeBuf.append('>');
687
688 return doctypeBuf.toString();
689 }
690 }