001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.html;
018
019import static org.apache.juneau.common.utils.StringUtils.*;
020
021import java.io.*;
022
023import org.apache.juneau.*;
024import org.apache.juneau.xml.*;
025
026/**
027 * Specialized writer for serializing HTML.
028 *
029 * <h5 class='section'>See Also:</h5><ul>
030 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HtmlBasics">HTML Basics</a>
031
032 * </ul>
033 */
034public class HtmlWriter extends XmlWriter {
035
036   /**
037    * Constructor.
038    *
039    * @param out The writer being wrapped.
040    * @param useWhitespace If <jk>true</jk>, tabs will be used in output.
041    * @param maxIndent The maximum indentation level.
042    * @param trimStrings If <jk>true</jk>, strings should be trimmed before they're serialized.
043    * @param quoteChar The quote character to use (i.e. <js>'\''</js> or <js>'"'</js>)
044    * @param uriResolver The URI resolver for resolving URIs to absolute or root-relative form.
045    */
046   public HtmlWriter(Writer out, boolean useWhitespace, int maxIndent, boolean trimStrings, char quoteChar,
047         UriResolver uriResolver) {
048      super(out, useWhitespace, maxIndent, trimStrings, quoteChar, uriResolver, false, null);
049   }
050
051   /**
052    * Copy constructor.
053    *
054    * @param w Writer being copied.
055    */
056   public HtmlWriter(HtmlWriter w) {
057      super(w);
058   }
059
060   //-----------------------------------------------------------------------------------------------------------------
061   // Overridden methods
062   //-----------------------------------------------------------------------------------------------------------------
063
064   @Override /* XmlSerializerWriter */
065   public HtmlWriter text(Object o, boolean preserveWhitespace) {
066
067      if (o == null) {
068         append("<null/>");
069         return this;
070      }
071      String s = o.toString();
072      if (s.isEmpty()) {
073         append("<sp/>");
074         return this;
075      }
076
077      for (int i = 0; i < s.length(); i++) {
078         char test = s.charAt(i);
079         if (test == '&')
080            append("&amp;");
081         else if (test == '<')
082            append("&lt;");
083         else if (test == '>')
084            append("&gt;");
085         else if (test == '\n')
086            append(preserveWhitespace ? "\n" : "<br/>");
087         else if (test == '\f')  // XML 1.0 doesn't support form feeds or backslashes, so we have to invent something.
088            append(preserveWhitespace ? "\f" : "<ff/>");
089         else if (test == '\b')
090            append(preserveWhitespace ? "\b" : "<bs/>");
091         else if (test == '\t')
092            append(preserveWhitespace ? "\t" : "<sp>&#x2003;</sp>");
093         else if ((i == 0 || i == s.length()-1) && Character.isWhitespace(test)) {
094            if (preserveWhitespace)
095               w(test);
096            else if (test == ' ')
097               append("<sp> </sp>");
098            else
099               append("<sp>&#x").append(toHex4(test)).append(";</sp>");
100         }
101         else if (Character.isISOControl(test))
102            append("&#" + (int) test + ";");
103         else
104            w(test);
105      }
106
107      return this;
108   }
109
110   @Override /* XmlSerializerWriter */
111   public HtmlWriter oTag(String ns, String name, boolean needsEncoding) {
112      super.oTag(ns, name, needsEncoding);
113      return this;
114   }
115   @Override /* XmlSerializerWriter */
116   public HtmlWriter oTag(String ns, String name) {
117      super.oTag(ns, name);
118      return this;
119   }
120   @Override /* XmlSerializerWriter */
121   public HtmlWriter oTag(String name) {
122      super.oTag(name);
123      return this;
124   }
125   @Override /* XmlSerializerWriter */
126   public HtmlWriter oTag(int indent, String ns, String name, boolean needsEncoding) {
127      super.oTag(indent, ns, name, needsEncoding);
128      return this;
129   }
130   @Override /* XmlSerializerWriter */
131   public HtmlWriter oTag(int indent, String ns, String name) {
132      super.oTag(indent, ns, name);
133      return this;
134   }
135   @Override /* XmlSerializerWriter */
136   public HtmlWriter oTag(int indent, String name) {
137      super.oTag(indent, name);
138      return this;
139   }
140   @Override /* XmlSerializerWriter */
141   public HtmlWriter tag(String ns, String name, boolean needsEncoding) {
142      super.tag(ns, name, needsEncoding);
143      return this;
144   }
145   @Override /* XmlSerializerWriter */
146   public HtmlWriter tag(String ns, String name) {
147      super.tag(ns, name);
148      return this;
149   }
150   @Override /* XmlSerializerWriter */
151   public HtmlWriter tag(String name) {
152      super.tag(name);
153      return this;
154   }
155   @Override /* XmlSerializerWriter */
156   public HtmlWriter tag(int indent, String name) {
157      super.tag(indent, name);
158      return this;
159   }
160   @Override /* XmlSerializerWriter */
161   public HtmlWriter tag(int indent, String ns, String name, boolean needsEncoding) {
162      super.tag(indent, ns, name, needsEncoding);
163      return this;
164   }
165   @Override /* XmlSerializerWriter */
166   public HtmlWriter tag(int indent, String ns, String name) {
167      super.tag(indent, ns, name);
168      return this;
169   }
170   @Override /* XmlSerializerWriter */
171   public HtmlWriter sTag(String ns, String name) {
172      super.sTag(ns, name);
173      return this;
174   }
175   @Override /* XmlSerializerWriter */
176   public HtmlWriter sTag(String ns, String name, boolean needsEncoding) {
177      super.sTag(ns, name, needsEncoding);
178      return this;
179   }
180   @Override /* XmlSerializerWriter */
181   public HtmlWriter sTag(int indent, String ns, String name) {
182      super.sTag(indent, ns, name);
183      return this;
184   }
185   @Override /* XmlSerializerWriter */
186   public HtmlWriter sTag(int indent, String name) {
187      super.sTag(indent, name);
188      return this;
189   }
190   @Override /* XmlSerializerWriter */
191   public HtmlWriter sTag(String name) {
192      super.sTag(name);
193      return this;
194   }
195   @Override /* XmlSerializerWriter */
196   public HtmlWriter sTag(int indent, String ns, String name, boolean needsEncoding) {
197      super.sTag(indent, ns, name, needsEncoding);
198      return this;
199   }
200   @Override /* XmlSerializerWriter */
201   public HtmlWriter eTag(String ns, String name) {
202      super.eTag(ns, name);
203      return this;
204   }
205   @Override /* XmlSerializerWriter */
206   public HtmlWriter eTag(String ns, String name, boolean needsEncoding) {
207      super.eTag(ns, name, needsEncoding);
208      return this;
209   }
210   @Override /* XmlSerializerWriter */
211   public HtmlWriter eTag(int indent, String ns, String name) {
212      super.eTag(indent, ns, name);
213      return this;
214   }
215   @Override /* XmlSerializerWriter */
216   public HtmlWriter eTag(int indent, String name) {
217      super.eTag(indent, name);
218      return this;
219   }
220   @Override /* XmlSerializerWriter */
221   public HtmlWriter eTag(String name) {
222      super.eTag(name);
223      return this;
224   }
225   @Override /* XmlSerializerWriter */
226   public HtmlWriter eTag(int indent, String ns, String name, boolean needsEncoding) {
227      super.eTag(indent, ns, name, needsEncoding);
228      return this;
229   }
230   @Override /* XmlSerializerWriter */
231   public HtmlWriter attr(String name, Object value) {
232      super.attr(name, value);
233      return this;
234   }
235   @Override /* XmlSerializerWriter */
236   public HtmlWriter attr(String ns, String name, Object value) {
237      super.attr(ns, name, value);
238      return this;
239   }
240   @Override /* XmlSerializerWriter */
241   public HtmlWriter attr(String ns, String name, Object value, boolean valNeedsEncoding) {
242      super.attr(ns, name, value, valNeedsEncoding);
243      return this;
244   }
245   @Override /* XmlSerializerWriter */
246   public HtmlWriter attr(String name, Object value, boolean valNeedsEncoding) {
247      super.attr(null, name, value, valNeedsEncoding);
248      return this;
249   }
250   @Override /* XmlSerializerWriter */
251   public HtmlWriter oAttr(String ns, String name) {
252      super.oAttr(ns, name);
253      return this;
254   }
255   @Override /* SerializerWriter */
256   public HtmlWriter cr(int depth) {
257      if (depth > 0)
258         super.cr(depth);
259      return this;
260   }
261   @Override /* SerializerWriter */
262   public HtmlWriter cre(int depth) {
263      if (depth > 0)
264         super.cre(depth);
265      return this;
266   }
267   @Override /* SerializerWriter */
268   public HtmlWriter appendln(int indent, String text) {
269      super.appendln(indent, text);
270      return this;
271   }
272   @Override /* SerializerWriter */
273   public HtmlWriter appendln(String text) {
274      super.appendln(text);
275      return this;
276   }
277   @Override /* SerializerWriter */
278   public HtmlWriter append(int indent, String text) {
279      super.append(indent, text);
280      return this;
281   }
282   @Override /* SerializerWriter */
283   public HtmlWriter append(int indent, char c) {
284      super.append(indent, c);
285      return this;
286   }
287   @Override /* SerializerWriter */
288   public HtmlWriter s() {
289      super.s();
290      return this;
291   }
292   @Override /* SerializerWriter */
293   public HtmlWriter q() {
294      super.q();
295      return this;
296   }
297   @Override /* SerializerWriter */
298   public HtmlWriter i(int indent) {
299      super.i(indent);
300      return this;
301   }
302   @Override /* SerializerWriter */
303   public HtmlWriter nl(int indent) {
304      super.nl(indent);
305      return this;
306   }
307   @Override /* SerializerWriter */
308   public HtmlWriter append(Object text) {
309      super.append(text);
310      return this;
311   }
312   @Override /* SerializerWriter */
313   public HtmlWriter append(String text) {
314      super.append(text);
315      return this;
316   }
317   @Override /* SerializerWriter */
318   public HtmlWriter append(char c) {
319      super.append(c);
320      return this;
321   }
322}