Providing Theme Resources"
m |
m ((via JWB)) |
||
(15 intermediate revisions by 4 users not shown) | |||
Line 3: | Line 3: | ||
__TOC__ | __TOC__ | ||
− | + | = ThemeProvider= | |
+ | After switching to another theme, a <javadoc type="interface">org.zkoss.zk.ui.util.ThemeProvider</javadoc> allows you the full control of CSS styling, including but not limited to | ||
− | * | + | * Switch among multiple sets of stylesheets based on, say, the user's preference, cookie, locale, or others |
− | * Replace the CSS styling of | + | * Replace the CSS styling of component(s) with your own custom styling |
− | * | + | * Inject additional CSS files |
− | We illustrate the theme provider with two examples. One is straightforward: set the corresponding attributes based on the cookie. The other '''injects''' a fragment to the URI such that we can allow the browser to cache the CSS file. | + | {{versionSince| 6.5.2}} |
+ | |||
+ | Standard implementations of ThemeProvider are available for each of ZK editions (CE, PE, and EE). | ||
+ | |||
+ | {| class='wikitable' | width="100%" | ||
+ | ! Edition !! ThemeProvider | ||
+ | |- | ||
+ | | ZK CE | ||
+ | | [http://www.zkoss.org/javadoc/latest/zk/org/zkoss/zul/theme/StandardThemeProvider.html org.zkoss.zul.theme.StandardThemeProvider] | ||
+ | |- | ||
+ | | ZK PE | ||
+ | | [http://www.zkoss.org/javadoc/latest/zk/org/zkoss/zkex/theme/StandardThemeProvider.html org.zkoss.zkex.theme.StandardThemeProvider] | ||
+ | |- | ||
+ | | ZK EE | ||
+ | |[http://www.zkoss.org/javadoc/latest/zk/org/zkoss/zkmax/theme/StandardThemeProvider.html org.zkoss.zkmax.theme.StandardThemeProvider] | ||
+ | |} | ||
+ | |||
+ | We will illustrate the theme provider with two examples. One is straightforward: set the corresponding attributes based on the cookie. The other '''injects''' a fragment to the URI such that we can allow the browser to cache the CSS file. | ||
<blockquote> | <blockquote> | ||
Line 16: | Line 34: | ||
</blockquote> | </blockquote> | ||
− | =Examples= | + | = Examples = |
+ | |||
== A Simple Example == | == A Simple Example == | ||
In the following example, we store the preferred font size and the skin (theme) in the cookie and retrieve them when required. | In the following example, we store the preferred font size and the skin (theme) in the cookie and retrieve them when required. | ||
+ | |||
+ | '''Since 7.0.0, the font size attributes are deprecated because of using LESS.''' | ||
<source lang="java"> | <source lang="java"> | ||
Line 74: | Line 95: | ||
Notice that we return -1 when <javadoc type="interface" method="getWCSCacheControl(org.zkoss.zk.ui.Execution, java.lang.String)">org.zkoss.zk.ui.util.ThemeProvider</javadoc> is called to disallow the browser to cache the CSS file. It is necessary since we manipulate the content of the CSS file by setting the attributes (based on the cookie). It means the content might be different with the same request URL. For a cacheable example, please refer to [[#A Cacheable Example|the next section]]. | Notice that we return -1 when <javadoc type="interface" method="getWCSCacheControl(org.zkoss.zk.ui.Execution, java.lang.String)">org.zkoss.zk.ui.util.ThemeProvider</javadoc> is called to disallow the browser to cache the CSS file. It is necessary since we manipulate the content of the CSS file by setting the attributes (based on the cookie). It means the content might be different with the same request URL. For a cacheable example, please refer to [[#A Cacheable Example|the next section]]. | ||
− | Then, you configure < | + | Then, you configure <code>WEB-INF/zk.xml</code> by adding the following lines. |
<source lang="xml" > | <source lang="xml" > | ||
Line 84: | Line 105: | ||
== A Cacheable Example == | == A Cacheable Example == | ||
− | To improve the performance, it is better to allow the browser to cache the CSS file as | + | To improve the performance, it is better to allow the browser to cache the CSS file as often as possible. With the theme provider, it can be done by returning a positive number when <javadoc type="interface" method="getWCSCacheControl(org.zkoss.zk.ui.Execution, java.lang.String)">org.zkoss.zk.ui.util.ThemeProvider</javadoc> is called. However, because the browser will use the cached version, we have to ensure the browser gets a different URL for each different theme. Here we illustrate a technique called '''fragment injection'''. |
The idea is simple: when <javadoc type="interface" method="getThemeURIs(org.zkoss.zk.ui.Execution, java.util.List)">org.zkoss.zk.ui.util.ThemeProvider</javadoc> is called, we '''inject''' a special fragment to denote the content, such that each different theme is represented with a different URL. The injection can be done easily with the inner class called <javadoc>org.zkoss.zk.ui.util.ThemeProvider.Aide</javadoc>. For example, | The idea is simple: when <javadoc type="interface" method="getThemeURIs(org.zkoss.zk.ui.Execution, java.util.List)">org.zkoss.zk.ui.util.ThemeProvider</javadoc> is called, we '''inject''' a special fragment to denote the content, such that each different theme is represented with a different URL. The injection can be done easily with the inner class called <javadoc>org.zkoss.zk.ui.util.ThemeProvider.Aide</javadoc>. For example, | ||
Line 199: | Line 220: | ||
= How to Specify the Media Types = | = How to Specify the Media Types = | ||
+ | {{versionSince| 5.0.3}} | ||
− | + | In addition to String instances, you can return instances of <javadoc>org.zkoss.web.servlet.StyleSheet</javadoc> in the returned collection of <javadoc method="getThemeURIs(org.zkoss.zk.ui.Execution,java.util.List)">org.zkoss.zk.ui.util.ThemeProvider</javadoc>, such that you can control more about the generated CSS link. For example, if you want to add a CSS link for [http://www.w3.org/TR/CSS2/media.html the media type], say, <code>print, handheld</code>, then you can do as follows. | |
− | |||
− | In | ||
<source lang="java"> | <source lang="java"> | ||
Line 212: | Line 232: | ||
=Version History= | =Version History= | ||
− | + | ||
− | {| | + | {| class='wikitable' | width="100%" |
! Version !! Date !! Content | ! Version !! Date !! Content | ||
|- | |- |
Latest revision as of 07:37, 8 July 2022
ThemeProvider
After switching to another theme, a ThemeProvider allows you the full control of CSS styling, including but not limited to
- Switch among multiple sets of stylesheets based on, say, the user's preference, cookie, locale, or others
- Replace the CSS styling of component(s) with your own custom styling
- Inject additional CSS files
Since 6.5.2
Standard implementations of ThemeProvider are available for each of ZK editions (CE, PE, and EE).
Edition | ThemeProvider |
---|---|
ZK CE | org.zkoss.zul.theme.StandardThemeProvider |
ZK PE | org.zkoss.zkex.theme.StandardThemeProvider |
ZK EE | org.zkoss.zkmax.theme.StandardThemeProvider |
We will illustrate the theme provider with two examples. One is straightforward: set the corresponding attributes based on the cookie. The other injects a fragment to the URI such that we can allow the browser to cache the CSS file.
For information of 3.6 and earlier, please refer to ZK 3 Theme Provider.
Examples
A Simple Example
In the following example, we store the preferred font size and the skin (theme) in the cookie and retrieve them when required.
Since 7.0.0, the font size attributes are deprecated because of using LESS.
package my;
public class MyThemeProvider implements ThemeProvder {
public Collection getThemeURIs(Execution exec, List uris) {
if ("silvergray".equals(getSkinCookie(exec))) {
uris.add("~./silvergray/color.css.dsp");
uris.add("~./silvergray/img.css.dsp");
}
return uris;
}
public int getWCSCacheControl(Execution exec, String uri) {
return -1;
}
public String beforeWCS(Execution exec, String uri) {
final String fsc = getFontSizeCookie(exec);
if ("lg".equals(fsc)) {
exec.setAttribute("fontSizeM", "15px");
exec.setAttribute("fontSizeMS", "13px");
exec.setAttribute("fontSizeS", "13px");
exec.setAttribute("fontSizeXS", "12px");
} else if ("sm".equals(fsc)) {
exec.setAttribute("fontSizeM", "10px");
exec.setAttribute("fontSizeMS", "9px");
exec.setAttribute("fontSizeS", "9px");
exec.setAttribute("fontSizeXS", "8px");
}
return uri;
}
public String beforeWidgetCSS(Execution exec, String uri) {
return uri;
}
/** Returns the font size specified in cooke. */
private static String getFontSizeCookie(Execution exec) {
Cookie[] cookies = ((HttpServletRequest)exec.getNativeRequest()).getCookies();
if (cookies!=null)
for (int i=0; i<cookies.length; i++)
if ("myfontsize".equals(cookies[i].getName()))
return cookies[i].getValue();
return "";
}
/** Returns the skin specified in cookie. */
private static String getSkinCookie(Execution exec) {
Cookie[] cookies = ((HttpServletRequest)exec.getNativeRequest()).getCookies();
if (cookies!=null)
for (int i=0; i<cookies.length; i++)
if ("myskin".equals(cookies[i].getName()))
return cookies[i].getValue();
return "";
}
}
Notice that we return -1 when ThemeProvider.getWCSCacheControl(Execution, String) is called to disallow the browser to cache the CSS file. It is necessary since we manipulate the content of the CSS file by setting the attributes (based on the cookie). It means the content might be different with the same request URL. For a cacheable example, please refer to the next section.
Then, you configure WEB-INF/zk.xml
by adding the following lines.
<desktop-config>
<theme-provider-class>my.MyThemeProvider</theme-provider-class>
</desktop-config>
A Cacheable Example
To improve the performance, it is better to allow the browser to cache the CSS file as often as possible. With the theme provider, it can be done by returning a positive number when ThemeProvider.getWCSCacheControl(Execution, String) is called. However, because the browser will use the cached version, we have to ensure the browser gets a different URL for each different theme. Here we illustrate a technique called fragment injection.
The idea is simple: when ThemeProvider.getThemeURIs(Execution, List) is called, we inject a special fragment to denote the content, such that each different theme is represented with a different URL. The injection can be done easily with the inner class called ThemeProvider.Aide. For example,
final String fsc = getFontSizeCookie(exec);
if (fsc != null && fsc.length() > 0) {
for (ListIterator it = uris.listIterator(); it.hasNext();) {
final String uri = (String)it.next();
if (uri.startsWith(DEFAULT_WCS)) {
it.set(Aide.injectURI(uri, fsc));
break;
}
}
}
Then, we can retrieve the fragment we encoded into the URI later when ThemeProvider.beforeWCS(Execution, String) is called. It can be done easily by use of ThemeProvider.Aide.decodeURI(String). ThemeProvider.Aide.decodeURI(String) returns a two-element array if the fragment is found. The first element is the URI without fragment, and the second element is the fragment. For example,
public String beforeWCS(Execution exec, String uri) {
final String[] dec = Aide.decodeURI(uri);
if (dec != null) {
if ("lg".equals(dec[1])) {
exec.setAttribute("fontSizeM", "15px");
exec.setAttribute("fontSizeMS", "13px");
exec.setAttribute("fontSizeS", "13px");
exec.setAttribute("fontSizeXS", "12px");
} else if ("sm".equals(dec[1])) {
exec.setAttribute("fontSizeM", "10px");
exec.setAttribute("fontSizeMS", "9px");
exec.setAttribute("fontSizeS", "9px");
exec.setAttribute("fontSizeXS", "8px");
}
return dec[0];
}
return uri;
}
Here is a complete example:
public class CacheableThemeProvider implements ThemeProvider{
private static String DEFAULT_WCS = "~./zul/css/zk.wcs";
public Collection getThemeURIs(Execution exec, List uris) {
//font-size
final String fsc = getFontSizeCookie(exec);
if (fsc != null && fsc.length() > 0) {
for (ListIterator it = uris.listIterator(); it.hasNext();) {
final String uri = (String)it.next();
if (uri.startsWith(DEFAULT_WCS)) {
it.set(Aide.injectURI(uri, fsc));
break;
}
}
}
//slivergray
if ("silvergray".equals(getSkinCookie(exec))) {
uris.add("~./silvergray/color.css.dsp");
uris.add("~./silvergray/img.css.dsp");
}
return uris;
}
public int getWCSCacheControl(Execution exec, String uri) {
return 8760; //safe to cache
}
public String beforeWCS(Execution exec, String uri) {
final String[] dec = Aide.decodeURI(uri);
if (dec != null) {
if ("lg".equals(dec[1])) {
exec.setAttribute("fontSizeM", "15px");
exec.setAttribute("fontSizeMS", "13px");
exec.setAttribute("fontSizeS", "13px");
exec.setAttribute("fontSizeXS", "12px");
} else if ("sm".equals(dec[1])) {
exec.setAttribute("fontSizeM", "10px");
exec.setAttribute("fontSizeMS", "9px");
exec.setAttribute("fontSizeS", "9px");
exec.setAttribute("fontSizeXS", "8px");
}
return dec[0];
}
return uri;
}
public String beforeWidgetCSS(Execution exec, String uri) {
return uri;
}
/** Returns the font size specified in cooke. */
private static String getFontSizeCookie(Execution exec) {
Cookie[] cookies = ((HttpServletRequest)exec.getNativeRequest()).getCookies();
if (cookies!=null)
for (int i=0; i<cookies.length; i++)
if ("myfontsize".equals(cookies[i].getName()))
return cookies[i].getValue();
return "";
}
/** Returns the skin specified in cookie. */
private static String getSkinCookie(Execution exec) {
Cookie[] cookies = ((HttpServletRequest)exec.getNativeRequest()).getCookies();
if (cookies!=null)
for (int i=0; i<cookies.length; i++)
if ("myskin".equals(cookies[i].getName()))
return cookies[i].getValue();
return "";
}
}
How to Specify the Media Types
Since 5.0.3
In addition to String instances, you can return instances of StyleSheet in the returned collection of ThemeProvider.getThemeURIs(Execution, List), such that you can control more about the generated CSS link. For example, if you want to add a CSS link for the media type, say, print, handheld
, then you can do as follows.
public Collection getThemeURIs(Execution exec, List uris) {
uris.add(new StyleSheet("/theme/foo.css", "text/css", "print, handheld", false));
return uris;
}
Version History
Version | Date | Content |
---|---|---|
5.0.3 | June 2010 | The media type was allowed in StyleSheet. |