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.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 */
025public class HtmlWriter extends XmlWriter {
026
027   /**
028    * Constructor.
029    * 
030    * @param out The writer being wrapped.
031    * @param useWhitespace If <jk>true</jk>, tabs will be used in output.
032    * @param maxIndent The maximum indentation level.
033    * @param trimStrings If <jk>true</jk>, strings should be trimmed before they're serialized.
034    * @param quoteChar The quote character to use (i.e. <js>'\''</js> or <js>'"'</js>)
035    * @param uriResolver The URI resolver for resolving URIs to absolute or root-relative form.
036    */
037   public HtmlWriter(Writer out, boolean useWhitespace, int maxIndent, boolean trimStrings, char quoteChar,
038         UriResolver uriResolver) {
039      super(out, useWhitespace, maxIndent, trimStrings, quoteChar, uriResolver, false, null);
040   }
041
042   /**
043    * Append an attribute with a URI value.
044    * 
045    * @param name The attribute name.
046    * @param value The attribute value.  Can be any object whose <code>toString()</code> method returns a URI.
047    * @return This object (for method chaining);
048    * @throws IOException If a problem occurred.
049    */
050   public HtmlWriter attrUri(String name, Object value) throws IOException {
051      super.attrUri((String)null, name, value);
052      return this;
053   }
054
055
056   //--------------------------------------------------------------------------------
057   // Overridden methods
058   //--------------------------------------------------------------------------------
059
060   @Override /* XmlSerializerWriter */
061   public HtmlWriter text(Object o, boolean preserveWhitespace) throws IOException {
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 formfeeds 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               append(test);
092            else if (test == ' ')
093               append("<sp> </sp>");
094            else
095               append("<sp>&#x").append(toHex(test)).append(";</sp>");
096         }
097         else if (Character.isISOControl(test))
098            append("&#" + (int) test + ";");
099         else
100            append(test);
101      }
102
103      return this;
104   }
105
106   @Override /* XmlSerializerWriter */
107   public HtmlWriter oTag(String ns, String name, boolean needsEncoding) throws IOException {
108      super.oTag(ns, name, needsEncoding);
109      return this;
110   }
111
112   @Override /* XmlSerializerWriter */
113   public HtmlWriter oTag(String ns, String name) throws IOException {
114      super.oTag(ns, name);
115      return this;
116   }
117
118   @Override /* XmlSerializerWriter */
119   public HtmlWriter oTag(String name) throws IOException {
120      super.oTag(name);
121      return this;
122   }
123
124   @Override /* XmlSerializerWriter */
125   public HtmlWriter oTag(int indent, String ns, String name, boolean needsEncoding) throws IOException {
126      super.oTag(indent, ns, name, needsEncoding);
127      return this;
128   }
129
130   @Override /* XmlSerializerWriter */
131   public HtmlWriter oTag(int indent, String ns, String name) throws IOException {
132      super.oTag(indent, ns, name);
133      return this;
134   }
135
136   @Override /* XmlSerializerWriter */
137   public HtmlWriter oTag(int indent, String name) throws IOException {
138      super.oTag(indent, name);
139      return this;
140   }
141
142   @Override /* XmlSerializerWriter */
143   public HtmlWriter tag(String ns, String name, boolean needsEncoding) throws IOException {
144      super.tag(ns, name, needsEncoding);
145      return this;
146   }
147
148   @Override /* XmlSerializerWriter */
149   public HtmlWriter tag(String ns, String name) throws IOException {
150      super.tag(ns, name);
151      return this;
152   }
153
154   @Override /* XmlSerializerWriter */
155   public HtmlWriter tag(String name) throws IOException {
156      super.tag(name);
157      return this;
158   }
159
160   @Override /* XmlSerializerWriter */
161   public HtmlWriter tag(int indent, String name) throws IOException {
162      super.tag(indent, name);
163      return this;
164   }
165
166   @Override /* XmlSerializerWriter */
167   public HtmlWriter tag(int indent, String ns, String name, boolean needsEncoding) throws IOException {
168      super.tag(indent, ns, name, needsEncoding);
169      return this;
170   }
171
172   @Override /* XmlSerializerWriter */
173   public HtmlWriter tag(int indent, String ns, String name) throws IOException {
174      super.tag(indent, ns, name);
175      return this;
176   }
177
178   @Override /* XmlSerializerWriter */
179   public HtmlWriter sTag(String ns, String name) throws IOException {
180      super.sTag(ns, name);
181      return this;
182   }
183
184   @Override /* XmlSerializerWriter */
185   public HtmlWriter sTag(String ns, String name, boolean needsEncoding) throws IOException {
186      super.sTag(ns, name, needsEncoding);
187      return this;
188   }
189
190   @Override /* XmlSerializerWriter */
191   public HtmlWriter sTag(int indent, String ns, String name) throws IOException {
192      super.sTag(indent, ns, name);
193      return this;
194   }
195
196   @Override /* XmlSerializerWriter */
197   public HtmlWriter sTag(int indent, String name) throws IOException {
198      super.sTag(indent, name);
199      return this;
200   }
201
202   @Override /* XmlSerializerWriter */
203   public HtmlWriter sTag(String name) throws IOException {
204      super.sTag(name);
205      return this;
206   }
207
208   @Override /* XmlSerializerWriter */
209   public HtmlWriter sTag(int indent, String ns, String name, boolean needsEncoding) throws IOException {
210      super.sTag(indent, ns, name, needsEncoding);
211      return this;
212   }
213
214   @Override /* XmlSerializerWriter */
215   public HtmlWriter eTag(String ns, String name) throws IOException {
216      super.eTag(ns, name);
217      return this;
218   }
219
220   @Override /* XmlSerializerWriter */
221   public HtmlWriter eTag(String ns, String name, boolean needsEncoding) throws IOException {
222      super.eTag(ns, name, needsEncoding);
223      return this;
224   }
225
226   @Override /* XmlSerializerWriter */
227   public HtmlWriter eTag(int indent, String ns, String name) throws IOException {
228      super.eTag(indent, ns, name);
229      return this;
230   }
231
232   @Override /* XmlSerializerWriter */
233   public HtmlWriter eTag(int indent, String name) throws IOException {
234      super.eTag(indent, name);
235      return this;
236   }
237
238   @Override /* XmlSerializerWriter */
239   public HtmlWriter eTag(String name) throws IOException {
240      super.eTag(name);
241      return this;
242   }
243
244   @Override /* XmlSerializerWriter */
245   public HtmlWriter eTag(int indent, String ns, String name, boolean needsEncoding) throws IOException {
246      super.eTag(indent, ns, name, needsEncoding);
247      return this;
248   }
249
250   @Override /* XmlSerializerWriter */
251   public HtmlWriter attr(String name, Object value) throws IOException {
252      super.attr(name, value);
253      return this;
254   }
255
256   @Override /* XmlSerializerWriter */
257   public HtmlWriter attr(String ns, String name, Object value) throws IOException {
258      super.attr(ns, name, value);
259      return this;
260   }
261
262   @Override /* XmlSerializerWriter */
263   public HtmlWriter attr(String ns, String name, Object value, boolean valNeedsEncoding) throws IOException {
264      super.attr(ns, name, value, valNeedsEncoding);
265      return this;
266   }
267
268   @Override /* XmlSerializerWriter */
269   public HtmlWriter attr(String name, Object value, boolean valNeedsEncoding) throws IOException {
270      super.attr(null, name, value, valNeedsEncoding);
271      return this;
272   }
273
274   @Override /* XmlSerializerWriter */
275   public HtmlWriter oAttr(String ns, String name) throws IOException {
276      super.oAttr(ns, name);
277      return this;
278   }
279
280   @Override /* SerializerWriter */
281   public HtmlWriter cr(int depth) throws IOException {
282      if (depth > 0)
283         super.cr(depth);
284      return this;
285   }
286
287   @Override /* SerializerWriter */
288   public HtmlWriter cre(int depth) throws IOException {
289      if (depth > 0)
290         super.cre(depth);
291      return this;
292   }
293
294   @Override /* SerializerWriter */
295   public HtmlWriter appendln(int indent, String text) throws IOException {
296      super.appendln(indent, text);
297      return this;
298   }
299
300   @Override /* SerializerWriter */
301   public HtmlWriter appendln(String text) throws IOException {
302      super.appendln(text);
303      return this;
304   }
305
306   @Override /* SerializerWriter */
307   public HtmlWriter append(int indent, String text) throws IOException {
308      super.append(indent, text);
309      return this;
310   }
311
312   @Override /* SerializerWriter */
313   public HtmlWriter append(int indent, char c) throws IOException {
314      super.append(indent, c);
315      return this;
316   }
317
318   @Override /* SerializerWriter */
319   public HtmlWriter s() throws IOException {
320      super.s();
321      return this;
322   }
323
324   @Override /* SerializerWriter */
325   public HtmlWriter q() throws IOException {
326      super.q();
327      return this;
328   }
329
330   @Override /* SerializerWriter */
331   public HtmlWriter i(int indent) throws IOException {
332      super.i(indent);
333      return this;
334   }
335
336   @Override /* SerializerWriter */
337   public HtmlWriter nl(int indent) throws IOException {
338      super.nl(indent);
339      return this;
340   }
341
342   @Override /* SerializerWriter */
343   public HtmlWriter append(Object text) throws IOException {
344      super.append(text);
345      return this;
346   }
347
348   @Override /* SerializerWriter */
349   public HtmlWriter append(String text) throws IOException {
350      super.append(text);
351      return this;
352   }
353
354   @Override /* SerializerWriter */
355   public HtmlWriter append(char c) throws IOException {
356      super.append(c);
357      return this;
358   }
359}