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, session.resolve(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 int i = 0; 073 for (String s : session.getStylesheet()) 074 w.sIf(i++ > 0).append(3, "@import ").q().append(session.resolveUri(session.resolve(s))).q().appendln(";"); 075 if (session.isNowrap()) 076 w.appendln(3, "div.data * {white-space:nowrap;} "); 077 for (String s : session.getStyle()) 078 w.sIf(i++ > 0).appendln(3, session.resolve(s)); 079 for (HtmlWidget hw : session.getWidgets()) 080 w.sIf(i++ > 0).appendln(3, session.resolve(hw.getStyle(session.getVarResolver()))); 081 } 082 083 /** 084 * Renders the contents of the <code><xt><head></xt>/<xt><script></xt></code> element. 085 * 086 * @param session The current serializer session. 087 * @param w The writer being written to. 088 * @param o The object being serialized. 089 * @throws Exception Any exception can be thrown. 090 */ 091 protected void script(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 092 int i = 0; 093 for (String s : session.getScript()) 094 w.sIf(i++ > 0).append(3, session.resolve(s)).append('\n'); // Must always append a newline even if whitespace disabled! 095 for (HtmlWidget hw : session.getWidgets()) 096 w.sIf(i++ > 0).append(3, session.resolve(hw.getScript(session.getVarResolver()))).append('\n'); // Must always append a newline even if whitespace disabled! 097 } 098 099 /** 100 * Renders the contents of the <code><xt><body></xt></code> element. 101 * 102 * @param session The current serializer session. 103 * @param w The writer being written to. 104 * @param o The object being serialized. 105 * @throws Exception Any exception can be thrown. 106 */ 107 protected void body(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 108 109 if (hasHeader(session)) { 110 w.sTag(2, "header").nl(2); 111 header(session, w, o); 112 w.ie(2).eTag("header").nl(2); 113 } 114 115 if (hasNav(session)) { 116 w.sTag(2, "nav").nl(2); 117 nav(session, w, o); 118 w.ie(2).eTag("nav").nl(2); 119 } 120 121 w.sTag(2, "section").nl(2); 122 123 w.sTag(3, "article").nl(3); 124 article(session, w, o); 125 w.ie(3).eTag("article").nl(3); 126 127 if (hasAside(session)) { 128 w.sTag(3, "aside").nl(3); 129 aside(session, w, o); 130 w.ie(3).eTag("aside").nl(3); 131 } 132 133 w.ie(2).eTag("section").nl(2); 134 135 if (hasFooter(session)) { 136 w.sTag(2, "footer").nl(2); 137 footer(session, w, o); 138 w.ie(2).eTag("footer").nl(2); 139 } 140 } 141 142 /** 143 * Renders the contents of the <code><xt><body></xt>/<xt><header></xt></code> element. 144 * 145 * @param session The current serializer session. 146 * @param w The writer being written to. 147 * @param o The object being serialized. 148 * @throws Exception Any exception can be thrown. 149 */ 150 protected void header(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 151 // Write the title of the page. 152 String[] header = session.getHeader(); 153 for (int i = 0; i < header.length; i++) 154 w.sIf(i > 0).appendln(3, session.resolve(header[i])); 155 } 156 157 /** 158 * Renders the contents of the <code><xt><body></xt>/<xt><nav></xt></code> element. 159 * 160 * @param session The current serializer session. 161 * @param w The writer being written to. 162 * @param o The object being serialized. 163 * @throws Exception Any exception can be thrown. 164 */ 165 protected void nav(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 166 String[] links = session.getNavLinks(); 167 if (links.length > 0 && ! ArrayUtils.contains("NONE", links)) { 168 w.sTag(3, "ol").nl(3); 169 for (String l : links) { 170 w.sTag(4, "li"); 171 l = session.resolve(l); 172 if (l.matches("(?s)\\S+\\:.*")) { 173 int i = l.indexOf(':'); 174 String key = l.substring(0, i); 175 String val = l.substring(i+1).trim(); 176 if (val.startsWith("<")) 177 w.nl(4).appendln(5, val); 178 else 179 w.oTag("a").attr("href", session.resolveUri(val), true).cTag().text(key, true).eTag("a"); 180 w.eTag("li").nl(4); 181 } else { 182 w.nl(4).appendln(5, l); 183 w.eTag(4, "li").nl(4); 184 } 185 } 186 w.eTag(3, "ol").nl(3); 187 } 188 String[] nav = session.getNav(); 189 if (nav.length > 0) { 190 for (int i = 0; i < nav.length; i++) 191 w.sIf(i > 0).appendln(3, session.resolve(nav[i])); 192 } 193 } 194 195 /** 196 * Renders the contents of the <code><xt><body></xt>/<xt><aside></xt></code> element. 197 * 198 * @param session The current serializer session. 199 * @param w The writer being written to. 200 * @param o The object being serialized. 201 * @throws Exception Any exception can be thrown. 202 */ 203 protected void aside(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 204 String[] aside = session.getAside(); 205 for (int i = 0; i < aside.length; i++) 206 w.sIf(i > 0).appendln(4, session.resolve(aside[i])); 207 } 208 209 /** 210 * Renders the contents of the <code><xt><body></xt>/<xt><article></xt></code> element. 211 * 212 * @param session The current serializer session. 213 * @param w The writer being written to. 214 * @param o The object being serialized. 215 * @throws Exception Any exception can be thrown. 216 */ 217 protected void article(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 218 // To allow for page formatting using CSS, we encapsulate the data inside two div tags: 219 // <div class='outerdata'><div class='data' id='data'>...</div></div> 220 w.oTag(4, "div").attr("class","outerdata").append('>').nl(4); 221 w.oTag(5, "div").attr("class","data").attr("id", "data").append('>').nl(5); 222 223 if (o == null) { 224 w.append(6, "<null/>").nl(6); 225 } else if (ObjectUtils.isEmpty(o)){ 226 String m = session.getNoResultsMessage(); 227 if (exists(m)) 228 w.append(6, session.resolve(m)).nl(6); 229 } else { 230 session.indent = 6; 231 w.flush(); 232 session.parentSerialize(w, o); 233 } 234 235 w.ie(5).eTag("div").nl(5); 236 w.ie(4).eTag("div").nl(4); 237 } 238 239 /** 240 * Renders the contents of the <code><xt><body></xt>/<xt><footer></xt></code> element. 241 * 242 * @param session The current serializer session. 243 * @param w The writer being written to. 244 * @param o The object being serialized. 245 * @throws Exception Any exception can be thrown. 246 */ 247 protected void footer(HtmlDocSerializerSession session, HtmlWriter w, Object o) throws Exception { 248 String[] footer = session.getFooter(); 249 for (int i = 0; i < footer.length; i++) 250 w.sIf(i > 0).appendln(3, session.resolve(footer[i])); 251 } 252 253 /** 254 * Returns <jk>true</jk> if this page should render a <code><xt><head></xt>/<xt><style></xt></code> element. 255 * 256 * @param session The current serializer session. 257 * @return A boolean flag. 258 */ 259 protected boolean hasStyle(HtmlDocSerializerSession session) { 260 return true; 261 } 262 263 /** 264 * Returns <jk>true</jk> if this page should render a <code><xt><head></xt>/<xt><script></xt></code> element. 265 * 266 * @param session The current serializer session. 267 * @return A boolean flag. 268 */ 269 protected boolean hasScript(HtmlDocSerializerSession session) { 270 return true; 271 } 272 273 /** 274 * Returns <jk>true</jk> if this page should render a <code><xt><body></xt>/<xt><header></xt></code> 275 * element. 276 * 277 * @param session The current serializer session. 278 * @return A boolean flag. 279 */ 280 protected boolean hasHeader(HtmlDocSerializerSession session) { 281 return session.getHeader().length > 0; 282 } 283 284 /** 285 * Returns <jk>true</jk> if this page should render a <code><xt><body></xt>/<xt><nav></xt></code> 286 * element. 287 * 288 * @param session The current serializer session. 289 * @return A boolean flag. 290 */ 291 protected boolean hasNav(HtmlDocSerializerSession session) { 292 return session.getNav().length > 0 || session.getNavLinks().length > 0; 293 } 294 295 /** 296 * Returns <jk>true</jk> if this page should render a <code><xt><body></xt>/<xt><aside></xt></code> 297 * element. 298 * 299 * @param session The current serializer session. 300 * @return A boolean flag. 301 */ 302 protected boolean hasAside(HtmlDocSerializerSession session) { 303 return session.getAside().length > 0; 304 } 305 306 /** 307 * Returns <jk>true</jk> if this page should render a <code><xt><body></xt>/<xt><footer></xt></code> 308 * element. 309 * 310 * @param session The current serializer session. 311 * @return A boolean flag. 312 */ 313 protected boolean hasFooter(HtmlDocSerializerSession session) { 314 return session.getFooter().length > 0; 315 } 316 317 private static boolean exists(String s) { 318 return s != null && ! "NONE".equals(s); 319 } 320}