001    // Copyright (c) 2001 Hursh Jain (http://www.mollypages.org) 
002    // The Molly framework is freely distributable under the terms of an
003    // MIT-style license. For details, see the molly pages web site at:
004    // http://www.mollypages.org/. Use, modify, have fun !
005    
006    package fc.web.forms;
007    
008    import javax.servlet.*;
009    import javax.servlet.http.*;
010    import java.io.*;
011    import java.util.*;
012    import java.util.regex.*;
013    
014    import fc.jdbc.*;
015    import fc.io.*;
016    import fc.util.*;
017    
018    /**
019    A HTML TextArea
020    */
021    public final class TextArea extends AbstractText
022    {
023    private WrapType wrap;
024    private int    rows = 0;
025    private int    cols = 0;
026    //private String   classname = getClass().getName();
027    
028    /** 
029    Creates a new textarea element with a initial value of "" (the
030    empty string). No initial rows/cols are specified which will have
031    the effect of rendering this field with the browsers default.
032    **/
033    public TextArea(String name)
034      {
035      this(name, "", 0, 0);
036      }
037    
038    /** 
039    Creates a new textarea element with a initial value of "" and
040    the specified rows/cols.
041    **/
042    public TextArea(String name, int rows, int cols)
043      {
044      this(name, "", rows, cols);
045      }
046      
047    /**
048    Creates a new text element with the specified initial value.
049    If the specified value is <tt>null</tt>, then the initial
050    value is set to "" (the empty string)
051    **/
052    public TextArea(String name, String value)
053      {
054      this(name, value, 0, 0);
055      }
056    
057    /**
058    Creates a new text element with the specified initial value
059    and rows/cols.
060    **/
061    public TextArea(String name, String value, int rows, int cols)
062      {
063      super(name, value);
064      this.rows = rows;
065      this.cols = cols;
066      }
067    
068    public Field.Type getType() {
069      return Field.Type.TEXTAREA;
070      }
071      
072    public void renderImpl(FormData fd, Writer writer) throws IOException 
073      {
074      String value = getRenderValue(fd);
075      
076      writer.write("<textarea ");
077    
078      if (! enabled || ! isEnabled(fd)) {
079        writer.write(" disabled");
080        }
081      
082      writer.write(" name='");
083      writer.write(name);
084      writer.write("'");
085    
086      if (rows > 0) {
087        writer.write(" rows='");
088        
089        // this is tricky, Writer != PrintWriter
090        // and a int value will be treated as a character code
091        // so writer.write(10) will write a newline, not '10'
092        // writer.write(rows);  
093        writer.write(String.valueOf(rows));
094        writer.write("'"); 
095        }
096      
097      if (cols > 0) {
098        writer.write(" cols='");
099        writer.write(String.valueOf(cols));
100        writer.write("'"); 
101        }
102    
103      if (wrap != null) {
104        writer.write(" wrap='");
105        writer.write(wrap.type);
106        writer.write("'"); 
107        }
108          
109      if (renderStyleTag) {
110        writer.write(" style='");
111        writer.write(styleTag);
112        writer.write("'");
113        }
114        
115      final int arlen = arbitraryString.size();
116      for (int n = 0; n < arlen; n++) {
117        writer.write(" ");
118        writer.write(arbitraryString.get(n).toString());
119        }
120    
121      writer.write(">");
122      writer.write(sanitizedValue(value));
123      writer.write("</textarea>");
124      }
125            
126      
127    /** 
128    This value (if set) is rendered as the html <tt>COLS</tt> tag.
129    
130    @return this object for method chaining convenience
131    **/
132    public TextArea setCols(int cols) {
133      this.cols = cols;
134      return this;
135      } 
136          
137    /** 
138    This value (if set) is rendered as the html <tt>ROWS</tt> tag.
139    
140    @return this object for method chaining convenience
141    **/
142    public TextArea setRows(int rows) {
143      this.rows = rows;
144      return this;
145      } 
146    
147    /** 
148    Sets the wrapping mode of this text box. This value (if set) is
149    rendered as the html <tt>WRAP</tt> tag. By default the wrap
150    value is not set (and hence not rendered).
151    
152    @return this object for method chaining convenience
153    **/
154    public TextArea setWrap(WrapType wrap) {
155      this.wrap = wrap;
156      return this;
157      }
158    
159    //we need to sanitize our value since if we set to "</textarea>"
160    //the browser will think the value indicates the end of the
161    //textarea
162    static final Pattern pat = Pattern.compile("(?i)</textarea>");
163    private String sanitizedValue(String value) 
164      {
165      if ( value == null || value.equals("") ) {
166        return "";     
167        }
168        
169      Matcher matcher = pat.matcher(value);
170      String newval = matcher.replaceAll("&lt;/textarea&gt;");
171      return newval;
172      }
173        
174    /** 
175    From the HTML spec:
176    <br>
177    <ol>
178      <li>OFF disables word wrap. Text the user types is
179      displayed with the exact line breaks that the user types.
180      If the user explicitly inserts a line break, however, the
181      break is included as part of the text area's value. The
182      user has to scroll horizontally to see the ends of lines
183      that do not fit in the text area element.
184      <li>HARD causes word wrap, and the line breaks are
185      included when the form is submitted. The text wraps inside
186      the text area element, and that the user does not need to
187      scroll horizontally.
188      <li>SOFT causes word wrap, but the line breaks are not
189      included when the form is submitted
190    </ol>
191    **/   
192    public static class WrapType {
193      private String type;
194      private WrapType(String type) { this.type = type; }
195        public static final WrapType OFF = new WrapType ("off");
196      public static final WrapType HARD = new WrapType ("hard");
197      public static final WrapType SOFT = new WrapType ("soft");
198      }   
199        
200    }          //~class TextArea