/*
* Copyright (C) 2014 Civilian Framework.
*
* Licensed under the Civilian License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.civilian-framework.org/license.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.civilian.template.mixin;
import org.civilian.Controller;
import org.civilian.Resource;
import org.civilian.Response;
import org.civilian.provider.ApplicationProvider;
import org.civilian.provider.PathProvider;
import org.civilian.provider.ResponseProvider;
import org.civilian.resource.Path;
import org.civilian.resource.Url;
import org.civilian.template.HtmlUtil;
import org.civilian.template.TemplateWriter;
import org.civilian.util.Check;
/**
* HtmlMixin is a template mixin with HTML related methods.
*/
public class HtmlMixin
{
/**
* Creates a new HtmlMixin.
* @param out the TemplateWriter.
*/
public HtmlMixin(TemplateWriter out)
{
this.out = Check.notNull(out, "out");
}
/**
* Prints a link element whose href attribute is the given css path.
* The link element has its rel-attribute set to "stylesheet" and its type attribute
* set to "text/css".
* @param cssPath a path to the css file. The path is automatically
* prefixed by the application path.
*/
public void linkCss(String cssPath)
{
linkCss(cssPath, (String[])null);
}
/**
* Prints a link element like {@link #linkCss(String)} and additionally prints
* a list of attribute names and values given by the attrs parameter.
* @param cssPath a path to the css file. The path is automatically
* prefixed by the {@link #path()} stored in the mixin..
*/
public void linkCss(String cssPath, String... attrs)
{
out.print("<link");
attr("rel", "stylesheet");
attr("type", "text/css");
printPathAttr("href", cssPath);
if (attrs != null)
HtmlUtil.attrs(out, attrs);
out.println(">");
}
/**
* Prints a script element with a src-attribute
* @param src a path to the script file. The path is automatically prefixed by
* the application path.
*/
public void script(String src)
{
script(src, (String[])null);
}
/**
* Same as {@link #script(String)} but additionally prints a
* list of attribute names and values given by the attrs parameter.
*/
public void script(String src, String... attrs)
{
out.print("<script");
printPathAttr("src", src);
if (attrs != null)
HtmlUtil.attrs(out, attrs);
out.println("></script>");
}
/**
* Prints a img element with a src-attribute
* @param src a path to the img file. The path is automatically prefixed by
* the {@link #path()} stored in the mixin.
*/
public void img(String src)
{
img(src, (String[])null);
}
/**
* Same as {@link #img(String)} but additionally prints a
* list of attribute names and values given by the attrs parameter.
*/
public void img(String src, String... attrs)
{
out.print("<img");
printPathAttr("src", src);
if (attrs != null)
HtmlUtil.attrs(out, attrs);
out.println("></img>");
}
/**
* Prints a meta tag with a http-equiv and content attribute.
*/
public void metaHttpEquiv(String httpEquiv, String content)
{
out.print("<meta");
attr("http-equiv", httpEquiv);
attr("content", content);
out.println(">");
}
/**
* Prints a meta tag for the content-type plus encoding of the response.
* @see #metaHttpEquiv(String, String)
* @see Response#getContentTypeAndEncoding()
* @throws IllegalStateException thrown if the TemplateWriter does not
* have a Response as {@link TemplateWriter#getContext(java.lang.Class) context object}
*/
public void metaContentType()
{
String contentType = response().getContentTypeAndEncoding();
if (contentType != null)
metaHttpEquiv("Content-Type", contentType);
}
/**
* Prints a integer attribute.
* The output is: ' ' name '="' value '"'.
*/
public void attr(String name, int value)
{
attr(name, String.valueOf(value), false);
}
/**
* Prints a String attribute.
* The output is: ' ' name '="' escaped-value '"'.
*/
public void attr(String name, String value)
{
attr(name, value, true);
}
/**
* Prints an attribute.
* The output is: ' ' name '="'value '"'.
* @param name the attribute name
* @param value the attribute value
* @param escape should the attribute value be escaped. Only pass false, if you
* know that escaping is not needed.
*/
public void attr(String name, String value, boolean escape)
{
out.print(' ');
out.print(name);
out.print("=\"");
if (value != null)
{
if (escape)
attrValue(value);
else
out.print(value);
}
out.print('"');
}
/**
* Prints an escaped attribute value.
*/
public void attrValue(String value)
{
HtmlUtil.escape(out, value, true);
}
/**
* Prints an escaped text string.
*/
public void text(String text)
{
HtmlUtil.escape(out, text, false);
}
/**
* Prints the text with proper escaping if the text is not null and has
* a non-zero length, else print the defaultValue without escaping.
* Example: out.printText(name, " ");
*/
public void text(String s, String defaultValue)
{
if ((s != null) && (s.length() > 0))
text(s);
else
out.print(defaultValue);
}
private void printPathAttr(String attr, String path)
{
out.print(' ');
out.print(attr);
out.print("=\"");
path(path);
out.print('"');
}
/**
* Returns the path stored in the HtmlMixin.
* This is either the default path or a path previously set
* by #setPath(Path).
* The default path equals the application path if the
* TemplateWriter was initialized from a Civilian response.
* Else the default path is simple the root path.
*/
public Path path()
{
if (path_ == null)
initPath();
return path_;
}
/**
* Lazily init the path.
*/
private void initPath()
{
ApplicationProvider ap = out.getContext(ApplicationProvider.class);
path_ = ap != null ? ap.getApplication().getPath() : Path.ROOT;
}
/**
* Sets the path stored in the HtmlMixin.
* @return this
*/
public HtmlMixin setPath(Path path)
{
Check.notNull(path, "path");
path_ = path;
return this;
}
/**
* Prints the mixin {@link #path()} + the subpath.
*/
public void path(String subPath)
{
path().print(out, subPath);
}
/**
* Prints a JavaScript string which is embedded in a HTML page.
* It escapes \', \n, \r \t and \\ characters and converts
* character which are not printable in the current encoding to
* a HTML character reference. It prints null, if the text is null
* @param text the string
* @param addQuotes adds single quote character around the string if true.
*/
public void jsString(String text, boolean addQuotes)
{
HtmlUtil.jsString(out, text, addQuotes);
}
//-----------------------------
// Urls
//-----------------------------
/**
* Returns a Url object with the resource path.
* @throws IllegalStateException thrown if the TemplateWriter does not
* have a Response as {@link TemplateWriter#getContext(java.lang.Class) context object}
*/
public Url url(Resource resource)
{
return new Url(response(), resource);
}
/**
* Returns a Url object with the path of the resource associated with the controller.
* @throws IllegalStateException thrown if the TemplateWriter does not
* have a Response as {@link TemplateWriter#getContext(java.lang.Class) context object}
*/
public Url url(Class<? extends Controller> controllerClass)
{
return new Url(response(), controllerClass);
}
/**
* Returns a Url with the given value.
* @throws IllegalStateException thrown if the TemplateWriter does not
* have a Response as {@link TemplateWriter#getContext(java.lang.Class) context object}
*/
public Url url(String value)
{
return new Url(response(), value);
}
/**
* Returns a Url with the path of the given path provider.
* @throws IllegalStateException thrown if the TemplateWriter does not
* have a Response as {@link TemplateWriter#getContext(java.lang.Class) context object}
*/
public Url url(PathProvider pp)
{
return new Url(response(), pp);
}
/**
* Returns a Url with the given path.
* @throws IllegalStateException thrown if the TemplateWriter does not
* have a Response as {@link TemplateWriter#getContext(java.lang.Class) context object}
*/
public Url url(Path path)
{
return new Url(response(), path);
}
//-----------------------------
// stacktrace
//-----------------------------
/**
* Prints a stacktrace of the Throwable.
* The stacktrace lines are wrapped in a paragraph element with css class "stacktrace".
*/
public void stackTrace(Throwable t)
{
stackTrace(t, false);
}
/**
* Prints a stacktrace of the Throwable.
* The stacktrace lines are wrapped in a paragraph element with css class "stacktrace".
*/
private void stackTrace(Throwable t, boolean printCausedBy)
{
if (printCausedBy)
out.print("caused by: ");
text(t.toString());
int stLimit = t.getCause() != null ? 3 : 0;
int count = 0;
out.println("<p class=\"stacktrace\">");
for (StackTraceElement ste : t.getStackTrace())
{
text(ste.toString());
out.println("<br>");
if (++count == stLimit)
{
out.println("...<br>");
break;
}
}
out.println("</p>");
if (t.getCause() != null)
stackTrace(t.getCause(), true);
}
//-----------------------------
// helper
//-----------------------------
private Response response()
{
if (response_ == null)
response_ = out.getSafeContext(ResponseProvider.class).getResponse();
return response_;
}
private Response response_;
private TemplateWriter out;
private Path path_;
}