//
// Copyright (c) 2006, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
// 28 May 06 Andy Frank Creation
//
**
** WebOutStream provides methods for generating XML and XHTML content.
**
class WebOutStream : OutStream
{
//////////////////////////////////////////////////////////////////////////
// Factory
//////////////////////////////////////////////////////////////////////////
**
** Construct a WebOutStream that wraps the given OutStream.
**
new make(OutStream out)
: super(out)
{
}
//////////////////////////////////////////////////////////////////////////
// General Methods
//////////////////////////////////////////////////////////////////////////
**
** Convenience for writeChars(obj.toStr).
**
WebOutStream w(Obj obj)
{
writeChars(obj.toStr)
return this
}
**
** Convenience for writeChars(Str.spaces(numSpaces)).
**
WebOutStream tab(Int numSpaces := 2)
{
writeChars(Str.spaces(numSpaces))
return this
}
**
** Convenience for writeChar('\n').
**
WebOutStream nl()
{
writeChar('\n')
return this
}
//////////////////////////////////////////////////////////////////////////
// Xml Methods
//////////////////////////////////////////////////////////////////////////
**
** Write out a prolog statement using the streams
** current charset encoding.
**
WebOutStream prolog()
{
writeChars("<?xml version='1.0' encoding='$charset'?>\n")
return this
}
**
** Write a start tag. Use attrs to fully specify the attributes
** manually. Use empty to optionally close this element without
** using an end tag.
**
WebOutStream tag(Str elemName, Str attrs := null, Bool empty := false)
{
writeChar('<')
writeChars(elemName)
if (attrs != null) writeChar(' ').writeChars(attrs)
if (empty) writeChars(" /")
writeChar('>')
return this
}
**
** Write an end tag.
**
WebOutStream tagEnd(Str elemName)
{
writeChars("</").writeChars(elemName).writeChar('>')
return this
}
//////////////////////////////////////////////////////////////////////////
// DOCTYPE
//////////////////////////////////////////////////////////////////////////
**
** Write the XHTML Strict DOCTYPE.
**
WebOutStream docType()
{
writeChars("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n")
writeChars(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n")
return this
}
//////////////////////////////////////////////////////////////////////////
// html
//////////////////////////////////////////////////////////////////////////
**
** Start a <html> tag.
**
WebOutStream html()
{
return tag("html", "xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'").nl
}
**
** End a <html> tag.
**
WebOutStream htmlEnd()
{
return tagEnd("html").nl
}
//////////////////////////////////////////////////////////////////////////
// head
//////////////////////////////////////////////////////////////////////////
**
** Start a <head> tag.
**
WebOutStream head()
{
return tag("head").nl
}
**
** End a <head> tag.
**
WebOutStream headEnd()
{
return tagEnd("head").nl
}
**
** Write a complete <title> tag.
**
WebOutStream title(Str title)
{
return tag("title").w(title).tagEnd("title").nl
}
**
** Write a complete <link> tag for an external CSS stylesheet.
** If this URI has already been included in this WebOutStream
** instance, then this method does nothing.
**
WebOutStream css(Uri href)
{
if (cssUris == null) cssUris = Uri[,]
if (!cssUris.contains(href))
{
attrs := "rel='stylesheet' type='text/css' href='$href'"
tag("link", attrs, true).nl
cssUris.add(href)
}
return this
}
**
** Write a complete <script> tag for an external JavaScript file.
** If this URI has already been included in this WebOutStream
** instance, then this method does nothing.
**
WebOutStream js(Uri href)
{
if (jsUris == null) jsUris = Uri[,]
if (!jsUris.contains(href))
{
tag("script", "type='text/javascript' src='$href'")
tagEnd("script").nl
jsUris.add(href)
}
return this
}
//////////////////////////////////////////////////////////////////////////
// body
//////////////////////////////////////////////////////////////////////////
**
** Start a <body> tag.
**
WebOutStream body(Str attrs := null)
{
return tag("body", attrs).nl
}
**
** End a <body> tag.
**
WebOutStream bodyEnd()
{
return tagEnd("body").nl
}
//////////////////////////////////////////////////////////////////////////
// h1, h2, h3, h4, h5, h6
//////////////////////////////////////////////////////////////////////////
**
** Write a complete <h1> tag.
**
WebOutStream h1(Str content, Str attrs := null)
{
return tag("h1", attrs).w(content).tagEnd("h1").nl
}
**
** Write a complete <h2> tag.
**
WebOutStream h2(Str content, Str attrs := null)
{
return tag("h2", attrs).w(content).tagEnd("h2").nl
}
**
** Write a complete <h3> tag.
**
WebOutStream h3(Str content, Str attrs := null)
{
return tag("h3", attrs).w(content).tagEnd("h3").nl
}
**
** Write a complete <h4> tag.
**
WebOutStream h4(Str content, Str attrs := null)
{
return tag("h4", attrs).w(content).tagEnd("h4").nl
}
**
** Write a complete <h5> tag.
**
WebOutStream h5(Str content, Str attrs := null)
{
return tag("h5", attrs).w(content).tagEnd("h5").nl
}
**
** Write a complete <h6> tag.
**
WebOutStream h6(Str content, Str attrs := null)
{
return tag("h6", attrs).w(content).tagEnd("h6").nl
}
//////////////////////////////////////////////////////////////////////////
// div
//////////////////////////////////////////////////////////////////////////
**
** Start a <div> tag.
**
WebOutStream div(Str attrs := null)
{
return tag("div", attrs).nl
}
**
** End a <div> tag.
**
WebOutStream divEnd()
{
return tagEnd("div").nl
}
//////////////////////////////////////////////////////////////////////////
// span
//////////////////////////////////////////////////////////////////////////
**
** Start a <span> tag.
**
WebOutStream span(Str attrs := null)
{
return tag("span", attrs)
}
**
** End a <span> tag.
**
WebOutStream spanEnd()
{
return tagEnd("span")
}
//////////////////////////////////////////////////////////////////////////
// p
//////////////////////////////////////////////////////////////////////////
**
** Start a <p> tag.
**
WebOutStream p(Str attrs := null)
{
return tag("p", attrs).nl
}
**
** End a <p> tag.
**
WebOutStream pEnd()
{
return tagEnd("p").nl
}
//////////////////////////////////////////////////////////////////////////
// b
//////////////////////////////////////////////////////////////////////////
**
** Start a <b> tag.
**
WebOutStream b(Str attrs := null)
{
return tag("b", attrs).nl
}
**
** End a <b> tag.
**
WebOutStream bEnd()
{
return tagEnd("b").nl
}
//////////////////////////////////////////////////////////////////////////
// i
//////////////////////////////////////////////////////////////////////////
**
** Start a <i> tag.
**
WebOutStream i(Str attrs := null)
{
return tag("i", attrs).nl
}
**
** End a <i> tag.
**
WebOutStream iEnd()
{
return tagEnd("i").nl
}
//////////////////////////////////////////////////////////////////////////
// em
//////////////////////////////////////////////////////////////////////////
**
** Start a <em> tag.
**
WebOutStream em(Str attrs := null)
{
return tag("em", attrs).nl
}
**
** End a <em> tag.
**
WebOutStream emEnd()
{
return tagEnd("em").nl
}
//////////////////////////////////////////////////////////////////////////
// pre
//////////////////////////////////////////////////////////////////////////
**
** Start a <pre> tag.
**
WebOutStream pre(Str attrs := null)
{
return tag("pre", attrs)
}
**
** End a <pre> tag.
**
WebOutStream preEnd()
{
return tagEnd("pre").nl
}
//////////////////////////////////////////////////////////////////////////
// code
//////////////////////////////////////////////////////////////////////////
**
** Start a <code> tag.
**
WebOutStream code(Str attrs := null)
{
return tag("code", attrs)
}
**
** End a <code> tag.
**
WebOutStream codeEnd()
{
return tagEnd("code")
}
//////////////////////////////////////////////////////////////////////////
// hr
//////////////////////////////////////////////////////////////////////////
**
** Write out a complete <hr/> tag.
**
WebOutStream hr()
{
return tag("hr", null, true).nl
}
//////////////////////////////////////////////////////////////////////////
// br
//////////////////////////////////////////////////////////////////////////
**
** Write out a complete <br/> tag.
**
WebOutStream br()
{
return tag("br", null, true)
}
//////////////////////////////////////////////////////////////////////////
// a
//////////////////////////////////////////////////////////////////////////
**
** Start a <a> tag.
**
WebOutStream a(Uri href, Str attrs := null)
{
return tag("a href='$href'", attrs)
}
**
** End a <a> tag.
**
WebOutStream aEnd()
{
return tagEnd("a")
}
//////////////////////////////////////////////////////////////////////////
// img
//////////////////////////////////////////////////////////////////////////
**
** Write a complete <img> tag.
**
WebOutStream img(Uri src, Str attrs := null)
{
return tag("img src='$src'", attrs, true)
}
//////////////////////////////////////////////////////////////////////////
// table
//////////////////////////////////////////////////////////////////////////
**
** Start a <table> tag.
**
WebOutStream table(Str attrs := null)
{
return tag("table", attrs).nl
}
**
** End a <table> tag.
**
WebOutStream tableEnd()
{
return tagEnd("table").nl
}
//////////////////////////////////////////////////////////////////////////
// tr
//////////////////////////////////////////////////////////////////////////
**
** Start a <tr> tag.
**
WebOutStream tr(Str attrs := null)
{
return tag("tr", attrs).nl
}
**
** End a <tr> tag.
**
WebOutStream trEnd()
{
return tagEnd("tr").nl
}
//////////////////////////////////////////////////////////////////////////
// th
//////////////////////////////////////////////////////////////////////////
**
** Start a <th> tag.
**
WebOutStream th(Str attrs := null)
{
return tag("th", attrs)
}
**
** End a <th> tag.
**
WebOutStream thEnd()
{
return tagEnd("th").nl
}
//////////////////////////////////////////////////////////////////////////
// td
//////////////////////////////////////////////////////////////////////////
**
** Start a <td> tag.
**
WebOutStream td(Str attrs := null)
{
return tag("td", attrs)
}
**
** End a <td> tag.
**
WebOutStream tdEnd()
{
return tagEnd("td").nl
}
//////////////////////////////////////////////////////////////////////////
// ul/ol/li
//////////////////////////////////////////////////////////////////////////
**
** Start a <ul> tag.
**
WebOutStream ul(Str attrs := null)
{
return tag("ul", attrs).nl
}
**
** End a <ul> tag.
**
WebOutStream ulEnd()
{
return tagEnd("ul").nl
}
**
** Start a <ol> tag.
**
WebOutStream ol(Str attrs := null)
{
return tag("ol", attrs).nl
}
**
** End a <ol> tag.
**
WebOutStream olEnd()
{
return tagEnd("ol").nl
}
**
** Start a <li> tag.
**
WebOutStream li(Str attrs := null)
{
return tag("li", attrs).nl
}
**
** End a <li> tag.
**
WebOutStream liEnd()
{
return tagEnd("li").nl
}
//////////////////////////////////////////////////////////////////////////
// dl/dd/dt
//////////////////////////////////////////////////////////////////////////
**
** Start a <dl> tag.
**
WebOutStream dl(Str attrs := null)
{
return tag("dl", attrs).nl
}
**
** End a <dl> tag.
**
WebOutStream dlEnd()
{
return tagEnd("dl").nl
}
**
** Start a <dt> tag.
**
WebOutStream dt(Str attrs := null)
{
return tag("dt", attrs).nl
}
**
** End a <dt> tag.
**
WebOutStream dtEnd()
{
return tagEnd("dt").nl
}
**
** Start a <dd> tag.
**
WebOutStream dd(Str attrs := null)
{
return tag("dd", attrs).nl
}
**
** End a <dd> tag.
**
WebOutStream ddEnd()
{
return tagEnd("dd").nl
}
//////////////////////////////////////////////////////////////////////////
// form
//////////////////////////////////////////////////////////////////////////
**
** Start a <form> tag.
**
WebOutStream form(Str attrs := null)
{
return tag("form", attrs).nl
}
**
** End a <form> tag.
**
WebOutStream formEnd()
{
return tagEnd("form").nl
}
//////////////////////////////////////////////////////////////////////////
// input
//////////////////////////////////////////////////////////////////////////
**
** Write a complete <input> tag.
**
WebOutStream input(Str attrs := null)
{
return tag("input", attrs, true)
}
**
** Convenience for input("type='text'" + attrs).
**
WebOutStream textField(Str attrs := null)
{
return tag("input type='text'", attrs, true)
}
**
** Convenience for input("type='password'" + attrs).
**
WebOutStream password(Str attrs := null)
{
return tag("input type='password'", attrs, true)
}
**
** Convenience for input("type='hidden'" + attrs).
**
WebOutStream hidden(Str attrs := null)
{
return tag("input type='hidden'", attrs, true)
}
**
** Convenience for input("type='button'" + attrs).
**
WebOutStream button(Str attrs := null)
{
return tag("input type='button'", attrs, true)
}
**
** Convenience for input("type='submit'" + attrs).
**
WebOutStream submit(Str attrs := null)
{
return tag("input type='submit'", attrs, true)
}
//////////////////////////////////////////////////////////////////////////
// select
//////////////////////////////////////////////////////////////////////////
**
** Start a <select> tag.
**
WebOutStream select(Str attrs := null)
{
return tag("select", attrs).nl
}
**
** End a <select> tag.
**
WebOutStream selectEnd()
{
return tagEnd("select").nl
}
**
** Start a <option> tag.
**
WebOutStream option(Str attrs := null)
{
return tag("option", attrs)
}
**
** End a <option> tag.
**
WebOutStream optionEnd()
{
return tagEnd("option").nl
}
//////////////////////////////////////////////////////////////////////////
// textarea
//////////////////////////////////////////////////////////////////////////
**
** Start a <textarea> tag.
**
WebOutStream textArea(Str attrs := null)
{
return tag("textarea", attrs).nl
}
**
** End a <textarea> tag.
**
WebOutStream textAreaEnd()
{
return tagEnd("textarea").nl
}
//////////////////////////////////////////////////////////////////////////
// Utils
//////////////////////////////////////////////////////////////////////////
**
** Write 'obj.toStr' to the stream as valid XML text. The
** special control characters amp, lt, apos and quot are
** always escaped. The gt char is escaped only if it is
** the first char or if preceeded by the ']' char. Also
** see `sys::Str.toXml`. If obj is null, then "null" is
** written.
**
WebOutStream esc(Obj obj)
{
if (obj == null) return w("null")
str := obj.toStr
str.each |Int ch, Int i|
{
switch (ch)
{
case '<': writeChars("<")
case '&': writeChars("&")
case '\'': writeChars("'")
case '"': writeChars(""")
case '>':
if (i == 0 || str[i-1] == ']')
writeChars(">")
else
writeChar(ch)
default:
writeChar(ch)
}
}
return this
}
//////////////////////////////////////////////////////////////////////////
// Fields
//////////////////////////////////////////////////////////////////////////
private Uri[] cssUris // what CSS uris have been added
private Uri[] jsUris // what JavaScript uris have been added
}