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 org.apache.juneau.html.annotation.*;
016import org.apache.juneau.serializer.*;
017
018/**
019 * Allows custom rendering of bean property values when serialized as HTML.
020 * 
021 * <p>
022 * Associated with bean properties using the {@link Html#render() @Html.render()} annotation.
023 * 
024 * <p>
025 * Using this class, you can alter the CSS style and HTML content of the bean property.
026 * 
027 * <p>
028 * The following example shows two render classes that customize the appearance of the <code>pctFull</code> and
029 * <code>status</code> columns shown below:
030 * 
031 * <p>
032 * <img class='bordered' src='doc-files/HtmlRender_1.png'>
033 * 
034 * <p class='bcode'>
035 *    <jc>// Our bean class</jc>
036 *    <jk>public class</jk> FileSpace {
037 * 
038 *       <jk>private final</jk> String <jf>drive</jf>;
039 *       <jk>private final long</jk> <jf>total</jf>, <jf>available</jf>;
040 * 
041 *       <jk>public</jk> FileSpace(String drive, <jk>long</jk> total, <jk>long</jk> available) {
042 *          <jk>this</jk>.<jf>drive</jf> = drive;
043 *          <jk>this</jk>.<jf>total</jf> = total;
044 *          <jk>this</jk>.<jf>available</jf> = available;
045 *       }
046 * 
047 *       <ja>@Html</ja>(link=<js>"drive/{drive}"</js>)
048 *       <jk>public</jk> String getDrive() {
049 *          <jk>return</jk> <jf>drive</jf>;
050 *       }
051 * 
052 *       <jk>public long</jk> getTotal() {
053 *          <jk>return</jk> <jf>total</jf>;
054 *       }
055 * 
056 *       <jk>public long</jk> getAvailable() {
057 *          <jk>return</jk> <jf>available</jf>;
058 *       }
059 * 
060 *       <ja>@Html</ja>(render=FileSpacePctRender.<jk>class</jk>)
061 *       <jk>public float</jk> getPctFull() {
062 *          <jk>return</jk> ((100 * <jf>available</jf>) / <jf>total</jf>);
063 *       }
064 * 
065 *       <ja>@Html</ja>(render=FileSpaceStatusRender.<jk>class</jk>)
066 *       <jk>public</jk> FileSpaceStatus getStatus() {
067 *          <jk>float</jk> pf = getPctFull();
068 *          <jk>if</jk> (pf &lt; 80)
069 *             <jk>return</jk> FileSpaceStatus.<jsf>OK</jsf>;
070 *          <jk>if</jk> (pf &lt; 90)
071 *             <jk>return</jk> FileSpaceStatus.<jsf>WARNING</jsf>;
072 *          <jk>return</jk> FileSpaceStatus.<jsf>SEVERE</jsf>;
073 *       }
074 *    }
075 * 
076 *    <jc>// Possible values for the getStatus() method</jc>
077 *    <jk>public static enum</jk> FileSpaceStatus {
078 *       <jsf>OK</jsf>, <jsf>WARNING</jsf>, <jsf>SEVERE</jsf>;
079 *    }
080 * 
081 *    <jc>// Custom render for getPctFull() method</jc>
082 *    <jk>public static class</jk> FileSpacePctRender <jk>extends</jk> HtmlRender&lt;Float&gt; {
083 * 
084 *       <ja>@Override</ja>
085 *       <jk>public</jk> String getStyle(SerializerSession session, Float value) {
086 *          <jk>if</jk> (value &lt; 80)
087 *             <jk>return</jk> <js>"background-color:lightgreen;text-align:center"</js>;
088 *          <jk>if</jk> (value &lt; 90)
089 *             <jk>return</jk> <js>"background-color:yellow;text-align:center"</js>;
090 *          <jk>return</jk> <js>"background-color:red;text-align:center;border:;animation:color_change 0.5s infinite alternate"</js>;
091 *       }
092 * 
093 *       <ja>@Override</ja>
094 *       <jk>public</jk> Object getContent(SerializerSession session, Float value) {
095 *          <jk>if</jk> (value >= 90)
096 *             <jk>return</jk> <jsm>div</jsm>(
097 *                String.<jsm>format</jsm>(<js>"%.0f%%"</js>, value),
098 *                <jsm>style</jsm>(<js>"@keyframes color_change { from { background-color: red; } to { background-color: yellow; }"</js>)
099 *             );
100 *          <jk>return</jk> String.<jsm>format</jsm>(<js>"%.0f%%"</js>, value);
101 *       }
102 *    }
103 * 
104 *    <jc>// Custom render for getStatus() method</jc>
105 *    <jk>public static class</jk> FileSpaceStatusRender <jk>extends</jk> HtmlRender&lt;FileSpaceStatus&gt; {
106 * 
107 *       <ja>@Override</ja>
108 *       <jk>public</jk> String getStyle(SerializerSession session, FileSpaceStatus value) {
109 *          <jk>return</jk> <js>"text-align:center"</js>;
110 *       }
111 * 
112 *       <ja>@Override</ja>
113 *       <jk>public</jk> Object getContent(SerializerSession session, FileSpaceStatus value) {
114 *          <jk>switch</jk> (value) {
115 *             <jk>case</jk> <jsf>OK</jsf>:  <jk>return</jk> <jsm>img</jsm>().src(URI.<jsm>create</jsm>(<js>"servlet:/htdocs/ok.png"</js>));
116 *             <jk>case</jk> <jsf>WARNING</jsf>:  <jk>return</jk> <jsm>img</jsm>().src(URI.<jsm>create</jsm>(<js>"servlet:/htdocs/warning.png"</js>));
117 *             <jk>default</jk>: <jk>return</jk> <jsm>img</jsm>().src(URI.<jsm>create</jsm>(<js>"servlet:/htdocs/severe.png"</js>));
118 *          }
119 *       }
120 *    }
121 * </p>
122 * 
123 * @param <T> The bean property type.
124 */
125public abstract class HtmlRender<T> {
126
127   /**
128    * Returns the CSS style of the element containing the bean property value.
129    * 
130    * @param session
131    *    The current serializer session.
132    *    Can be used to retrieve properties and session-level information.
133    * @param value The bean property value.
134    * @return The CSS style string, or <jk>null</jk> if no style should be added.
135    */
136   public String getStyle(SerializerSession session, T value) {
137      return null;
138   }
139
140   /**
141    * Returns the delegate value for the specified bean property value.
142    * 
143    * <p>
144    * The default implementation simply returns the same value.
145    * A typical use is to return an HTML element using one of the HTML5 DOM beans.
146    * 
147    * @param session
148    *    The current serializer session.
149    *    Can be used to retrieve properties and session-level information.
150    * @param value The bean property value.
151    * @return The new bean property value.
152    */
153   public Object getContent(SerializerSession session, T value) {
154      return value;
155   }
156}