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 }