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 006package fc.web.simpleforms; 007 008import jakarta.servlet.*; 009import jakarta.servlet.http.*; 010import java.io.*; 011import java.util.*; 012 013import fc.io.*; 014import fc.util.*; 015 016/** 017Helps maintain form state. Form state needs to be maintained 018when a form is submitted but needs to be redisplayed to the 019user because of errors or incomplete fields. 020<p> 021For example: 022<blockquote><pre> 023<input name=<span style="color:green">foo</span> type='text' value='<span style="color:blue">[= State.text(req, "<span style="color:green">foo</span>")]'</span>> 024</pre></blockquote> 025Often we need to set default/initial values (say from a database) for 026pre-filling a form before it's shown to the user (for example, when 027the user is editing some information that already exists in the database). 028In the simple form API, this is done via invoking the {@link 029#set(HttpServletRequest, String, String) set(req, field_name, field_value)} 030method, which sets the initial value of the field in the specified 031HttpServletRequest object (mimicking as if the user had entered those values 032and submitted the form). Since various widgets maintain state by retrieveing 033these values from the HttpServletRequest, these values will be shown 034to the user. For example: 035<blockquote><pre> 036String initial_value = databaseQuery.getUserName(); //for example 037State.set(req, "<span style="color:green">foo</span>", initial_value); 038 039...later in the page... 040//this will show the initial value set above and also maintain state 041//when the user changes the value and submits the form 042<input name=<span style="color:green">foo</span> type='text' value='<span style="color:blue">[= State.text(req, "<span style="color:green">foo</span>")]'</span>> 043</pre></blockquote> 044 045@author hursh jain 046*/ 047public final class State 048{ 049private static final boolean dbg = false; 050 051//text should always be at least an empty string. However, can 052//can be hacked. Also browser return no value for disabled fields 053//we don't track field enable/disable status and to keep simpleforms 054//simple, don't have a overloaded method that takes status as a 055//param. so no hacklerts here. 056 057//TEXT, TEXTAREA, PASSWORD, RADIO, CHECKBOX, HIDDEN, SELECT 058 059// ------------------------------------------------------------ 060 061private static final String getParameter( 062 final HttpServletRequest req, final String name) 063 { 064 if (req.getAttribute(cleared_key) == null) //use submitted data ? 065 { 066 final String val = req.getParameter(name); 067 if (val != null) 068 return val; 069 } 070 071 072 /* 073 return (String) req.getAttribute(name); //some value or null 074 //below prevents cut-n-paste typos 075 */ 076 final Object val = req.getAttribute(name); 077 try { 078 return (String) val; 079 } 080 catch (ClassCastException e) { 081 throw new RuntimeException("The value of this field [" + name + "] should be set ONLY once (and as a string). You cutting'n'pasting dude ?"); 082 } 083 084 } 085 086private static final String[] getParameterValues( 087 final HttpServletRequest req, final String name) 088 { 089 if (req.getAttribute(cleared_key) == null) //use submitted data ? 090 { 091 final String[] val = req.getParameterValues(name); 092 if (val != null) { 093 return val; 094 } 095 } 096 097 //returns null or String[] 098 final Object obj = req.getAttribute(name); 099 100 if (obj == null) 101 return null; 102 103 //in case we only added 1 string for a group 104 if (obj instanceof String) { 105 String[] arr = new String[1]; 106 arr[0] = (String) obj; 107 return arr; 108 } 109 110 final List list = (ArrayList) obj; 111 return (String[]) list.toArray(str_arr_type); 112 } 113 114private static final String[] str_arr_type = new String[] { }; 115 116//--------------------------------------------------------- 117 118/** 119Returns the value of the submitted text area (or an empty string if 120no value was submitted). Example: 121<blockquote><pre> 122<input type=text name=<span style="color:green">foo</span> value='[=State.text(req, "<span style="color:green">foo</span>")]'> 123</pre></blockquote> 124*/ 125public static final String text( 126final HttpServletRequest req, final String name) 127 { 128 final String val = getParameter(req, name); 129 if (dbg) System.out.println(name+"="+val); 130 131 if (val != null) 132 return val; 133 else 134 return ""; 135 } 136 137/** 138Returns the value of the submitted text area (or an empty string if 139no value was submitted). The returned value is trimmed of all 140leading and trailing spaces. 141<p> 142The returned value replicates what the user entered and is not url 143encoded. This is good when maintaining state. 144<p> 145Of course, when saving this out to the database, we should either 146strip naughty tags or save it as url encoded text. (otherwise, 147the door to cross-site scripting hacks is wide open). That's an 148orthogonal issue to maintaining form state via this method. 149Example: 150<blockquote><pre> 151<textarea name=<span style="color:green">foo</span>> 152[=State.textarea(req, "<span style="color:green">foo</span>")] 153</textarea> 154</pre></blockquote> 155*/ 156public static final String textarea( 157final HttpServletRequest req, final String name) 158 { 159 //we need to trim(), otherwise 160 // <textarea> NL 161 // [state.. ] NL 162 // </textarea> 163 // The newline keep adding up and adding themselves to the state 164 165 return text(req, name).trim(); 166 } 167 168 169/** 170Returns the value of the submitted password (or an empty string if 171no value was submitted). Example: 172<blockquote><pre> 173<input type=password name=<span style="color:green">foo</span> value='[=State.password(req, "<span style="color:green">foo</span>")]'> 174</pre></blockquote> 175*/ 176public static final String password( 177 final HttpServletRequest req, final String name) 178 { 179 return text(req, name); 180 } 181 182/** 183Returns the submitted state of the submitted radio box. This radio 184box should not be part of a radio group (multiple radio buttons with 185the same name). For radio groups use the {@link #radiogroup 186radiogroup} method. Example: 187<blockquote><pre> 188<input type=radio name=<span style="color:green">foo</span> value='somevalue' [=State.radio(req, "<span style="color:green">foo</span>")]> 189</pre></blockquote> 190<b>Note</b>: For radio boxes, the state maintainence value is the 191presence/absence of the <code>checked</code> attribute. The value 192returned by this method will be either an empty string or 193<code>checked</code>. This should not be assigned to the 'value' 194attribute (if present) of the radiobox. Rather, it should be a 195stand-alone attribute. 196 197@param name the name of the radio element 198@param selected <code>true</code> to select this radio box 199 initially (the first time the form is shown to 200 the user), <code>false</code> otherwise. 201*/ 202public static final String radio( 203 final HttpServletRequest req, final String name, 204 final boolean selected) 205 { 206 final String val = getParameter(req, name); 207 if (dbg) System.out.println(name+"="+val); 208 209 if (val == null) 210 { 211 if (selected) 212 return "checked"; 213 else 214 return ""; 215 } 216 217 //value != null (any value) 218 return "checked"; 219 } 220 221/** 222Calls {@link #radio(HttpServletRequest, String, boolean) radio(req, name, <b>false</b>)} 223*/ 224public static final String radio( 225 final HttpServletRequest req, final String name) 226 { 227 return radio(req, name, false); 228 } 229 230 231/** 232Returns the submitted state of the specified radio box which is part 233of a radio group (multiple radio buttons with the same name). For 234non-group radio boxes, use the {@link #radio radio} method instead. 235Example: 236<blockquote><pre> 237<b><u>Good:</u></b> 238<input type=radio name=<span style="color:green">foo</span> <u>value='<span style="color:blue">somevalue1</span>'</u> [=State.radiogroup(req, "<span style="color:green">foo</span>", <span style="color:blue">"somevalue1"</span>)]> 239<input type=radio name=<span style="color:green">foo</span> <u>value='<span style="color:blue">somevalue2</span>'</u> [=State.radiogroup(req, "<span style="color:green">foo</span>", <span style="color:blue">"somevalue2"</span>)]> 240 241<b>Don't do this</b> 242<input type=radio name=<span style="color:green">foo</span> [=State.radiogroup(req, "<span style="color:green">foo</span>", <span style="color:blue">"on"</span>)]> 243</pre></blockquote> 244This method takes a <code>value</code> parameter that specifies the 245value associated with this particular radio box in the radio group. 246Radios with no specific value are submitted with the value "on" 247(case-insensitive) by the browser. (as seen in the second example above). 248<u>This method requires that each radio in the radiogroup have a unique 249and specified value tag.</u> 250<p> 251<b>Note</b>: For radio boxes, the state maintainence value is the 252presence/absence of the <code>checked</code> attribute. The value 253returned by this method will be either an empty string or 254<code>checked</code>. This should not be assigned to the 'value' 255attribute (if present) of the radiobox. Rather, it should be a 256stand-alone attribute. 257*/ 258public static final String radiogroup( 259 final HttpServletRequest req, final String name, final String value) 260 { 261 final String[] val = getParameterValues(req, name); 262 263 if (dbg) System.out.println(name+"="+Arrays.toString(val)); 264 265 //val could be the value or "on" if radio has no value tag 266 if (val == null) 267 return ""; 268 269 for (int n = 0; n < val.length; n++) 270 { 271 if (val[n].equals(value) || val[n].equalsIgnoreCase("on")) { 272 return "checked"; 273 } 274 } 275 276 return ""; 277 } 278 279/* 280Calls {@link checkbox(HttpServletRequest, String, boolean)} as 281<tt>checkbox(HttpServletRequest, String, <b>false</b>)</tt> 282*/ 283/* 284..thot it was convenient but it's useless...the checkbox will 285be checked every time if we say 286 [=State.checkbox(req, "foo", true)], 287because the true will override things even if the user unchecked 288the box. so state is not maintained, too confusing... 289..use the initial state (set) method to show initially checked boxes. 290 291public static final String checkbox( 292 final HttpServletRequest req, final String name) 293 { 294 return checkbox(req, name, false); 295 } 296*/ 297 298/** 299Returns the checked state of the submitted checkbox. This radio box 300should not be part of a radio group (multiple checkboxes with the 301same name). For radio groups use the {@link #checkboxgroup 302checkboxgroup} method. 303Example: 304<blockquote><pre> 305<input type=checkbox name=<span style="color:green">foo</span> value='somevalue' [=State.checkbox(req, "<span style="color:green">foo</span>")]> 306</pre></blockquote> 307<b>Note</b>: For check boxes, the state maintainence value is the 308presence/absence of the <code>checked</code> attribute. The value 309returned by this method will be either an empty string or 310<code>checked</code>. This should not be assigned to the 'value' 311attribute (if present) of checkbox. Rather, it should be a 312stand-alone attribute as shown above. 313 314@param name the name of the radio element 315*/ 316public static final String checkbox( 317 final HttpServletRequest req, final String name) 318 { 319 final String val = getParameter(req, name); 320 if (dbg) System.out.println(name+"="+val); 321 322 if (val == null) { 323 return ""; 324 } 325 326 //value != null (any value) 327 return "checked"; 328 } 329 330/** 331Returns the submitted state of the specified check box which is part 332of a checkbox group (multiple check buttons with the same name). For 333non-group check boxes, use the {@link #checkbox checkbox} method instead. 334<p> 335Note: Checkboxes with no specific value are submitted with the value 336"on" (case-insensitive) by the browser (as seen in the second and 337third example below). Example: 338<blockquote><pre> 339 340<b><u>Good</u></b>: 341<input type=checkbox name=<span style="color:green">foo</span> <u>value='<span style="color:blue">somevalue1</span>'</u> [=State.checkboxgroup(req, "<span style="color:green">foo</span>", <span style="color:blue">"somevalue1"</span>)]> 342<input type=checkbox name=<span style="color:green">foo</span> <u>value='<span style="color:blue">somevalue2</span>'</u> [=State.checkboxgroup(req, "<span style="color:green">foo</span>", <span style="color:blue">"somevalue2"</span>)]> 343 344<b>Don't do this</b>: 345<input type=checkbox name=<span style="color:green">foo</span> [=State.checkboxgroup(req, "<span style="color:green">foo</span>", <span style="color:blue">"on"</span>)]> 346<input type=checkbox name=<span style="color:green">foo</span> [=State.checkboxgroup(req, "<span style="color:green">foo</span>", <span style="color:blue">"on"</span>)]> 347</pre></blockquote> 348This method takes a <code>value</code> parameter that specifies the 349value of the check box in the checkbox group. <u>This method 350requires that each checkbox in the group have a specified and unique 351value attribute</u>. 352<p> 353<b>Note</b>: For check boxes, the state maintainence value is the 354presence/absence of the <code>checked</code> attribute. The value 355returned by this method will be either an empty string or 356<code>checked</code>. This should not be assigned to the 'value' 357attribute (if present) of the checkbox. Rather, it should be a 358stand-alone attribute. 359*/ 360public static final String checkboxgroup( 361 final HttpServletRequest req, final String name, final String value) 362 { 363 final String[] val = getParameterValues(req, name); 364 if (dbg) System.out.println(name+"="+Arrays.toString(val)); 365 366 if (val == null) 367 return ""; 368 369 /* 370 we cannot say: 371 372 if (val[n].equals(value) || val[n].equalsIgnoreCase("on")) ... 373 374 because a checkbox with no value - if checked - will also check all 375 other checkboxes in the group (since we get foo=on and we don't 376 know which checkbox to turn on in that case, since they are all 377 called foo) 378 */ 379 for (int n = 0; n < val.length; n++) 380 { 381 if (val[n].equals(value)) { 382 return "checked"; 383 } 384 } 385 386 return ""; 387 } 388 389 390/** 391Returns the value of the submitted hidden field or an empty string if no 392value was submitted (this can happen if the user hacked/removed this 393value manually). 394Example: 395<blockquote><pre> 396<input type=hidden name=<span style="color:green">foo</span> value='[=State.hidden(req, "<span style="color:green">foo</span>")]'> 397</pre></blockquote> 398*/ 399public static final String hidden(final HttpServletRequest req, final String name) 400 { 401 return text(req, name); 402 } 403 404 405//<input type=image: get x,y co-ordinates of the click. not needed for form 406//maintainence 407//<input type=submit: not needed for form maintainence 408 409 410/** 411Returns the state of the submitted select. For select options, we 412need to maintain whichever option(s) were selected by the user. The 413presence/absence of the <code>selected</code> attribute maintains this 414state. 415<p> 416When maintaining states for select input types: 417<ol> 418<li> 419We know the select options on the server-side and write them 420out dynamically (or statically) on the server-side and 421then send the page to the client. To maintain state, we 422say: 423<blockquote> 424<pre> 425<select name=<span style="color:green">sel1</span>> 426<option value=<span style="color:red">"1"</span> <span style="color:blue">[=State.select(req, <span style="color:green">"sel1"</span>, <span style="color:red">"1")</span>]</span>> Option 1 427<option <span style="color:blue">[=State.select(req, <span style="color:green">"sel1"</span>, <span style="color:red">"Option 1"</span>)]</span>> <span style="color:red">Option 1</span> 428</select> 429</pre> 430</blockquote> 431 432<li> 433We query and create select options on the client-side using 434ajax/js/etc (for example, if the client chooses a country, we query 435a database and show the states for that country via another 436client-side select, created dynamically). Upon submission of this 437form, we still need to maintain the state of this option. To do 438this, we need to know, on the server side, the names of any new 439selects that are created on the client (and/or the names of 440initially empty selects that are re-populated on the client). 441Suppose, initially we have: 442 443<blockquote><pre> 444<select name=<span style="color:green">states</span>> 445</select> 446</pre></blockquote> 447 448On the client, we then add: 449<blockquote><pre> 450<select name=<span style="color:green">states</span>> 451<option> <span style="color:red">Pennsylvania</span> (generated on client) 452</select> 453</pre></blockquote> 454 455To maintain the state on the server for this option, we now have to 456say on the server-side (upon form submission): 457<blockquote><pre> 458<select name=<span style="color:green">states</span>> 459 <option <span style="color:blue">[=State.select(req, <span style="color:green">"states"</span>, </span><span style="color:red">"?"</span>)]><span style="color:red">Pennsylvania</span> (generated on client) 460<select> 461</pre></blockquote> 462 463But we don't know what value to put in <code><span style="color:red">"?"</span></code> 464on the server-side because <code><span style="color:red">Pennsylvania</span></code> was generated on the 465client. So we can do any of the following: 466<ol style="list-style: square"> 467<li>Rerun the query on the server, get the list of states again 468and say, for example something like: 469<blockquote> 470<pre> 471[[ 472if (...options were added by by client...) 473 { //maintain state 474 List option_list == ...create new {@link SelectOption}'s here [possibly via a query]... 475 out.print(" <select name=<span style="color:green">states</span>> "); 476 for (int n = 0; n < option_list.size(); n++) 477 { 478 {@link SelectOption} opt = (SelectOption) option_list.get(n); 479 String html = opt.getHTML(); 480 String val = opt.getValue(); 481 out.print(" <option val="); 482 our.print(val); 483 if (<span style="color:blue">State.select(req, <span style="color:green">"states"</span>, val)</span>) { 484 out.print(" selected "); 485 } 486 out.print(" > "); 487 out.print(html); 488 } 489 out.print(" </select> "); 490 } 491]] 492</pre></blockquote> 493But this (kind of) defeats the purpose of using ajax because we have to 494replicate the logic on the server. 495</li> 496<li> 497Another solution is to write out the possible values to be shown to 498the client as a javascript array on the page. Then the client js can 499show the contents of a an array depending on user choice. This saves 500a ajax call to the database. If we store the results of the query in 501a cache or a static variable, then we don't have to re-run the query 502every time and can simply rewrite the array from the cached query 503results. 504</li> 505<li> 506Another option is that when the form is submitted to the server, it 507sets a hidden field with the submitted value of the select. Upon 508recieving the page, javascript on the browser re-runs the query on 509the client side again and then uses the hidden field to restore the 510state of the select option. 511</li> 512</ol> 513<p>These issue only arise when select elements are being modified 514on the client side via Javascript. 515</li> 516</ol> 517 518@param req the HttpServletRequest 519@param selectName the name of the select field 520@param optionVal the value attribute of the option. If the 521 option has no option attribute, the html 522 text associated with that option. Browsers 523 do not submit leading spaces in the html 524 text so, for example for: <code> 525 "<option> Option 1"</code>, the 526 value would be "Option 1" 527 528*/ 529public static final String select(final HttpServletRequest req, 530 final String selectName, final String optionVal) 531 { 532 final String[] val = getParameterValues(req, selectName); 533 if (dbg) System.out.println(selectName+"="+Arrays.toString(val)); 534 535 if (val == null) 536 return ""; 537 538 for (int n = 0; n < val.length; n++) { 539 if (dbg) System.out.println(val[n] + ";" + optionVal + ";" + (optionVal.equals(val[n]) ? "true/checked" : "false") ); 540 if (optionVal.equals(val[n])) { 541 return "selected"; 542 } 543 } 544 545 return ""; 546 } 547 548 549/** 550Convenience method that creates a list of select options that 551maintain form state. Example: 552<blockquote><pre> 553[[ 554List list = (..create a list of {@link SelectOption}, possible from database lookup..) 555]] 556<select name=foo> 557[[ makeOptions(out, req, "foo", list); ]] 558</select> 559</pre></blockquote> 560 561@param out destination where the options will be printed 562@param req the current HttpServletRequest 563@param selectName the name of the select field 564@param optionList a list of objects of type {@link SelectOption} 565*/ 566public static void makeOptions(final PrintWriter out, 567 final HttpServletRequest req, 568 final String selectName, final List optionList) 569 { 570 final int size = optionList.size(); 571 for (int n = 0; n < size; n++) 572 { 573 SelectOption opt = (SelectOption) optionList.get(n); 574 String html = HTMLUtil.quoteToEntity(opt.getHTML()); 575 String val = opt.getValue(); 576 String escaped_val = HTMLUtil.quoteToEntity(val); 577 out.print("<option val='"); 578 out.print(escaped_val); 579 out.print("'"); 580 out.print(opt.selected() ? " selected " : " "); 581 out.print(State.select(req, selectName, val)); 582 out.print(">"); 583 out.print(html); 584 if ( (n + 1) < size) { 585 out.print("\n"); 586 } 587 } 588 } 589 590/** 591Convenience method that creates a list of select options that 592maintain form state. Returns the list of options as a string 593(rather than printing it to a printwriter as some other variants of 594this method do). Example: 595<blockquote><pre> 596[[ 597List list = (..create a list of {@link SelectOption}, possible from database lookup..) 598]] 599<select name=foo> 600[= makeOptions(req, "foo", list); ] 601</select> 602</pre></blockquote> 603 604@param req the current HttpServletRequest 605@param selectName the name of the select field 606@param optionList a list of objects of type {@link SelectOption} 607*/ 608public static String makeOptions(final HttpServletRequest req, 609 final String selectName, final List optionList) 610 { 611 final int size = optionList.size(); 612 final StringBuilder buf = new StringBuilder(size * 32); 613 for (int n = 0; n < size; n++) 614 { 615 SelectOption opt = (SelectOption) optionList.get(n); 616 String html = HTMLUtil.quoteToEntity(opt.getHTML()); 617 String val = opt.getValue(); 618 String escaped_val = HTMLUtil.quoteToEntity(val); 619 buf.append("<option val='"); 620 buf.append(escaped_val); 621 buf.append("'"); 622 buf.append(opt.selected() ? " selected " : " "); 623 buf.append(State.select(req, selectName, val)); 624 buf.append(">"); 625 buf.append(html); 626 if ( (n + 1) < size) { 627 buf.append("\n"); 628 } 629 } 630 return buf.toString(); 631 } 632 633 634 635 636/** 637Sets the value of the form element with the specified name. This 638method is useful to set initial values for the form. The initial 639values shown to the user can be different per user, for example, 640when the user is editing some data that already exists on the database. 641<p> 642This method can be invoked more than once. This is useful to set 643multiple values for the same field (for example, a select box 644with multiple selections or multiple checkboxes with the same name). 645<blockquote><pre> 646State.set(req, "checkbox1", "1.a"); 647State.set(req, "checkbox1", "1.b"); 648</pre></blockquote> 649*/ 650public static final void set( 651 final HttpServletRequest req, final String name, final String value) 652 { 653 final Object obj = req.getAttribute(name); 654 655 if (obj == null) { //obj not already present 656 req.setAttribute(name, value); 657 return; 658 } 659 660 //obj is present. could be a single string or string[] (list) 661 if (obj instanceof String) 662 { 663 //defaults to size of 10 which is fine for us 664 final ArrayList list = new ArrayList(); 665 666 list.add(obj); //save old single string value 667 list.add(value); //save new value 668 req.setAttribute(name, list); 669 } 670 else if (obj instanceof ArrayList) { 671 //append new string value to the list 672 ((ArrayList)obj).add(value); 673 } 674 else{ 675 throw new IllegalArgumentException("Only strings can be added. You are trying to add: " + obj + "/" + obj.getClass().getName()); 676 } 677 } 678 679private static final String cleared_key = "_fc.web.simpleforms.cleared"; 680 681/** 682The servlet api is written by retarded monkeys smoking crack....which 683is why there is no way to modify/remove/change/clear 684the parameters in the servlet request (the parameters map is read-only) 685..which leads to all sort of problems in html form processing. 686<p> 687This method changes the state of <b>all</b> fields such that methods 688that return state (text, textarea, radio etc) will act as if the 689form field had not been submitted by the user. However, any values 690set by the {@link set} method <i>after</i> invoking this method 691<i>will</i> be seen. 692<p> 693All this is really useful when form data has been saved and the 694user needs to be shown the same form, but with an empty (fresh) 695form state. So for example: 696<blockquote><pre> 697// At the top of a page 698String field_1 = req.getParameter("field_1"); 699String field_2 = req.getParameter("field_2"); 700 701Errors err = validate_and_save(field1, field2); 702if (err == null) { 703 State.<span style="color:blue">clear</span>(req); //req is the HttpServletRequest object 704 State.set("field_1", "enter a value"); //initial value for field_1 705 } 706 707<form> 708[[ if (err != null) { err.renderFormErrors(out); } ]] 709<input type=text name=field_1 value='[=State.text(req, "field_1")]'> 710<input type=text name=field_2 value='[=State.text(req, "field_2")]'> 711</form> 712</pre></blockquote> 713Note: redirecting the client to the form page also has the same 714effect (of clearing request parameters), because that forces a 715entirely new request object to be used on the server. 716*/ 717public static final void clear(final HttpServletRequest req) 718 { 719 Enumeration e = req.getAttributeNames(); 720 while (e.hasMoreElements()) { 721 req.removeAttribute((String)e.nextElement()); 722 } 723 724 req.setAttribute(cleared_key, ""); 725 } 726 727// ----------- escaped ---------------- 728/** 729Convenience method that returns: <code>{@link 730fc.util.HTMLUtil#quoteToEntity HTMLUtil.quoteToEntity}(text(req, name));</code> 731Useful for setting arbitrary values in the value="..." part 732of a text field. 733*/ 734public static final String escapedText( 735final HttpServletRequest req, final String name) 736 { 737 return HTMLUtil.quoteToEntity(text(req, name)); 738 } 739 740/** 741Convenience method that returns: <code>{@link 742fc.util.HTMLUtil#quoteToEntity(String) HTMLUtil.quoteToEntity}(password (req, name));</code> 743Useful for setting arbitrary values in the value="..." part 744of a password field. 745*/ 746public static final String escapedPassword( 747final HttpServletRequest req, final String name) 748 { 749 return HTMLUtil.quoteToEntity(password(req, name)); 750 } 751 752 753/** 754Convenience method that returns: <code>{@link 755fc.util.HTMLUtil#quoteToEntity(String) HTMLUtil.quoteToEntity}(hidden(req, name));</code> 756Useful for setting arbitrary values in the value="..." part 757of a hidden field. 758*/ 759public static final String escapedHidden( 760final HttpServletRequest req, final String name) 761 { 762 return HTMLUtil.quoteToEntity(hidden(req, name)); 763 } 764 765 766private static final String disabled_key = "_fc.web.simpleforms.disabled"; 767 768/** 769Convenience method that marks the specified field as disabled. This 770value can be later retrieved while rendering the form via the 771getDisabled or disabled methods. 772*/ 773public static final void setDisabled( 774 final HttpServletRequest req, final String name) 775 { 776 Set set = (Set) req.getAttribute(disabled_key); 777 if (set == null) { 778 set = new HashSet(); 779 req.setAttribute(disabled_key, set); 780 } 781 set.add(name); 782 } 783 784/** 785Returns true if the specified field was marked as disabled. 786Example usage: 787<blockquote><pre> 788[= State.getDisabled(req, "somefield") ? "disabled" : ""] 789</pre></blockquote> 790*/ 791public static final boolean getDisabled( 792 final HttpServletRequest req, final String name) 793 { 794 Set set = (Set) req.getAttribute(disabled_key); 795 if (set == null) { 796 return false; 797 } 798 return set.contains(name); 799 } 800 801/** 802Convenience method. Instead of saying: 803Example usage: 804<blockquote><pre> 805[= State.getDisabled(req, "somefield") ? "disabled" : ""] 806</pre></blockquote> 807this method allows one to say: 808<blockquote><pre> 809[= State.disabled(req, "somefield")] 810</pre></blockquote> 811*/ 812public static final String disabled( 813 final HttpServletRequest req, final String name) 814 { 815 if (getDisabled(req, name)) 816 return "disabled"; 817 else 818 return ""; 819 } 820 821} //~class State