2007-02-26 Igor Zelmanovich <igorz@mainsoft.com>
[mono.git] / mcs / class / System.Web / System.Web.UI / ClientScriptManager.cs
1 //
2 // System.Web.UI.ClientScriptManager.cs
3 //
4 // Authors:
5 //   Duncan Mak  (duncan@ximian.com)
6 //   Gonzalo Paniagua (gonzalo@ximian.com)
7 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
8 //   Lluis Sanchez (lluis@novell.com)
9 //
10 // (C) 2002,2003 Ximian, Inc. (http://www.ximian.com)
11 // (c) 2003 Novell, Inc. (http://www.novell.com)
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using System;
36 using System.Collections;
37 #if NET_2_0
38 using System.Collections.Generic;
39 #endif
40 using System.Text;
41 using System.Collections.Specialized;
42 using System.Web.Util;
43
44 namespace System.Web.UI
45 {
46         #if NET_2_0
47         public sealed
48         #else
49         internal
50         #endif
51                 class ClientScriptManager
52         {
53                 Hashtable registeredArrayDeclares;
54                 ScriptEntry clientScriptBlocks;
55                 ScriptEntry startupScriptBlocks;
56                 internal Hashtable hiddenFields;
57                 ScriptEntry submitStatements;
58                 ScriptEntry scriptIncludes;
59                 Page page;
60 #if NET_2_0
61                 List <int> eventValidationValues;
62                 Hashtable expandoAttributes;
63                 bool _hasRegisteredForEventValidationOnCallback;
64 #endif
65                 
66                 internal ClientScriptManager (Page page)
67                 {
68                         this.page = page;
69                 }
70
71 #if !NET_2_0
72                 public string GetPostBackClientEvent (Control control, string argument)
73                 {
74                         return GetPostBackEventReference (control, argument);
75                 }
76 #endif
77
78                 public string GetPostBackClientHyperlink (Control control, string argument)
79                 {
80                         return "javascript:" + GetPostBackEventReference (control, argument);
81                 }
82         
83 #if NET_2_0
84                 public string GetPostBackClientHyperlink (Control control, string argument, bool registerForEventValidation)
85                 {
86                         if (registerForEventValidation)
87                                 RegisterForEventValidation (control.UniqueID, argument);
88                         return "javascript:" + GetPostBackEventReference (control, argument);
89                 }
90 #endif          
91
92 #if !NET_2_0
93                 internal
94 #else
95                 public
96 #endif
97                 string GetPostBackEventReference (Control control, string argument)
98                 {
99                         if (control == null)
100                                 throw new ArgumentNullException ("control");
101                         
102                         page.RequiresPostBackScript ();
103 #if NET_2_0
104                         return String.Format ("{0}.__doPostBack('{1}','{2}')", page.theForm, control.UniqueID, argument);
105 #else
106                         return String.Format ("__doPostBack('{0}','{1}')", control.UniqueID, argument);
107 #endif
108                 }
109
110 #if NET_2_0
111                 public string GetPostBackEventReference (Control control, string argument, bool registerForEventValidation)
112                 {
113                         if (control == null)
114                                 throw new ArgumentNullException ("control");
115                         
116                         if (registerForEventValidation)
117                                 RegisterForEventValidation (control.UniqueID, argument);
118                         return GetPostBackEventReference (control, argument);
119                 }
120                 
121                 public string GetPostBackEventReference (PostBackOptions options, bool registerForEventValidation)
122                 {
123                         if (options == null)
124                                 throw new ArgumentNullException ("options");
125                         if (registerForEventValidation)
126                                 RegisterForEventValidation (options);
127                         return GetPostBackEventReference (options);
128                 }
129                 
130                 public string GetPostBackEventReference (PostBackOptions options)
131                 {
132                         if (options == null)
133                                 throw new ArgumentNullException ("options");
134
135                         if (options.ActionUrl == null && options.ValidationGroup == null && !options.TrackFocus && 
136                                 !options.AutoPostBack && !options.PerformValidation)
137                         {
138                                 if (!options.ClientSubmit)
139                                         return null;
140
141                                 if (options.RequiresJavaScriptProtocol)
142                                         return GetPostBackClientHyperlink (options.TargetControl, options.Argument);
143                                 else
144                                         return GetPostBackEventReference (options.TargetControl, options.Argument);
145                         }
146
147                         RegisterWebFormClientScript ();
148
149                         string actionUrl = options.ActionUrl;
150                         if (actionUrl != null)
151                                 RegisterHiddenField (Page.PreviousPageID, page.Request.FilePath);
152
153                         if(options.TrackFocus)
154                                 RegisterHiddenField (Page.LastFocusID, String.Empty);
155
156                         string prefix = options.RequiresJavaScriptProtocol ? "javascript:" : "";
157 #if TARGET_J2EE
158                         // Allow the page to transform ActionUrl to a portlet action url
159                         if (actionUrl != null && page.PortletNamespace != null) {
160                                 actionUrl = page.CreateActionUrl(actionUrl);
161                                 prefix += "Portal";
162                         }
163 #endif
164
165                         return String.Format ("{0}WebForm_DoPostback({1},{2},{3},{4},{5},{6},{7},{8},{9})", 
166                                         prefix,
167                                         ClientScriptManager.GetScriptLiteral (options.TargetControl.UniqueID), 
168                                         ClientScriptManager.GetScriptLiteral (options.Argument),
169                                         ClientScriptManager.GetScriptLiteral (actionUrl),
170                                         ClientScriptManager.GetScriptLiteral (options.AutoPostBack),
171                                         ClientScriptManager.GetScriptLiteral (options.PerformValidation),
172                                         ClientScriptManager.GetScriptLiteral (options.TrackFocus),
173                                         ClientScriptManager.GetScriptLiteral (options.ClientSubmit),
174                                         ClientScriptManager.GetScriptLiteral (options.ValidationGroup),
175                                         page.theForm
176                                 );
177                 }
178
179                 internal void RegisterWebFormClientScript ()
180                 {
181                         if (IsClientScriptIncludeRegistered (typeof (Page), "webform"))
182                                 return;
183
184                         RegisterClientScriptInclude (typeof (Page), "webform", GetWebResourceUrl (typeof (Page), "webform.js"));
185                         page.RequiresPostBackScript ();
186                 }
187                 
188                 public string GetCallbackEventReference (Control control, string argument, string clientCallback, string context)
189                 {
190                         return GetCallbackEventReference (control, argument, clientCallback, context, null, false);
191                 }
192
193                 public string GetCallbackEventReference (Control control, string argument, string clientCallback, string context, bool useAsync)
194                 {
195                         return GetCallbackEventReference (control, argument, clientCallback, context, null, useAsync);
196                 }
197
198                 public string GetCallbackEventReference (Control control, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)
199                 {
200                         if (control == null)
201                                 throw new ArgumentNullException ("control");
202                         if(!(control is ICallbackEventHandler))
203                                 throw new InvalidOperationException ("The control must implement the ICallbackEventHandler interface and provide a RaiseCallbackEvent method.");
204
205                         return GetCallbackEventReference (control.UniqueID, argument, clientCallback, context, clientErrorCallback, useAsync);
206                 }
207
208                 public string GetCallbackEventReference (string target, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)
209                 {
210                         RegisterWebFormClientScript ();
211                         
212                         return string.Format ("WebForm_DoCallback('{0}',{1},{2},{3},{4},{5},{6})", target, argument, clientCallback, context, ((clientErrorCallback == null) ? "null" : clientErrorCallback), (useAsync ? "true" : "false"), page.theForm);
213                 }
214 #endif
215                 
216 #if NET_2_0
217                 public
218 #else
219                 internal
220 #endif
221                 string GetWebResourceUrl(Type type, string resourceName)
222                 {
223                         if (type == null)
224                                 throw new ArgumentNullException ("type");
225                 
226                         if (resourceName == null || resourceName.Length == 0)
227                                 throw new ArgumentNullException ("type");
228                 
229                         return System.Web.Handlers.AssemblyResourceLoader.GetResourceUrl (type, resourceName); 
230                 }
231                 
232
233                 public bool IsClientScriptBlockRegistered (string key)
234                 {
235                         return IsScriptRegistered (clientScriptBlocks, GetType(), key);
236                 }
237         
238                 public bool IsClientScriptBlockRegistered (Type type, string key)
239                 {
240                         return IsScriptRegistered (clientScriptBlocks, type, key);
241                 }
242         
243                 public bool IsStartupScriptRegistered (string key)
244                 {
245                         return IsScriptRegistered (startupScriptBlocks, GetType(), key);
246                 }
247         
248                 public bool IsStartupScriptRegistered (Type type, string key)
249                 {
250                         return IsScriptRegistered (startupScriptBlocks, type, key);
251                 }
252                 
253                 public bool IsOnSubmitStatementRegistered (string key)
254                 {
255                         return IsScriptRegistered (submitStatements, GetType(), key);
256                 }
257         
258                 public bool IsOnSubmitStatementRegistered (Type type, string key)
259                 {
260                         return IsScriptRegistered (submitStatements, type, key);
261                 }
262                 
263                 public bool IsClientScriptIncludeRegistered (string key)
264                 {
265                         return IsScriptRegistered (scriptIncludes, GetType(), key);
266                 }
267         
268                 public bool IsClientScriptIncludeRegistered (Type type, string key)
269                 {
270                         return IsScriptRegistered (scriptIncludes, type, key);
271                 }
272                 
273                 bool IsScriptRegistered (ScriptEntry scriptList, Type type, string key)
274                 {
275                         while (scriptList != null) {
276                                 if (scriptList.Type == type && scriptList.Key == key)
277                                         return true;
278                                 scriptList = scriptList.Next;
279                         }
280                         return false;
281                 }
282                 
283                 public void RegisterArrayDeclaration (string arrayName, string arrayValue)
284                 {
285                         if (registeredArrayDeclares == null)
286                                 registeredArrayDeclares = new Hashtable();
287         
288                         if (!registeredArrayDeclares.ContainsKey (arrayName))
289                                 registeredArrayDeclares.Add (arrayName, new ArrayList());
290         
291                         ((ArrayList) registeredArrayDeclares[arrayName]).Add(arrayValue);
292                 }
293         
294                 void RegisterScript (ref ScriptEntry scriptList, Type type, string key, string script, bool addScriptTags)
295                 {
296                         ScriptEntry last = null;
297                         ScriptEntry entry = scriptList;
298
299                         while (entry != null) {
300                                 if (entry.Type == type && entry.Key == key)
301                                         return;
302                                 last = entry;
303                                 entry = entry.Next;
304                         }
305                         
306                         if (addScriptTags)
307                                 script = "<script language=javascript>\n<!--\n" + script + "\n// -->\n</script>";
308
309                         entry = new ScriptEntry (type, key, script);
310                         
311                         if (last != null) last.Next = entry;
312                         else scriptList = entry;
313                 }
314         
315                 internal void RegisterClientScriptBlock (string key, string script)
316                 {
317                         RegisterScript (ref clientScriptBlocks, GetType(), key, script, false);
318                 }
319         
320                 public void RegisterClientScriptBlock (Type type, string key, string script)
321                 {
322                         RegisterClientScriptBlock (type, key, script, false);
323                 }
324         
325                 public void RegisterClientScriptBlock (Type type, string key, string script, bool addScriptTags)
326                 {
327                         if (type == null)
328                                 throw new ArgumentNullException ("type");
329
330                         RegisterScript (ref clientScriptBlocks, type, key, script, addScriptTags);
331                 }
332         
333                 public void RegisterHiddenField (string hiddenFieldName, string hiddenFieldInitialValue)
334                 {
335                         if (hiddenFields == null)
336                                 hiddenFields = new Hashtable ();
337
338                         if (!hiddenFields.ContainsKey (hiddenFieldName))
339                                 hiddenFields.Add (hiddenFieldName, hiddenFieldInitialValue);
340                 }
341         
342                 internal void RegisterOnSubmitStatement (string key, string script)
343                 {
344                         RegisterScript (ref submitStatements, GetType (), key, script, false);
345                 }
346         
347                 public void RegisterOnSubmitStatement (Type type, string key, string script)
348                 {
349                         if (type == null)
350                                 throw new ArgumentNullException ("type");
351                         
352                         RegisterScript (ref submitStatements, type, key, script, false);
353                 }
354         
355                 internal void RegisterStartupScript (string key, string script)
356                 {
357                         RegisterScript (ref startupScriptBlocks, GetType(), key, script, false);
358                 }
359                 
360                 public void RegisterStartupScript (Type type, string key, string script)
361                 {
362                         RegisterStartupScript (type, key, script, false);
363                 }
364                 
365                 public void RegisterStartupScript (Type type, string key, string script, bool addScriptTags)
366                 {
367                         if (type == null)
368                                 throw new ArgumentNullException ("type");
369
370                         RegisterScript (ref startupScriptBlocks, type, key, script, addScriptTags);
371                 }
372
373                 public void RegisterClientScriptInclude (string key, string url)
374                 {
375                         RegisterClientScriptInclude (GetType (), key, url);
376                 }
377                 
378                 public void RegisterClientScriptInclude (Type type, string key, string url)
379                 {
380                         if (type == null)
381                                 throw new ArgumentNullException ("type");
382                         if (url == null || url.Length == 0)
383                                 throw new ArgumentException ("url");
384
385                         RegisterScript (ref scriptIncludes, type, key, url, false);
386                 }
387
388 #if NET_2_0
389                 public void RegisterClientScriptResource (Type type, string resourceName)
390                 {
391                         RegisterScript (ref scriptIncludes, type, "resource-" + resourceName, GetWebResourceUrl (type, resourceName), false);
392                 }
393
394                 public void RegisterExpandoAttribute (string controlId, string attributeName, string attributeValue)
395                 {
396                         RegisterExpandoAttribute (controlId, attributeName, attributeValue, true);
397                 }
398
399                 public void RegisterExpandoAttribute (string controlId, string attributeName, string attributeValue, bool encode)
400                 {
401                         if (controlId == null)
402                                 throw new ArgumentNullException ("controlId");
403
404                         if (attributeName == null)
405                                 throw new ArgumentNullException ("attributeName");
406                         
407                         if (expandoAttributes == null)
408                                 expandoAttributes = new Hashtable ();
409
410                         ListDictionary list = (ListDictionary)expandoAttributes [controlId];
411                         if (list == null) {
412                                 list = new ListDictionary ();
413                                 expandoAttributes [controlId] = list;
414                         }
415
416                         list.Add (attributeName, encode ? StrUtils.EscapeQuotesAndBackslashes (attributeValue) : attributeValue);
417                 }
418                 
419                 // Implemented following the description in http://odetocode.com/Blogs/scott/archive/2006/03/20/3145.aspx
420                 private int CalculateEventHash (string uniqueId, string argument)
421                 {
422                         int uniqueIdHash = uniqueId.GetHashCode ();
423                         int argumentHash = String.IsNullOrEmpty (argument) ? 0 : argument.GetHashCode ();
424                         return (uniqueIdHash ^ argumentHash);
425                 }
426                 
427                 public void RegisterForEventValidation (PostBackOptions options)
428                 {
429                         // MS.NET does not check for options == null, so we won't too...
430                         RegisterForEventValidation (options.TargetControl.UniqueID, options.Argument);
431                 }
432                 
433                 public void RegisterForEventValidation (string uniqueId)
434                 {
435                         RegisterForEventValidation (uniqueId, null);
436                 }
437                 
438                 public void RegisterForEventValidation (string uniqueId, string argument)
439                 {
440                         if (!page.EnableEventValidation)
441                                 return;
442                         if (uniqueId == null || uniqueId.Length == 0)
443                                 return;
444                         if (page.IsCallback)
445                                 _hasRegisteredForEventValidationOnCallback = true;
446                         else if (page.LifeCycle < PageLifeCycle.Render)
447                                 throw new InvalidOperationException ("RegisterForEventValidation may only be called from the Render method");
448                         if (eventValidationValues == null)
449                                 eventValidationValues = new List <int> ();
450
451                         
452                         int hash = CalculateEventHash (uniqueId, argument);
453                         if (eventValidationValues.BinarySearch (hash) < 0)
454                                 eventValidationValues.Add (hash);
455                 }
456
457                 public void ValidateEvent (string uniqueId)
458                 {
459                         ValidateEvent (uniqueId, null);
460                 }
461
462                 public void ValidateEvent (string uniqueId, string argument)
463                 {
464                         if (uniqueId == null || uniqueId.Length == 0)
465                                 throw new ArgumentException ("must not be null or empty", "uniqueId");
466                         if (!page.EnableEventValidation)
467                                 return;
468                         if (eventValidationValues == null)
469                                 goto bad;
470                         
471                         int hash = CalculateEventHash (uniqueId, argument);
472                         if (eventValidationValues.BinarySearch (hash) < 0)
473                                 goto bad;
474                         return;
475                         
476                         bad:
477                         throw new ArgumentException ("Invalid postback or callback argument. Event validation is enabled using <pages enableEventValidation=\"true\"/> in configuration or <%@ Page EnableEventValidation=\"true\" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.");
478                 }
479 #endif
480                 void WriteScripts (HtmlTextWriter writer, ScriptEntry scriptList)
481                 {
482                         while (scriptList != null) {
483                                 writer.WriteLine (scriptList.Script);
484                                 scriptList = scriptList.Next;
485                         }
486                 }
487
488 #if NET_2_0
489                 internal void RestoreEventValidationState (string fieldValue)
490                 {
491                         if (!page.EnableEventValidation || fieldValue == null || fieldValue.Length == 0)
492                                 return;
493                         IStateFormatter fmt = page.GetFormatter ();
494                         int [] eventValues = (int []) fmt.Deserialize (fieldValue);
495 #if TARGET_JVM // FIXME: No support yet for passing 'int[]' as 'T[]'
496                         eventValidationValues = new List<int> (eventValues.Length);
497                         for (int i = 0; i < eventValues.Length; i++)
498                                 eventValidationValues.Add(eventValues[i]);
499 #else
500                         eventValidationValues = new List<int> (eventValues);
501 #endif
502                         eventValidationValues.Sort ();
503                 }
504                 
505                 internal void SaveEventValidationState ()
506                 {
507                         if (!page.EnableEventValidation)
508                                 return;
509
510                         string eventValidation = GetEventValidationStateFormatted ();
511                         if (eventValidation == null)
512                                 return;
513
514                         RegisterHiddenField (EventStateFieldName, eventValidation);
515                 }
516
517                 internal string GetEventValidationStateFormatted ()
518                 {
519                         if (eventValidationValues == null || eventValidationValues.Count == 0)
520                                 return null;
521
522                         if(page.IsCallback && !_hasRegisteredForEventValidationOnCallback)
523                                 return null;
524
525                         IStateFormatter fmt = page.GetFormatter ();
526                         int [] array = new int [eventValidationValues.Count];
527 #if TARGET_JVM // FIXME: No support yet for passing 'int[]' as 'T[]'
528                         ((ICollection)eventValidationValues).CopyTo (array, 0);
529 #else
530                         eventValidationValues.CopyTo (array);
531 #endif
532                         return fmt.Serialize (array);
533                 }
534
535                 internal string EventStateFieldName
536                 {
537                         get { return "__EVENTVALIDATION"; }
538                 }
539
540                 internal void WriteExpandoAttributes (HtmlTextWriter writer)
541                 {
542                         if (expandoAttributes == null)
543                                 return;
544
545                         writer.WriteLine ();
546                         WriteBeginScriptBlock (writer);
547
548                         foreach (string controlId in expandoAttributes.Keys) {
549                                 writer.WriteLine ("var {0} = document.all ? document.all [\"{0}\"] : document.getElementById (\"{0}\");", controlId);
550                                 ListDictionary attrs = (ListDictionary) expandoAttributes [controlId];
551                                 foreach (string attributeName in attrs.Keys) {
552                                         writer.WriteLine ("{0}.{1} = \"{2}\";", controlId, attributeName, attrs [attributeName]);
553                                 }
554                         }
555                         WriteEndScriptBlock (writer);
556                         writer.WriteLine ();
557                 }
558
559 #endif
560                 internal void WriteBeginScriptBlock (HtmlTextWriter writer)
561                 {
562                         writer.WriteLine ("<script"+
563 #if !NET_2_0
564                                 " language=\"javascript\""+
565 #endif
566                                 " type=\"text/javascript\">");
567                         writer.WriteLine ("<!--");
568                 }
569
570                 internal void WriteEndScriptBlock (HtmlTextWriter writer)
571                 {
572                         writer.WriteLine ("// -->");
573                         writer.WriteLine ("</script>");
574                 }
575                 
576                 internal void WriteHiddenFields (HtmlTextWriter writer)
577                 {
578                         if (hiddenFields == null)
579                                 return;
580         
581                         foreach (string key in hiddenFields.Keys) {
582                                 string value = hiddenFields [key] as string;
583                                 writer.WriteLine ("<input type=\"hidden\" name=\"{0}\" id=\"{0}\" value=\"{1}\" />", key, value);
584                         }
585         
586                         hiddenFields = null;
587                 }
588                 
589                 internal void WriteClientScriptIncludes (HtmlTextWriter writer)
590                 {
591                         ScriptEntry entry = scriptIncludes;
592                         while (entry != null) {
593                                 if (!entry.Rendered) {
594 #if TARGET_J2EE
595                                         if (!page.IsPortletRender)
596 #endif
597                                                 writer.WriteLine ("\n<script src=\"{0}\" type=\"text/javascript\"></script>", entry.Script);
598 #if TARGET_J2EE
599                                         else {
600                                                 string scriptKey = "inc_" + entry.Key.GetHashCode ().ToString ("X");
601                                                 writer.WriteLine ("\n<script type=\"text/javascript\">");
602                                                 writer.WriteLine ("<!--");
603                                                 writer.WriteLine ("if (document.{0} == null) {{", scriptKey);
604                                                 writer.WriteLine ("\tdocument.{0} = true", scriptKey);
605                                                 writer.WriteLine ("\tdocument.write('<script src=\"{0}\" type=\"text/javascript\"><\\/script>'); }}", entry.Script);
606                                                 writer.WriteLine ("// -->");
607                                                 writer.WriteLine ("</script>");
608                                         }
609 #endif
610                                         entry.Rendered = true;
611                                 }
612                                 entry = entry.Next;
613                         }
614                 }
615                 
616                 internal void WriteClientScriptBlocks (HtmlTextWriter writer)
617                 {
618                         WriteScripts (writer, clientScriptBlocks);
619                 }
620         
621                 internal void WriteStartupScriptBlocks (HtmlTextWriter writer)
622                 {
623                         WriteScripts (writer, startupScriptBlocks);
624                 }
625         
626                 internal void WriteArrayDeclares (HtmlTextWriter writer)
627                 {
628                         if (registeredArrayDeclares != null) {
629                                 writer.WriteLine();
630                                 WriteBeginScriptBlock (writer);
631                                 IDictionaryEnumerator arrayEnum = registeredArrayDeclares.GetEnumerator();
632                                 while (arrayEnum.MoveNext()) {
633                                         writer.Write("\tvar ");
634                                         writer.Write(arrayEnum.Key);
635                                         writer.Write(" =  new Array(");
636                                         IEnumerator arrayListEnum = ((ArrayList) arrayEnum.Value).GetEnumerator();
637                                         bool isFirst = true;
638                                         while (arrayListEnum.MoveNext()) {
639                                                 if (isFirst)
640                                                         isFirst = false;
641                                                 else
642                                                         writer.Write(", ");
643                                                 writer.Write(arrayListEnum.Current);
644                                         }
645                                         writer.WriteLine(");");
646 #if TARGET_J2EE
647                                         // in addition, add a form array declaration
648                                         if (page.IsPortletRender) {
649                                                 writer.Write ("\t" + page.theForm + ".");
650                                                 writer.Write (arrayEnum.Key);
651                                                 writer.Write (" = ");
652                                                 writer.Write (arrayEnum.Key);
653                                                 writer.WriteLine (";");
654                                         }
655 #endif
656                                 }
657                                 WriteEndScriptBlock (writer);
658                                 writer.WriteLine ();
659                         }
660                 }
661
662 #if NET_2_0
663                 internal string GetClientValidationEvent (string validationGroup) {
664                         string eventScript = "if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate('" + validationGroup + "');";
665 #if TARGET_J2EE
666                         if (page.IsPortletRender)
667                                 return "if (typeof(SetValidatorContext) == 'function') SetValidatorContext ('" + page.theForm + "'); " + eventScript;
668 #endif
669                         return eventScript;
670                 }
671 #endif
672
673                 internal string GetClientValidationEvent ()
674                 {
675                         string eventScript = "if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate();";
676 #if TARGET_J2EE
677                         if (page.IsPortletRender)
678                                 return "if (typeof(SetValidatorContext) == 'function') SetValidatorContext ('" + page.theForm + "'); " + eventScript;
679 #endif
680                         return eventScript;
681                 }
682
683
684                 internal string WriteSubmitStatements ()
685                 {
686                         if (submitStatements == null) return null;
687                         
688                         StringBuilder sb = new StringBuilder ();
689                         ScriptEntry entry = submitStatements;
690                         while (entry != null) {
691 #if NET_2_0
692                                 sb.Append (EnsureEndsWithSemicolon (entry.Script));
693 #else
694                                 sb.Append (entry.Script);
695 #endif
696                                 entry = entry.Next;
697                         }
698 #if NET_2_0
699                         RegisterClientScriptBlock ("HtmlForm-OnSubmitStatemen",
700 @"<script type=""text/javascript"">
701 <!--
702 " + page.theForm + @".WebForm_OnSubmit = function () {
703 " + sb.ToString () + @"
704 return true;
705 }
706 // -->
707 </script>");
708                         return "javascript:return this.WebForm_OnSubmit();";
709
710 #else
711                         return sb.ToString ();
712 #endif
713                 }
714                 
715                 [MonoTODO ("optimize s.Replace")]
716                 internal static string GetScriptLiteral (object ob)
717                 {
718                         if (ob == null)
719                                 return "null";
720                         else if (ob is string) {
721                                 string s = (string)ob;
722                                 s = s.Replace ("\\", "\\\\");
723                                 s = s.Replace ("\"", "\\\"");
724                                 return "\"" + s + "\"";
725                         } else if (ob is bool) {
726                                 return ob.ToString().ToLower();
727                         } else {
728                                 return ob.ToString ();
729                         }
730                 }
731                 
732                 class ScriptEntry
733                 {
734                         public Type Type;
735                         public string Key;
736                         public string Script;
737                         public ScriptEntry Next;
738                         public bool Rendered;
739                          
740                         public ScriptEntry (Type type, string key, string script)
741                         {
742                                 Key = key;
743                                 Type = type;
744                                 Script = script;
745                         }
746                 }
747
748 #if NET_2_0
749                 // helper method
750                 internal static string EnsureEndsWithSemicolon (string value) {
751                         if (value != null && value.Length > 0 && !value.EndsWith (";"))
752                                 return value += ";";
753                         return value;
754                 }
755 #endif
756         }
757 }