8.4 HtmlProperties, XHTML and HTML5
Lift unifies many aspects of parsing and displaying the HTML page in a single trait, HtmlProperties.
HtmlProperties defines, on a session-by-session (and even a request-by-request) basis, the way that templates are parsed and the way that Scala’s NodeSeq is converted into valid HTML output. The properties on HtmlProperties are:
-
docType - the DocType for the HTML page, e.g., <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> or <!DOCTYPE html>
-
encoding - the page’s encoding, e.g., <?xml version="1.0" encoding="UTF-8"?>
-
contentType - the setting of the Content-Type response header, e.g., application/xhtml+xml; charset=utf-8 or text/html; charset=utf-8
-
htmlOutputHeader - calculates the way to combine the docType and encoding (this is important for IE6 support where encoding goes after docType).
-
htmlParser - a function that converts an InputStream to a Box[NodeSeq]. This is used by Lift to parse templates.
-
htmlWriter - a function that writes a NodeSeq to a Writer. This is used by Lift to convert the internal XML representation of a page to a stream of bytes representing an HTML page.
-
html5FormsSupport - a flag indicating whether the current browser supports HTML5 forms.
-
maxOpenRequests - the maximum number of concurrent HTTP requests the browser supports to a named host.
-
userAgent - the User-Agent string sent from the browser.
8.4.1 XHTML via OldHtmlProperties
The default properties that keep compability with the disparate LiftRules used to calculate DocType and Encoding. Uses the PCDataXmlParser parser which requires well-formed XML files. Output is generally XHTML via AltXML.toXML, but cerain tags (e.g., <br>) are written in IE6/IE7 friendly ways.
8.4.2 HTML5 via Html5Properties
Prior to Lift 2.2, Lift always emitted XHTML and by default set the Content-Type header to application/xhtml+xml; charset=utf-8. This continues to be Lift’s default behavior. It turns out that most browsers, even modern ones (Firefox, Chrome and Safari) had issues with XHTML. Further, XHTML limited the behavior of certain JavaScript libraries.
By invoking
LiftRules.htmlProperties.default.set((r: Req) => new Html5Properties(r.userAgent)) in Boot.scala, you can set Lift to full HTML5 support. Lift uses the
nu.validator HTML parser and emits the correct DocType and response headers such that all tested browsers (IE6+, Firefox 2+, Safari 2+, Chrome 1+) render pages correctly.
Because the HTML5 parser is different from the standard XML parser, you will need to adjust your existing templates in the following ways:
-
All tags are converted to lower case. This means the <lift:FooBar/> gets converted to <lift:foobar/> I advise converting to designer friendly where possible (e.g., <div class="lift:FooBar"></div>).
-
Tags of the format <div/> and <my_thing:bind/> are not legal. They must be converted to <div></div> and <my_thing:bind></my_thing:bind>. Unfortunately, the parser is very forgiving so rather than barking about the lack of closing tag, the parser will nest things in unexpected ways.
-
There are some tags that the parser "ensures". For example a <tr>, <thead>, or <tbody> tag must be the first tag inside <table>. This breaks the
<table><mysnippet:line>
<tr><td><mysnippet:bind_here></mysnippet:bind_here></td></tr>
</mysnippet:line><table>
paradigm. You can get the desired behavior with
<table><tr lift:bind="mysnippet:line"><td><mysnippet:bind_here></mysnippet:bind_here></td></tr><table>.
8.4.3 Changing behavior mid-session or mid-request
You can change the behavior of HtmlProperties mid-session or mid-request. LiftSession.sessionHtmlProperties is a SessionVar that contains the HtmlProperties for the session. LiftSession.requestHtmlProperties is a TranientRequestVar containing the HtmlProperties for the request. At the begining of the request, requestHtmlProperties is set to the value of sessionHtmlProperties. You can alter a property for the duration of the request using:
for {
session <- S.session
} session.requestHtmlProperties.set(session.
requestHtmlProperties.is.setDocType(() =>
Full("<!DOCTYPE moose>")))
(C) 2012 David Pollak