001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.html; 014 015import org.apache.juneau.internal.*; 016 017/** 018 * A basic template for the HTML doc serializer. 019 * 020 * <p> 021 * This class can be subclassed to customize page rendering. 022 */ 023public class BasicHtmlDocTemplate implements HtmlDocTemplate { 024 025 @Override /* HtmlDocTemplate */ 026 public void writeTo(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 027 w.sTag("html").nl(0); 028 w.sTag(1, "head").nl(1); 029 head(session, w, o); 030 w.eTag(1, "head").nl(1); 031 w.sTag(1, "body").nl(1); 032 body(session, w, o); 033 w.eTag(1, "body").nl(1); 034 w.eTag("html").nl(0); 035 } 036 037 /** 038 * Renders the contents of the <code><xt><head></xt></code> element. 039 * 040 * @param session The current serializer session. 041 * @param w The writer being written to. 042 * @param o The object being serialized. 043 * @throws Exception Any exception can be thrown. 044 */ 045 protected void head(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 046 047 String[] head = session.getHead(); 048 for (int i = 0; i < head.length; i++) 049 w.sIf(i > 0).appendln(2, head[i]); 050 051 if (hasStyle(session)) { 052 w.sTag(2, "style").nl(2); 053 style(session, w, o); 054 w.ie(2).eTag("style").nl(2); 055 } 056 if (hasScript(session)) { 057 w.sTag(2, "script").nl(2); 058 script(session, w, o); 059 w.ie(2).eTag("script").nl(2); 060 } 061 } 062 063 /** 064 * Renders the contents of the <code><xt><head></xt>/<xt><style></xt></code> element. 065 * 066 * @param session The current serializer session. 067 * @param w The writer being written to. 068 * @param o The object being serialized. 069 * @throws Exception Any exception can be thrown. 070 */ 071 protected void style(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 072 073 int i = 0; 074 for (String s : session.getStylesheet()) 075 w.sIf(i++ > 0).append(3, "@import ").q().append(session.resolveUri(s)).q().appendln(";"); 076 077 if (session.isNowrap()) 078 w.appendln(3, "div.data * {white-space:nowrap;} "); 079 080 for (String s : session.getStyle()) 081 w.sIf(i > 0).appendln(3, s); 082 } 083 084 /** 085 * Renders the contents of the <code><xt><head></xt>/<xt><script></xt></code> element. 086 * 087 * @param session The current serializer session. 088 * @param w The writer being written to. 089 * @param o The object being serialized. 090 * @throws Exception Any exception can be thrown. 091 */ 092 protected void script(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 093 int i = 0; 094 for (String s : session.getScript()) 095 w.sIf(i++ > 0).append(3, s).append('\n'); // Must always append a newline even if whitespace disabled! 096 } 097 098 /** 099 * Renders the contents of the <code><xt><body></xt></code> element. 100 * 101 * @param session The current serializer session. 102 * @param w The writer being written to. 103 * @param o The object being serialized. 104 * @throws Exception Any exception can be thrown. 105 */ 106 protected void body(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 107 108 if (hasHeader(session)) { 109 w.sTag(2, "header").nl(2); 110 header(session, w, o); 111 w.ie(2).eTag("header").nl(2); 112 } 113 114 if (hasNav(session)) { 115 w.sTag(2, "nav").nl(2); 116 nav(session, w, o); 117 w.ie(2).eTag("nav").nl(2); 118 } 119 120 w.sTag(2, "section").nl(2); 121 122 w.sTag(3, "article").nl(3); 123 article(session, w, o); 124 w.ie(3).eTag("article").nl(3); 125 126 if (hasAside(session)) { 127 w.sTag(3, "aside").nl(3); 128 aside(session, w, o); 129 w.ie(3).eTag("aside").nl(3); 130 } 131 132 w.ie(2).eTag("section").nl(2); 133 134 if (hasFooter(session)) { 135 w.sTag(2, "footer").nl(2); 136 footer(session, w, o); 137 w.ie(2).eTag("footer").nl(2); 138 } 139 } 140 141 /** 142 * Renders the contents of the <code><xt><body></xt>/<xt><header></xt></code> element. 143 * 144 * @param session The current serializer session. 145 * @param w The writer being written to. 146 * @param o The object being serialized. 147 * @throws Exception Any exception can be thrown. 148 */ 149 protected void header(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 150 // Write the title of the page. 151 String[] header = session.getHeader(); 152 for (int i = 0; i < header.length; i++) 153 w.sIf(i > 0).appendln(3, header[i]); 154 } 155 156 /** 157 * Renders the contents of the <code><xt><body></xt>/<xt><nav></xt></code> element. 158 * 159 * @param session The current serializer session. 160 * @param w The writer being written to. 161 * @param o The object being serialized. 162 * @throws Exception Any exception can be thrown. 163 */ 164 protected void nav(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 165 String[] links = session.getNavLinks(); 166 if (links.length > 0 && ! ArrayUtils.contains("NONE", links)) { 167 w.sTag(3, "ol").nl(3); 168 for (String l : links) { 169 w.sTag(4, "li"); 170 if (l.matches("(?s)\\S+\\:.*")) { 171 int i = l.indexOf(':'); 172 String key = l.substring(0, i); 173 String val = l.substring(i+1).trim(); 174 if (val.startsWith("<")) 175 w.nl(4).appendln(5, val); 176 else 177 w.oTag("a").attr("href", session.resolveUri(val), true).cTag().text(key, true).eTag("a"); 178 w.eTag("li").nl(4); 179 } else { 180 w.nl(4).appendln(5, l); 181 w.eTag(4, "li").nl(4); 182 } 183 } 184 w.eTag(3, "ol").nl(3); 185 } 186 String[] nav = session.getNav(); 187 if (nav.length > 0) { 188 for (int i = 0; i < nav.length; i++) 189 w.sIf(i > 0).appendln(3, nav[i]); 190 } 191 } 192 193 /** 194 * Renders the contents of the <code><xt><body></xt>/<xt><aside></xt></code> element. 195 * 196 * @param session The current serializer session. 197 * @param w The writer being written to. 198 * @param o The object being serialized. 199 * @throws Exception Any exception can be thrown. 200 */ 201 protected void aside(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 202 String[] aside = session.getAside(); 203 for (int i = 0; i < aside.length; i++) 204 w.sIf(i > 0).appendln(4, aside[i]); 205 } 206 207 /** 208 * Renders the contents of the <code><xt><body></xt>/<xt><article></xt></code> element. 209 * 210 * @param session The current serializer session. 211 * @param w The writer being written to. 212 * @param o The object being serialized. 213 * @throws Exception Any exception can be thrown. 214 */ 215 protected void article(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 216 // To allow for page formatting using CSS, we encapsulate the data inside two div tags: 217 // <div class='outerdata'><div class='data' id='data'>...</div></div> 218 w.oTag(4, "div").attr("class","outerdata").append('>').nl(4); 219 w.oTag(5, "div").attr("class","data").attr("id", "data").append('>').nl(5); 220 221 if (o == null) { 222 w.append(6, "<null/>").nl(6); 223 } else if (ObjectUtils.isEmpty(o)){ 224 String m = session.getNoResultsMessage(); 225 if (exists(m)) 226 w.append(6, m).nl(6); 227 } else { 228 session.indent = 6; 229 w.flush(); 230 session.parentSerialize(w, o); 231 } 232 233 w.ie(5).eTag("div").nl(5); 234 w.ie(4).eTag("div").nl(4); 235 } 236 237 /** 238 * Renders the contents of the <code><xt><body></xt>/<xt><footer></xt></code> element. 239 * 240 * @param session The current serializer session. 241 * @param w The writer being written to. 242 * @param o The object being serialized. 243 * @throws Exception Any exception can be thrown. 244 */ 245 protected void footer(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 246 String[] footer = session.getFooter(); 247 for (int i = 0; i < footer.length; i++) 248 w.sIf(i > 0).appendln(3, footer[i]); 249 } 250 251 /** 252 * Returns <jk>true</jk> if this page should render a <code><xt><head></xt>/<xt><style></xt></code> element. 253 * 254 * @param session The current serializer session. 255 * @return A boolean flag. 256 */ 257 protected boolean hasStyle(HtmlDocSerializerSession session) { 258 return true; 259 } 260 261 /** 262 * Returns <jk>true</jk> if this page should render a <code><xt><head></xt>/<xt><script></xt></code> element. 263 * 264 * @param session The current serializer session. 265 * @return A boolean flag. 266 */ 267 protected boolean hasScript(HtmlDocSerializerSession session) { 268 return true; 269 } 270 271 /** 272 * Returns <jk>true</jk> if this page should render a <code><xt><body></xt>/<xt><header></xt></code> 273 * element. 274 * 275 * @param session The current serializer session. 276 * @return A boolean flag. 277 */ 278 protected boolean hasHeader(HtmlDocSerializerSession session) { 279 return session.getHeader().length > 0; 280 } 281 282 /** 283 * Returns <jk>true</jk> if this page should render a <code><xt><body></xt>/<xt><nav></xt></code> 284 * element. 285 * 286 * @param session The current serializer session. 287 * @return A boolean flag. 288 */ 289 protected boolean hasNav(HtmlDocSerializerSession session) { 290 return session.getNav().length > 0 || session.getNavLinks().length > 0; 291 } 292 293 /** 294 * Returns <jk>true</jk> if this page should render a <code><xt><body></xt>/<xt><aside></xt></code> 295 * element. 296 * 297 * @param session The current serializer session. 298 * @return A boolean flag. 299 */ 300 protected boolean hasAside(HtmlDocSerializerSession session) { 301 return session.getAside().length > 0; 302 } 303 304 /** 305 * Returns <jk>true</jk> if this page should render a <code><xt><body></xt>/<xt><footer></xt></code> 306 * element. 307 * 308 * @param session The current serializer session. 309 * @return A boolean flag. 310 */ 311 protected boolean hasFooter(HtmlDocSerializerSession session) { 312 return session.getFooter().length > 0; 313 } 314 315 private static boolean exists(String s) { 316 return s != null && ! "NONE".equals(s); 317 } 318}