View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.custom.inputHtml;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.myfaces.component.html.ext.HtmlInputText;
24  import org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils;
25  import org.apache.myfaces.shared_tomahawk.util._ComponentUtils;
26  
27  import javax.faces.context.FacesContext;
28  import javax.faces.el.ValueBinding;
29  
30  /**
31   * HTML Editor using the kupu library.
32   * http://kupu.oscom.org/
33   *
34   * An inline HTML based word processor based on the Kupu library. 
35   * 
36   * See http://kupu.oscom.org 
37   * 
38   * Right now, the support is limited to one editor per page 
39   * (but you can use tabs to have multiple editors, but only 
40   * one rendered at a time). 
41   * 
42   * Unless otherwise specified, all attributes accept static values or EL expressions.
43   *
44   * @JSFComponent
45   *   name = "t:inputHtml"
46   *   tagClass = "org.apache.myfaces.custom.inputHtml.InputHtmlTag"
47   *
48   * @author Sylvain Vieujot (latest modification by $Author: skitching $)
49   * @version $Revision: 673833 $ $Date: 2008-07-03 16:58:05 -0500 (Thu, 03 Jul 2008) $
50   */
51  public class InputHtml extends HtmlInputText {
52      public static final String COMPONENT_TYPE = "org.apache.myfaces.InputHtml";
53  
54      public static final String DEFAULT_RENDERER_TYPE = "org.apache.myfaces.InputHtml";
55  
56      private static final Log log = LogFactory.getLog(HtmlInputText.class);
57  
58      private String _fallback;
59      private String _type;
60  
61      private Boolean _allowEditSource;
62      private Boolean _allowExternalLinks;
63      private Boolean _addKupuLogo;
64  
65      private Boolean _showAllToolBoxes;
66      private Boolean _showPropertiesToolBox;
67      private Boolean _showLinksToolBox;
68      private Boolean _showImagesToolBox;
69      private Boolean _showTablesToolBox;
70      private Boolean _showCleanupExpressionsToolBox;
71      private Boolean _showDebugToolBox;
72  
73      public InputHtml() {
74          setRendererType(DEFAULT_RENDERER_TYPE);
75      }
76  
77      public Object saveState(FacesContext context) {
78          Object values[] = new Object[4];
79          values[0] = super.saveState(context);
80  
81          String[] types = new String[2];
82          types[0] = _fallback;
83          types[1] = _type;
84  
85          values[1] = types;
86  
87          Boolean toolBarButtons[] = new Boolean[3];
88          toolBarButtons[0] = _allowEditSource;
89          toolBarButtons[1] = _allowExternalLinks;
90          toolBarButtons[2] = _addKupuLogo;
91  
92          values[2] = toolBarButtons;
93  
94          Boolean toolBoxes[] = new Boolean[7];
95          toolBoxes[0] = _showAllToolBoxes;
96          toolBoxes[1] = _showPropertiesToolBox;
97          toolBoxes[2] = _showLinksToolBox;
98          toolBoxes[3] = _showImagesToolBox;
99          toolBoxes[4] = _showTablesToolBox;
100         toolBoxes[5] = _showCleanupExpressionsToolBox;
101         toolBoxes[6] = _showDebugToolBox;
102 
103         values[3] = toolBoxes;
104 
105         return values;
106     }
107 
108     public void restoreState(FacesContext context, Object state) {
109         Object values[] = (Object[]) state;
110         super.restoreState(context, values[0]);
111 
112         String[] types = (String[]) values[1];
113         _fallback = types[0];
114         _type = types[1];
115 
116         Boolean[] toolBarButtons = (Boolean[]) values[2];
117         _allowEditSource = toolBarButtons[0];
118         _allowExternalLinks = toolBarButtons[1];
119         _addKupuLogo = toolBarButtons[2];
120 
121         Boolean[] toolBoxes = (Boolean[]) values[3];
122         _showAllToolBoxes = toolBoxes[0];
123         _showPropertiesToolBox = toolBoxes[1];
124         _showLinksToolBox = toolBoxes[2];
125         _showImagesToolBox = toolBoxes[3];
126         _showTablesToolBox = toolBoxes[4];
127         _showCleanupExpressionsToolBox = toolBoxes[5];
128         _showDebugToolBox = toolBoxes[6];
129     }
130 
131     /**
132      * Use a text area instead of the javascript HTML editor. 
133      * 
134      * Default is false. Use with caution.
135      * 
136      * @JSFProperty
137      */
138     public String getFallback(){
139         if (_fallback != null)
140             return _fallback;
141         ValueBinding vb = getValueBinding("fallback");
142         return vb != null ? vb.getValue(getFacesContext()).toString() : "false";
143     }
144     public void setFallback(String _fallback){
145         this._fallback = _fallback;
146     }
147 
148     /**
149      * The type of the value. It can be either fragment for an HTML 
150      * fragment (default) or document for a full HTML document, with 
151      * head, title, body, ... tags.
152      * 
153      * @JSFProperty
154      */
155     public String getType(){
156         if (_type != null)
157             return _type;
158         ValueBinding vb = getValueBinding("type");
159         return vb != null ? _ComponentUtils.getStringValue(getFacesContext(), vb) : "fragment";
160     }
161     public void setType(String _type){
162         this._type = _type;
163     }
164     public boolean isTypeDocument(){
165         return getType().equals("document");
166     }
167 
168     /**
169      * Allows the user to edit the HTML source code. Default is true.
170      * 
171      * @JSFProperty
172      */
173     public boolean isAllowEditSource(){
174            if (_allowEditSource != null)
175                return _allowEditSource.booleanValue();
176            ValueBinding vb = getValueBinding("allowEditSource");
177            return vb != null ? ((Boolean)vb.getValue(getFacesContext())).booleanValue() : true;
178     }
179     public void setAllowEditSource(boolean allowEditSource){
180         this._allowEditSource = Boolean.valueOf(allowEditSource);
181     }
182 
183     /**
184      * Allows the user to insert external links. Default is true.
185      * 
186      * @JSFProperty
187      */
188     public boolean isAllowExternalLinks(){
189         if (_allowExternalLinks != null)
190             return _allowExternalLinks.booleanValue();
191         ValueBinding vb = getValueBinding("allowExternalLinks");
192         return vb != null ? ((Boolean)vb.getValue(getFacesContext())).booleanValue() : true;
193     }
194     public void setAllowExternalLinks(boolean allowExternalLinks){
195         this._allowExternalLinks = Boolean.valueOf(allowExternalLinks);
196     }
197 
198     /**
199      * Show the Kupu Logo in the buttons bar. Default is true.
200      * 
201      * @JSFProperty
202      */
203     public boolean isAddKupuLogo(){
204            if (_addKupuLogo != null)
205                return _addKupuLogo.booleanValue();
206            ValueBinding vb = getValueBinding("addKupuLogo");
207            return vb != null ? ((Boolean)vb.getValue(getFacesContext())).booleanValue() : true;
208     }
209     public void setAddKupuLogo(boolean addKupuLogo){
210         this._addKupuLogo = Boolean.valueOf(addKupuLogo);
211     }
212 
213     /**
214      * Shortcut to avoid setting all the showXXToolBox to true. Default is false.
215      * 
216      * @JSFProperty
217      */
218     public boolean isShowAllToolBoxes(){
219            if (_showAllToolBoxes != null)
220                return _showAllToolBoxes.booleanValue();
221         ValueBinding vb = getValueBinding("showAllToolBoxes");
222         return vb != null ? ((Boolean)vb.getValue(getFacesContext())).booleanValue() : false;
223     }
224     public void setShowAllToolBoxes(boolean showAllToolBoxes){
225         this._showAllToolBoxes = Boolean.valueOf(showAllToolBoxes);
226     }
227 
228     /**
229      * Show the Properties tool box next to the text. Default is false.
230      * 
231      * @JSFProperty
232      */
233     public boolean isShowPropertiesToolBox(){
234         if( isShowAllToolBoxes() )
235             return true;
236 
237            if (_showPropertiesToolBox != null)
238                return _showPropertiesToolBox.booleanValue();
239         ValueBinding vb = getValueBinding("showPropertiesToolBox");
240         return vb != null ? ((Boolean)vb.getValue(getFacesContext())).booleanValue() : false;
241     }
242 
243     public void setShowPropertiesToolBox(boolean showPropertiesToolBox){
244         this._showPropertiesToolBox = Boolean.valueOf(showPropertiesToolBox);
245     }
246 
247     /**
248      * Show the Links tool box next to the text. Default is false.
249      * 
250      * @JSFProperty
251      */
252     public boolean isShowLinksToolBox(){
253         if( isShowAllToolBoxes() )
254             return true;
255 
256            if (_showLinksToolBox != null)
257                return _showLinksToolBox.booleanValue();
258         ValueBinding vb = getValueBinding("showLinksToolBox");
259         return vb != null ? ((Boolean)vb.getValue(getFacesContext())).booleanValue() : false;
260     }
261     
262     public void setShowLinksToolBox(boolean showLinksToolBox){
263         this._showLinksToolBox = Boolean.valueOf(showLinksToolBox);
264     }
265 
266     /**
267      * Show the Images tool box next to the text. Default is false.
268      * 
269      * @JSFProperty
270      */
271     public boolean isShowImagesToolBox(){
272         if( isShowAllToolBoxes() )
273             return true;
274 
275            if (_showImagesToolBox != null)
276                return _showImagesToolBox.booleanValue();
277         ValueBinding vb = getValueBinding("showImagesToolBox");
278         return vb != null ? ((Boolean)vb.getValue(getFacesContext())).booleanValue() : false;
279     }
280     public void setShowImagesToolBox(boolean showImagesToolBox){
281         this._showImagesToolBox = Boolean.valueOf(showImagesToolBox);
282     }
283 
284     /**
285      * Show the Tables tool box next to the text. Default is false.
286      * 
287      * @JSFProperty
288      */
289     public boolean isShowTablesToolBox(){
290         if( isShowAllToolBoxes() )
291             return true;
292 
293            if (_showTablesToolBox != null)
294                return _showTablesToolBox.booleanValue();
295         ValueBinding vb = getValueBinding("showTablesToolBox");
296         return vb != null ? ((Boolean)vb.getValue(getFacesContext())).booleanValue() : false;
297     }
298     public void setShowTablesToolBox(boolean showTablesToolBox){
299         this._showTablesToolBox = Boolean.valueOf(showTablesToolBox);
300     }
301 
302     /**
303      * Show the Cleanup Expressions tool box next to the text. Default is false.
304      * 
305      * @JSFProperty
306      */
307     public boolean isShowCleanupExpressionsToolBox(){
308         if( isShowAllToolBoxes() )
309             return true;
310 
311            if (_showCleanupExpressionsToolBox != null)
312                return _showCleanupExpressionsToolBox.booleanValue();
313         ValueBinding vb = getValueBinding("showCleanupExpressionsToolBox");
314         return vb != null ? ((Boolean)vb.getValue(getFacesContext())).booleanValue() : false;
315     }
316     public void setShowCleanupExpressionsToolBox(boolean showCleanupExpressionsToolBox){
317         this._showCleanupExpressionsToolBox = Boolean.valueOf(showCleanupExpressionsToolBox);
318     }
319 
320     /**
321      * Show the Debug tool box next to the text. Default is false.
322      * 
323      * @JSFProperty
324      */
325     public boolean isShowDebugToolBox(){
326         if( isShowAllToolBoxes() )
327             return true;
328 
329            if (_showDebugToolBox != null)
330                return _showDebugToolBox.booleanValue();
331         ValueBinding vb = getValueBinding("showDebugToolBox");
332         return vb != null ? ((Boolean)vb.getValue(getFacesContext())).booleanValue() : false;
333     }
334     public void setShowDebugToolBox(boolean showTablesToolBox){
335         this._showDebugToolBox = Boolean.valueOf(showTablesToolBox);
336     }
337 
338     public boolean isShowAnyToolBox(){
339            return isShowAllToolBoxes()
340                || isShowPropertiesToolBox()
341                || isShowLinksToolBox()
342                || isShowImagesToolBox()
343                || isShowTablesToolBox()
344                || isShowCleanupExpressionsToolBox()
345                || isShowDebugToolBox();
346     }
347 
348     public String getValueAsHtmlDocument(FacesContext context){
349         String val = RendererUtils.getStringValue(context, this);
350         if( isHtmlDocument( val ) )
351             return val;
352 
353         return "<html><body>"+(val==null ? "" : val)+"</body></html>";
354     }
355 
356     private static boolean isHtmlDocument(String text){
357         if( text == null )
358             return false;
359 
360         if( text.indexOf("<body>")!=-1 || text.indexOf("<body ")!=-1
361             || text.indexOf("<BODY>")!=-1 || text.indexOf("<BODY ")!=-1 )
362             return true;
363 
364         return false;
365     }
366 
367     public String getValueFromDocument(String text){
368         if( text == null )
369             return "";
370 
371         if( isTypeDocument() )
372             return text.trim();
373 
374         if( !isHtmlDocument(text) )
375             return text.trim();
376 
377         // Extract the fragment from the document.
378         String fragment = getHtmlBody( text );
379         if( fragment.endsWith("<br />") )
380             return fragment.substring(0, fragment.length()-6);
381         return fragment;
382     }
383     
384     String getHtmlBody(String html){
385         html = html.trim();
386         if( html.length() == 0 )
387             return "";
388 
389         String lcText = html.toLowerCase();
390         int textLength = lcText.length();
391         int bodyStartIndex = -1;
392         while(bodyStartIndex < textLength){
393             bodyStartIndex++;
394             bodyStartIndex = lcText.indexOf("<body", bodyStartIndex);
395             if( bodyStartIndex == -1 )
396                 break; // not found.
397 
398             bodyStartIndex += 5;
399             char c = lcText.charAt(bodyStartIndex);
400             if( c=='>' )
401                 break;
402 
403             if( c!=' ' && c!='\t' )
404                 continue;
405 
406             bodyStartIndex = lcText.indexOf('>', bodyStartIndex);
407             break;
408         }
409         bodyStartIndex++;
410 
411         int bodyEndIndex = lcText.lastIndexOf("</body>")-1;
412         
413         if( bodyStartIndex<0 || bodyEndIndex<0
414            || bodyStartIndex > bodyEndIndex
415            || bodyStartIndex>=textLength || bodyEndIndex>=textLength ){
416 
417             if( lcText.indexOf("<body/>")!=-1 || lcText.indexOf("<body />")!=-1 )
418                 return "";
419             
420             int htmlStartIndex = lcText.indexOf("<html>");
421             int htmlEndIndex = lcText.indexOf("</html>");
422             if( htmlStartIndex != -1 && htmlEndIndex > htmlStartIndex )
423                 return html.substring(htmlStartIndex+6, htmlEndIndex);
424             
425             if( isTypeDocument() )
426                 log.warn("Couldn't extract HTML body from :\n"+html);
427             return html.trim();
428         }
429 
430         return html.substring(bodyStartIndex, bodyEndIndex+1).trim();
431     }
432 }