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 static org.apache.juneau.common.internal.StringUtils.*;
016
017import java.io.*;
018
019import org.apache.juneau.*;
020import org.apache.juneau.xml.*;
021
022/**
023 * Specialized writer for serializing HTML.
024 *
025 * <h5 class='section'>See Also:</h5><ul>
026 *    <li class='link'><a class="doclink" href="../../../../index.html#jm.HtmlDetails">HTML Details</a>
027
028 * </ul>
029 */
030public class HtmlWriter extends XmlWriter {
031
032   /**
033    * Constructor.
034    *
035    * @param out The writer being wrapped.
036    * @param useWhitespace If <jk>true</jk>, tabs will be used in output.
037    * @param maxIndent The maximum indentation level.
038    * @param trimStrings If <jk>true</jk>, strings should be trimmed before they're serialized.
039    * @param quoteChar The quote character to use (i.e. <js>'\''</js> or <js>'"'</js>)
040    * @param uriResolver The URI resolver for resolving URIs to absolute or root-relative form.
041    */
042   public HtmlWriter(Writer out, boolean useWhitespace, int maxIndent, boolean trimStrings, char quoteChar,
043         UriResolver uriResolver) {
044      super(out, useWhitespace, maxIndent, trimStrings, quoteChar, uriResolver, false, null);
045   }
046
047   /**
048    * Copy constructor.
049    *
050    * @param w Writer being copied.
051    */
052   public HtmlWriter(HtmlWriter w) {
053      super(w);
054   }
055
056   //-----------------------------------------------------------------------------------------------------------------
057   // Overridden methods
058   //-----------------------------------------------------------------------------------------------------------------
059
060   @Override /* XmlSerializerWriter */
061   public HtmlWriter text(Object o, boolean preserveWhitespace) {
062
063      if (o == null) {
064         append("<null/>");
065         return this;
066      }
067      String s = o.toString();
068      if (s.isEmpty()) {
069         append("<sp/>");
070         return this;
071      }
072
073      for (int i = 0; i < s.length(); i++) {
074         char test = s.charAt(i);
075         if (test == '&')
076            append("&amp;");
077         else if (test == '<')
078            append("&lt;");
079         else if (test == '>')
080            append("&gt;");
081         else if (test == '\n')
082            append(preserveWhitespace ? "\n" : "<br/>");
083         else if (test == '\f')  // XML 1.0 doesn't support form feeds or backslashes, so we have to invent something.
084            append(preserveWhitespace ? "\f" : "<ff/>");
085         else if (test == '\b')
086            append(preserveWhitespace ? "\b" : "<bs/>");
087         else if (test == '\t')
088            append(preserveWhitespace ? "\t" : "<sp>&#x2003;</sp>");
089         else if ((i == 0 || i == s.length()-1) && Character.isWhitespace(test)) {
090            if (preserveWhitespace)
091               w(test);
092            else if (test == ' ')
093               append("<sp> </sp>");
094            else
095               append("<sp>&#x").append(toHex4(test)).append(";</sp>");
096         }
097         else if (Character.isISOControl(test))
098            append("&#" + (int) test + ";");
099         else
100            w(test);
101      }
102
103      return this;
104   }
105
106   // <FluentSetters>
107
108   @Override /* XmlSerializerWriter */
109   public HtmlWriter oTag(String ns, String name, boolean needsEncoding) {
110      super.oTag(ns, name, needsEncoding);
111      return this;
112   }
113
114   @Override /* XmlSerializerWriter */
115   public HtmlWriter oTag(String ns, String name) {
116      super.oTag(ns, name);
117      return this;
118   }
119
120   @Override /* XmlSerializerWriter */
121   public HtmlWriter oTag(String name) {
122      super.oTag(name);
123      return this;
124   }
125
126   @Override /* XmlSerializerWriter */
127   public HtmlWriter oTag(int indent, String ns, String name, boolean needsEncoding) {
128      super.oTag(indent, ns, name, needsEncoding);
129      return this;
130   }
131
132   @Override /* XmlSerializerWriter */
133   public HtmlWriter oTag(int indent, String ns, String name) {
134      super.oTag(indent, ns, name);
135      return this;
136   }
137
138   @Override /* XmlSerializerWriter */
139   public HtmlWriter oTag(int indent, String name) {
140      super.oTag(indent, name);
141      return this;
142   }
143
144   @Override /* XmlSerializerWriter */
145   public HtmlWriter tag(String ns, String name, boolean needsEncoding) {
146      super.tag(ns, name, needsEncoding);
147      return this;
148   }
149
150   @Override /* XmlSerializerWriter */
151   public HtmlWriter tag(String ns, String name) {
152      super.tag(ns, name);
153      return this;
154   }
155
156   @Override /* XmlSerializerWriter */
157   public HtmlWriter tag(String name) {
158      super.tag(name);
159      return this;
160   }
161
162   @Override /* XmlSerializerWriter */
163   public HtmlWriter tag(int indent, String name) {
164      super.tag(indent, name);
165      return this;
166   }
167
168   @Override /* XmlSerializerWriter */
169   public HtmlWriter tag(int indent, String ns, String name, boolean needsEncoding) {
170      super.tag(indent, ns, name, needsEncoding);
171      return this;
172   }
173
174   @Override /* XmlSerializerWriter */
175   public HtmlWriter tag(int indent, String ns, String name) {
176      super.tag(indent, ns, name);
177      return this;
178   }
179
180   @Override /* XmlSerializerWriter */
181   public HtmlWriter sTag(String ns, String name) {
182      super.sTag(ns, name);
183      return this;
184   }
185
186   @Override /* XmlSerializerWriter */
187   public HtmlWriter sTag(String ns, String name, boolean needsEncoding) {
188      super.sTag(ns, name, needsEncoding);
189      return this;
190   }
191
192   @Override /* XmlSerializerWriter */
193   public HtmlWriter sTag(int indent, String ns, String name) {
194      super.sTag(indent, ns, name);
195      return this;
196   }
197
198   @Override /* XmlSerializerWriter */
199   public HtmlWriter sTag(int indent, String name) {
200      super.sTag(indent, name);
201      return this;
202   }
203
204   @Override /* XmlSerializerWriter */
205   public HtmlWriter sTag(String name) {
206      super.sTag(name);
207      return this;
208   }
209
210   @Override /* XmlSerializerWriter */
211   public HtmlWriter sTag(int indent, String ns, String name, boolean needsEncoding) {
212      super.sTag(indent, ns, name, needsEncoding);
213      return this;
214   }
215
216   @Override /* XmlSerializerWriter */
217   public HtmlWriter eTag(String ns, String name) {
218      super.eTag(ns, name);
219      return this;
220   }
221
222   @Override /* XmlSerializerWriter */
223   public HtmlWriter eTag(String ns, String name, boolean needsEncoding) {
224      super.eTag(ns, name, needsEncoding);
225      return this;
226   }
227
228   @Override /* XmlSerializerWriter */
229   public HtmlWriter eTag(int indent, String ns, String name) {
230      super.eTag(indent, ns, name);
231      return this;
232   }
233
234   @Override /* XmlSerializerWriter */
235   public HtmlWriter eTag(int indent, String name) {
236      super.eTag(indent, name);
237      return this;
238   }
239
240   @Override /* XmlSerializerWriter */
241   public HtmlWriter eTag(String name) {
242      super.eTag(name);
243      return this;
244   }
245
246   @Override /* XmlSerializerWriter */
247   public HtmlWriter eTag(int indent, String ns, String name, boolean needsEncoding) {
248      super.eTag(indent, ns, name, needsEncoding);
249      return this;
250   }
251
252   @Override /* XmlSerializerWriter */
253   public HtmlWriter attr(String name, Object value) {
254      super.attr(name, value);
255      return this;
256   }
257
258   @Override /* XmlSerializerWriter */
259   public HtmlWriter attr(String ns, String name, Object value) {
260      super.attr(ns, name, value);
261      return this;
262   }
263
264   @Override /* XmlSerializerWriter */
265   public HtmlWriter attr(String ns, String name, Object value, boolean valNeedsEncoding) {
266      super.attr(ns, name, value, valNeedsEncoding);
267      return this;
268   }
269
270   @Override /* XmlSerializerWriter */
271   public HtmlWriter attr(String name, Object value, boolean valNeedsEncoding) {
272      super.attr(null, name, value, valNeedsEncoding);
273      return this;
274   }
275
276   @Override /* XmlSerializerWriter */
277   public HtmlWriter oAttr(String ns, String name) {
278      super.oAttr(ns, name);
279      return this;
280   }
281
282   @Override /* SerializerWriter */
283   public HtmlWriter cr(int depth) {
284      if (depth > 0)
285         super.cr(depth);
286      return this;
287   }
288
289   @Override /* SerializerWriter */
290   public HtmlWriter cre(int depth) {
291      if (depth > 0)
292         super.cre(depth);
293      return this;
294   }
295
296   @Override /* SerializerWriter */
297   public HtmlWriter appendln(int indent, String text) {
298      super.appendln(indent, text);
299      return this;
300   }
301
302   @Override /* SerializerWriter */
303   public HtmlWriter appendln(String text) {
304      super.appendln(text);
305      return this;
306   }
307
308   @Override /* SerializerWriter */
309   public HtmlWriter append(int indent, String text) {
310      super.append(indent, text);
311      return this;
312   }
313
314   @Override /* SerializerWriter */
315   public HtmlWriter append(int indent, char c) {
316      super.append(indent, c);
317      return this;
318   }
319
320   @Override /* SerializerWriter */
321   public HtmlWriter s() {
322      super.s();
323      return this;
324   }
325
326   @Override /* SerializerWriter */
327   public HtmlWriter q() {
328      super.q();
329      return this;
330   }
331
332   @Override /* SerializerWriter */
333   public HtmlWriter i(int indent) {
334      super.i(indent);
335      return this;
336   }
337
338   @Override /* SerializerWriter */
339   public HtmlWriter nl(int indent) {
340      super.nl(indent);
341      return this;
342   }
343
344   @Override /* SerializerWriter */
345   public HtmlWriter append(Object text) {
346      super.append(text);
347      return this;
348   }
349
350   @Override /* SerializerWriter */
351   public HtmlWriter append(String text) {
352      super.append(text);
353      return this;
354   }
355
356   @Override /* SerializerWriter */
357   public HtmlWriter append(char c) {
358      super.append(c);
359      return this;
360   }
361
362   // </FluentSetters>
363}