2007-07-24 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 using System.Globalization;
44
45 namespace System.Web.UI
46 {
47         #if NET_2_0
48         public sealed
49         #else
50         internal
51         #endif
52                 class ClientScriptManager
53         {
54                 Hashtable registeredArrayDeclares;
55                 ScriptEntry clientScriptBlocks;
56                 ScriptEntry startupScriptBlocks;
57                 internal Hashtable hiddenFields;
58                 ScriptEntry submitStatements;
59                 Page page;
60 #if NET_2_0
61                 int [] eventValidationValues;
62                 int eventValidationPos = 0;
63                 Hashtable expandoAttributes;
64                 bool _hasRegisteredForEventValidationOnCallback;
65 #endif
66                 
67                 internal ClientScriptManager (Page page)
68                 {
69                         this.page = page;
70                 }
71
72 #if !NET_2_0
73                 public string GetPostBackClientEvent (Control control, string argument)
74                 {
75                         return GetPostBackEventReference (control, argument);
76                 }
77 #endif
78
79                 public string GetPostBackClientHyperlink (Control control, string argument)
80                 {
81                         return "javascript:" + GetPostBackEventReference (control, argument);
82                 }
83         
84 #if NET_2_0
85                 public string GetPostBackClientHyperlink (Control control, string argument, bool registerForEventValidation)
86                 {
87                         if (registerForEventValidation)
88                                 RegisterForEventValidation (control.UniqueID, argument);
89                         return "javascript:" + GetPostBackEventReference (control, argument);
90                 }
91 #endif          
92
93 #if !NET_2_0
94                 internal
95 #else
96                 public
97 #endif
98                 string GetPostBackEventReference (Control control, string argument)
99                 {
100                         if (control == null)
101                                 throw new ArgumentNullException ("control");
102                         
103                         page.RequiresPostBackScript ();
104 #if NET_2_0
105                         return String.Format ("{0}.__doPostBack('{1}','{2}')", page.theForm, control.UniqueID, argument);
106 #else
107                         return String.Format ("__doPostBack('{0}','{1}')", control.UniqueID, argument);
108 #endif
109                 }
110
111 #if NET_2_0
112                 public string GetPostBackEventReference (Control control, string argument, bool registerForEventValidation)
113                 {
114                         if (control == null)
115                                 throw new ArgumentNullException ("control");
116                         
117                         if (registerForEventValidation)
118                                 RegisterForEventValidation (control.UniqueID, argument);
119                         return GetPostBackEventReference (control, argument);
120                 }
121                 
122                 public string GetPostBackEventReference (PostBackOptions options, bool registerForEventValidation)
123                 {
124                         if (options == null)
125                                 throw new ArgumentNullException ("options");
126                         if (registerForEventValidation)
127                                 RegisterForEventValidation (options);
128                         return GetPostBackEventReference (options);
129                 }
130                 
131                 public string GetPostBackEventReference (PostBackOptions options)
132                 {
133                         if (options == null)
134                                 throw new ArgumentNullException ("options");
135
136                         if (options.ActionUrl == null && options.ValidationGroup == null && !options.TrackFocus && 
137                                 !options.AutoPostBack && !options.PerformValidation)
138                         {
139                                 if (!options.ClientSubmit)
140                                         return null;
141
142                                 if (options.RequiresJavaScriptProtocol)
143                                         return GetPostBackClientHyperlink (options.TargetControl, options.Argument);
144                                 else
145                                         return GetPostBackEventReference (options.TargetControl, options.Argument);
146                         }
147
148                         RegisterWebFormClientScript ();
149
150                         string actionUrl = options.ActionUrl;
151                         if (actionUrl != null)
152                                 RegisterHiddenField (Page.PreviousPageID, page.Request.FilePath);
153
154                         if(options.TrackFocus)
155                                 RegisterHiddenField (Page.LastFocusID, String.Empty);
156
157                         string prefix = options.RequiresJavaScriptProtocol ? "javascript:" : "";
158 #if TARGET_J2EE
159                         // Allow the page to transform ActionUrl to a portlet action url
160                         if (actionUrl != null && page.PortletNamespace != null) {
161                                 actionUrl = page.CreateActionUrl(actionUrl);
162                                 prefix += "Portal";
163                         }
164 #endif
165
166                         return String.Format ("{0}WebForm_DoPostback({1},{2},{3},{4},{5},{6},{7},{8},{9})", 
167                                         prefix,
168                                         ClientScriptManager.GetScriptLiteral (options.TargetControl.UniqueID), 
169                                         ClientScriptManager.GetScriptLiteral (options.Argument),
170                                         ClientScriptManager.GetScriptLiteral (actionUrl),
171                                         ClientScriptManager.GetScriptLiteral (options.AutoPostBack),
172                                         ClientScriptManager.GetScriptLiteral (options.PerformValidation),
173                                         ClientScriptManager.GetScriptLiteral (options.TrackFocus),
174                                         ClientScriptManager.GetScriptLiteral (options.ClientSubmit),
175                                         ClientScriptManager.GetScriptLiteral (options.ValidationGroup),
176                                         page.theForm
177                                 );
178                 }
179
180                 internal void RegisterWebFormClientScript ()
181                 {
182                         if (_webFormClientScriptRequired)
183                                 return;
184
185                         page.RequiresPostBackScript ();
186                         _webFormClientScriptRequired = true;
187                 }
188
189                 bool _webFormClientScriptRendered;
190                 bool _webFormClientScriptRequired;
191
192                 internal void WriteWebFormClientScript (HtmlTextWriter writer) {
193                         if (!_webFormClientScriptRendered && _webFormClientScriptRequired) {
194                                 writer.WriteLine ();
195                                 WriteClientScriptInclude (writer, GetWebResourceUrl (typeof (Page), "webform.js"));
196                                 _webFormClientScriptRendered = true;
197                         }
198                 }
199                 
200                 public string GetCallbackEventReference (Control control, string argument, string clientCallback, string context)
201                 {
202                         return GetCallbackEventReference (control, argument, clientCallback, context, null, false);
203                 }
204
205                 public string GetCallbackEventReference (Control control, string argument, string clientCallback, string context, bool useAsync)
206                 {
207                         return GetCallbackEventReference (control, argument, clientCallback, context, null, useAsync);
208                 }
209
210                 public string GetCallbackEventReference (Control control, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)
211                 {
212                         if (control == null)
213                                 throw new ArgumentNullException ("control");
214                         if(!(control is ICallbackEventHandler))
215                                 throw new InvalidOperationException ("The control must implement the ICallbackEventHandler interface and provide a RaiseCallbackEvent method.");
216
217                         return GetCallbackEventReference ("'" + control.UniqueID + "'", argument, clientCallback, context, clientErrorCallback, useAsync);
218                 }
219
220                 public string GetCallbackEventReference (string target, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)
221                 {
222                         RegisterWebFormClientScript ();
223                         
224                         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);
225                 }
226 #endif
227                 
228 #if NET_2_0
229                 public
230 #else
231                 internal
232 #endif
233                 string GetWebResourceUrl(Type type, string resourceName)
234                 {
235                         if (type == null)
236                                 throw new ArgumentNullException ("type");
237                 
238                         if (resourceName == null || resourceName.Length == 0)
239                                 throw new ArgumentNullException ("type");
240                 
241                         return System.Web.Handlers.AssemblyResourceLoader.GetResourceUrl (type, resourceName); 
242                 }
243                 
244
245                 public bool IsClientScriptBlockRegistered (string key)
246                 {
247                         return IsScriptRegistered (clientScriptBlocks, GetType(), key);
248                 }
249         
250                 public bool IsClientScriptBlockRegistered (Type type, string key)
251                 {
252                         return IsScriptRegistered (clientScriptBlocks, type, key);
253                 }
254         
255                 public bool IsStartupScriptRegistered (string key)
256                 {
257                         return IsScriptRegistered (startupScriptBlocks, GetType(), key);
258                 }
259         
260                 public bool IsStartupScriptRegistered (Type type, string key)
261                 {
262                         return IsScriptRegistered (startupScriptBlocks, type, key);
263                 }
264                 
265                 public bool IsOnSubmitStatementRegistered (string key)
266                 {
267                         return IsScriptRegistered (submitStatements, GetType(), key);
268                 }
269         
270                 public bool IsOnSubmitStatementRegistered (Type type, string key)
271                 {
272                         return IsScriptRegistered (submitStatements, type, key);
273                 }
274                 
275                 public bool IsClientScriptIncludeRegistered (string key)
276                 {
277                         return IsClientScriptIncludeRegistered (GetType (), key);
278                 }
279         
280                 public bool IsClientScriptIncludeRegistered (Type type, string key)
281                 {
282                         return IsScriptRegistered (clientScriptBlocks, type, "include-" + key);
283                 }
284                 
285                 bool IsScriptRegistered (ScriptEntry scriptList, Type type, string key)
286                 {
287                         while (scriptList != null) {
288                                 if (scriptList.Type == type && scriptList.Key == key)
289                                         return true;
290                                 scriptList = scriptList.Next;
291                         }
292                         return false;
293                 }
294                 
295                 public void RegisterArrayDeclaration (string arrayName, string arrayValue)
296                 {
297                         if (registeredArrayDeclares == null)
298                                 registeredArrayDeclares = new Hashtable();
299         
300                         if (!registeredArrayDeclares.ContainsKey (arrayName))
301                                 registeredArrayDeclares.Add (arrayName, new ArrayList());
302         
303                         ((ArrayList) registeredArrayDeclares[arrayName]).Add(arrayValue);
304                 }
305
306                 void RegisterScript (ref ScriptEntry scriptList, Type type, string key, string script, bool addScriptTags)
307                 {
308                         RegisterScript (ref scriptList, type, key, script, addScriptTags ? ScriptEntryFormat.AddScriptTag : ScriptEntryFormat.None);
309                 }
310
311                 void RegisterScript (ref ScriptEntry scriptList, Type type, string key, string script, ScriptEntryFormat format)
312                 {
313                         ScriptEntry last = null;
314                         ScriptEntry entry = scriptList;
315
316                         while (entry != null) {
317                                 if (entry.Type == type && entry.Key == key)
318                                         return;
319                                 last = entry;
320                                 entry = entry.Next;
321                         }
322
323                         entry = new ScriptEntry (type, key, script, format);
324                         
325                         if (last != null) last.Next = entry;
326                         else scriptList = entry;
327                 }
328         
329                 internal void RegisterClientScriptBlock (string key, string script)
330                 {
331                         RegisterScript (ref clientScriptBlocks, GetType(), key, script, false);
332                 }
333         
334                 public void RegisterClientScriptBlock (Type type, string key, string script)
335                 {
336                         RegisterClientScriptBlock (type, key, script, false);
337                 }
338         
339                 public void RegisterClientScriptBlock (Type type, string key, string script, bool addScriptTags)
340                 {
341                         if (type == null)
342                                 throw new ArgumentNullException ("type");
343
344                         RegisterScript (ref clientScriptBlocks, type, key, script, addScriptTags);
345                 }
346         
347                 public void RegisterHiddenField (string hiddenFieldName, string hiddenFieldInitialValue)
348                 {
349                         if (hiddenFields == null)
350                                 hiddenFields = new Hashtable ();
351
352                         if (!hiddenFields.ContainsKey (hiddenFieldName))
353                                 hiddenFields.Add (hiddenFieldName, hiddenFieldInitialValue);
354                 }
355         
356                 internal void RegisterOnSubmitStatement (string key, string script)
357                 {
358                         RegisterScript (ref submitStatements, GetType (), key, script, false);
359                 }
360         
361                 public void RegisterOnSubmitStatement (Type type, string key, string script)
362                 {
363                         if (type == null)
364                                 throw new ArgumentNullException ("type");
365                         
366                         RegisterScript (ref submitStatements, type, key, script, false);
367                 }
368         
369                 internal void RegisterStartupScript (string key, string script)
370                 {
371                         RegisterScript (ref startupScriptBlocks, GetType(), key, script, false);
372                 }
373                 
374                 public void RegisterStartupScript (Type type, string key, string script)
375                 {
376                         RegisterStartupScript (type, key, script, false);
377                 }
378                 
379                 public void RegisterStartupScript (Type type, string key, string script, bool addScriptTags)
380                 {
381                         if (type == null)
382                                 throw new ArgumentNullException ("type");
383
384                         RegisterScript (ref startupScriptBlocks, type, key, script, addScriptTags);
385                 }
386
387                 public void RegisterClientScriptInclude (string key, string url)
388                 {
389                         RegisterClientScriptInclude (GetType (), key, url);
390                 }
391                 
392                 public void RegisterClientScriptInclude (Type type, string key, string url)
393                 {
394                         if (type == null)
395                                 throw new ArgumentNullException ("type");
396                         if (url == null || url.Length == 0)
397                                 throw new ArgumentException ("url");
398
399                         RegisterScript (ref clientScriptBlocks, type, "include-" + key, url, ScriptEntryFormat.Include);
400                 }
401
402 #if NET_2_0
403                 public void RegisterClientScriptResource (Type type, string resourceName)
404                 {
405                         RegisterScript (ref clientScriptBlocks, type, "resource-" + resourceName, GetWebResourceUrl (type, resourceName), ScriptEntryFormat.Include);
406                 }
407
408                 public void RegisterExpandoAttribute (string controlId, string attributeName, string attributeValue)
409                 {
410                         RegisterExpandoAttribute (controlId, attributeName, attributeValue, true);
411                 }
412
413                 public void RegisterExpandoAttribute (string controlId, string attributeName, string attributeValue, bool encode)
414                 {
415                         if (controlId == null)
416                                 throw new ArgumentNullException ("controlId");
417
418                         if (attributeName == null)
419                                 throw new ArgumentNullException ("attributeName");
420                         
421                         if (expandoAttributes == null)
422                                 expandoAttributes = new Hashtable ();
423
424                         ListDictionary list = (ListDictionary)expandoAttributes [controlId];
425                         if (list == null) {
426                                 list = new ListDictionary ();
427                                 expandoAttributes [controlId] = list;
428                         }
429
430                         list.Add (attributeName, encode ? StrUtils.EscapeQuotesAndBackslashes (attributeValue) : attributeValue);
431                 }
432
433                 private void EnsureEventValidationArray ()
434                 {
435                         if (eventValidationValues == null)
436                                 eventValidationValues = new int [64];
437
438                         int len = eventValidationValues.Length;
439
440                         if (eventValidationPos >= len) {
441                                 int [] tmp = new int [len * 2];
442                                 Array.Copy (eventValidationValues, tmp, len);
443                                 eventValidationValues = tmp;
444                         }
445                 }
446
447                 internal void ResetEventValidationState ()
448                 {
449                         eventValidationPos = 0;
450                 }
451
452                 // Implemented following the description in http://odetocode.com/Blogs/scott/archive/2006/03/20/3145.aspx
453                 private int CalculateEventHash (string uniqueId, string argument)
454                 {
455                         int uniqueIdHash = uniqueId.GetHashCode ();
456                         int argumentHash = String.IsNullOrEmpty (argument) ? 0 : argument.GetHashCode ();
457                         return (uniqueIdHash ^ argumentHash);
458                 }
459                 
460                 public void RegisterForEventValidation (PostBackOptions options)
461                 {
462                         // MS.NET does not check for options == null, so we won't too...
463                         RegisterForEventValidation (options.TargetControl.UniqueID, options.Argument);
464                 }
465                 
466                 public void RegisterForEventValidation (string uniqueId)
467                 {
468                         RegisterForEventValidation (uniqueId, null);
469                 }
470                 
471                 public void RegisterForEventValidation (string uniqueId, string argument)
472                 {
473                         if (!page.EnableEventValidation)
474                                 return;
475                         if (uniqueId == null || uniqueId.Length == 0)
476                                 return;
477                         if (page.IsCallback)
478                                 _hasRegisteredForEventValidationOnCallback = true;
479                         else if (page.LifeCycle < PageLifeCycle.Render)
480                                 throw new InvalidOperationException ("RegisterForEventValidation may only be called from the Render method");
481
482                         EnsureEventValidationArray ();
483                         
484                         int hash = CalculateEventHash (uniqueId, argument);
485                         for (int i = 0; i < eventValidationPos; i++)
486                                 if (eventValidationValues [i] == hash)
487                                         return;
488                         eventValidationValues [eventValidationPos++] = hash;
489                 }
490
491                 public void ValidateEvent (string uniqueId)
492                 {
493                         ValidateEvent (uniqueId, null);
494                 }
495
496                 public void ValidateEvent (string uniqueId, string argument)
497                 {
498                         if (uniqueId == null || uniqueId.Length == 0)
499                                 throw new ArgumentException ("must not be null or empty", "uniqueId");
500                         if (!page.EnableEventValidation)
501                                 return;
502                         if (eventValidationValues == null)
503                                 goto bad;
504                         
505                         int hash = CalculateEventHash (uniqueId, argument);
506                         for (int i = 0; i < eventValidationValues.Length; i++)
507                                 if (eventValidationValues [i] == hash)
508                                         return;
509                         
510                         bad:
511                         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.");
512                 }
513 #endif
514                 void WriteScripts (HtmlTextWriter writer, ScriptEntry scriptList)
515                 {
516                         if (scriptList == null)
517                                 return;
518
519                         writer.WriteLine ();
520
521                         while (scriptList != null) {
522                                 switch (scriptList.Format) {
523                                 case ScriptEntryFormat.AddScriptTag:
524                                         EnsureBeginScriptBlock (writer);
525                                         writer.Write (scriptList.Script);
526                                         break;
527                                 case ScriptEntryFormat.Include:
528                                         EnsureEndScriptBlock (writer);
529                                         WriteClientScriptInclude (writer, scriptList.Script);
530                                         break;
531                                 default:
532                                         EnsureEndScriptBlock (writer);
533                                         writer.WriteLine (scriptList.Script);
534                                         break;
535                                 }
536                                 scriptList = scriptList.Next;
537                         }
538                         EnsureEndScriptBlock (writer);
539                 }
540
541                 bool _scriptTagOpened;
542
543                 void EnsureBeginScriptBlock (HtmlTextWriter writer) {
544                         if (!_scriptTagOpened) {
545                                 WriteBeginScriptBlock (writer);
546                                 _scriptTagOpened = true;
547                         }
548                 }
549
550                 void EnsureEndScriptBlock (HtmlTextWriter writer) {
551                         if (_scriptTagOpened) {
552                                 WriteEndScriptBlock (writer);
553                                 _scriptTagOpened = false;
554                         }
555                 }
556
557 #if NET_2_0
558                 internal void RestoreEventValidationState (string fieldValue)
559                 {
560                         if (!page.EnableEventValidation || fieldValue == null || fieldValue.Length == 0)
561                                 return;
562                         IStateFormatter fmt = page.GetFormatter ();
563                         eventValidationValues = (int []) fmt.Deserialize (fieldValue);
564                         eventValidationPos = eventValidationValues.Length;
565                 }
566                 
567                 internal void SaveEventValidationState ()
568                 {
569                         if (!page.EnableEventValidation)
570                                 return;
571
572                         string eventValidation = GetEventValidationStateFormatted ();
573                         if (eventValidation == null)
574                                 return;
575
576                         RegisterHiddenField (EventStateFieldName, eventValidation);
577                 }
578
579                 internal string GetEventValidationStateFormatted ()
580                 {
581                         if (eventValidationValues == null || eventValidationValues.Length == 0)
582                                 return null;
583
584                         if(page.IsCallback && !_hasRegisteredForEventValidationOnCallback)
585                                 return null;
586
587                         IStateFormatter fmt = page.GetFormatter ();
588                         int [] array = new int [eventValidationPos];
589                         Array.Copy (eventValidationValues, array, eventValidationPos);
590                         return fmt.Serialize (array);
591                 }
592
593                 internal string EventStateFieldName
594                 {
595                         get { return "__EVENTVALIDATION"; }
596                 }
597
598                 internal void WriteExpandoAttributes (HtmlTextWriter writer)
599                 {
600                         if (expandoAttributes == null)
601                                 return;
602
603                         writer.WriteLine ();
604                         WriteBeginScriptBlock (writer);
605
606                         foreach (string controlId in expandoAttributes.Keys) {
607                                 writer.WriteLine ("var {0} = document.all ? document.all [\"{0}\"] : document.getElementById (\"{0}\");", controlId);
608                                 ListDictionary attrs = (ListDictionary) expandoAttributes [controlId];
609                                 foreach (string attributeName in attrs.Keys) {
610                                         writer.WriteLine ("{0}.{1} = \"{2}\";", controlId, attributeName, attrs [attributeName]);
611                                 }
612                         }
613                         WriteEndScriptBlock (writer);
614                         writer.WriteLine ();
615                 }
616
617 #endif
618                 internal static void WriteBeginScriptBlock (HtmlTextWriter writer)
619                 {
620                         writer.WriteLine ("<script"+
621 #if !NET_2_0
622                                 " language=\"javascript\""+
623 #endif
624                                 " type=\"text/javascript\">");
625                         writer.WriteLine ("<!--");
626                 }
627
628                 internal static void WriteEndScriptBlock (HtmlTextWriter writer)
629                 {
630                         writer.WriteLine ("// -->");
631                         writer.WriteLine ("</script>");
632                 }
633                 
634                 internal void WriteHiddenFields (HtmlTextWriter writer)
635                 {
636                         if (hiddenFields == null)
637                                 return;
638
639                         writer.RenderBeginTag (HtmlTextWriterTag.Div);
640                         foreach (string key in hiddenFields.Keys) {
641                                 string value = hiddenFields [key] as string;
642                                 writer.WriteLine ("<input type=\"hidden\" name=\"{0}\" id=\"{0}\" value=\"{1}\" />", key, value);
643                         }
644                         writer.RenderEndTag (); // DIV
645                         hiddenFields = null;
646                 }
647                 
648                 internal void WriteClientScriptInclude (HtmlTextWriter writer, string path) {
649 #if TARGET_J2EE
650                                         if (!page.IsPortletRender)
651 #endif
652                                                 writer.WriteLine ("<script src=\"{0}\" type=\"text/javascript\"></script>", path);
653 #if TARGET_J2EE
654                                         else {
655                                                 string scriptKey = "inc_" + path.GetHashCode ().ToString ("X");
656                                                 writer.WriteLine ("<script type=\"text/javascript\">");
657                                                 writer.WriteLine ("<!--");
658                                                 writer.WriteLine ("if (document.{0} == null) {{", scriptKey);
659                                                 writer.WriteLine ("\tdocument.{0} = true", scriptKey);
660                                                 writer.WriteLine ("\tdocument.write('<script src=\"{0}\" type=\"text/javascript\"><\\/script>'); }}", path);
661                                                 writer.WriteLine ("// -->");
662                                                 writer.WriteLine ("</script>");
663                                         }
664 #endif
665                                         }
666                 
667                 internal void WriteClientScriptBlocks (HtmlTextWriter writer)
668                 {
669                         WriteScripts (writer, clientScriptBlocks);
670                 }
671         
672                 internal void WriteStartupScriptBlocks (HtmlTextWriter writer)
673                 {
674                         WriteScripts (writer, startupScriptBlocks);
675                 }
676         
677                 internal void WriteArrayDeclares (HtmlTextWriter writer)
678                 {
679                         if (registeredArrayDeclares != null) {
680                                 writer.WriteLine();
681                                 WriteBeginScriptBlock (writer);
682                                 IDictionaryEnumerator arrayEnum = registeredArrayDeclares.GetEnumerator();
683                                 while (arrayEnum.MoveNext()) {
684                                         writer.Write("\tvar ");
685                                         writer.Write(arrayEnum.Key);
686                                         writer.Write(" =  new Array(");
687                                         IEnumerator arrayListEnum = ((ArrayList) arrayEnum.Value).GetEnumerator();
688                                         bool isFirst = true;
689                                         while (arrayListEnum.MoveNext()) {
690                                                 if (isFirst)
691                                                         isFirst = false;
692                                                 else
693                                                         writer.Write(", ");
694                                                 writer.Write(arrayListEnum.Current);
695                                         }
696                                         writer.WriteLine(");");
697 #if TARGET_J2EE
698                                         // in addition, add a form array declaration
699                                         if (page.IsPortletRender) {
700                                                 writer.Write ("\t" + page.theForm + ".");
701                                                 writer.Write (arrayEnum.Key);
702                                                 writer.Write (" = ");
703                                                 writer.Write (arrayEnum.Key);
704                                                 writer.WriteLine (";");
705                                         }
706 #endif
707                                 }
708                                 WriteEndScriptBlock (writer);
709                                 writer.WriteLine ();
710                         }
711                 }
712
713 #if NET_2_0
714                 internal string GetClientValidationEvent (string validationGroup) {
715                         string eventScript = "if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate('" + validationGroup + "');";
716 #if TARGET_J2EE
717                         if (page.IsPortletRender)
718                                 return "if (typeof(SetValidatorContext) == 'function') SetValidatorContext ('" + page.theForm + "'); " + eventScript;
719 #endif
720                         return eventScript;
721                 }
722 #endif
723
724                 internal string GetClientValidationEvent ()
725                 {
726                         string eventScript = "if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate();";
727 #if TARGET_J2EE
728                         if (page.IsPortletRender)
729                                 return "if (typeof(SetValidatorContext) == 'function') SetValidatorContext ('" + page.theForm + "'); " + eventScript;
730 #endif
731                         return eventScript;
732                 }
733
734
735                 internal string WriteSubmitStatements ()
736                 {
737                         if (submitStatements == null) return null;
738                         
739                         StringBuilder sb = new StringBuilder ();
740                         ScriptEntry entry = submitStatements;
741                         while (entry != null) {
742 #if NET_2_0
743                                 sb.Append (EnsureEndsWithSemicolon (entry.Script));
744 #else
745                                 sb.Append (entry.Script);
746 #endif
747                                 entry = entry.Next;
748                         }
749 #if NET_2_0
750                         RegisterClientScriptBlock ("HtmlForm-OnSubmitStatemen",
751 @"<script type=""text/javascript"">
752 <!--
753 " + page.theForm + @".WebForm_OnSubmit = function () {
754 " + sb.ToString () + @"
755 return true;
756 }
757 // -->
758 </script>");
759                         return "javascript:return this.WebForm_OnSubmit();";
760
761 #else
762                         return sb.ToString ();
763 #endif
764                 }
765                 
766                 [MonoTODO ("optimize s.Replace")]
767                 internal static string GetScriptLiteral (object ob)
768                 {
769                         if (ob == null)
770                                 return "null";
771                         else if (ob is string) {
772                                 string s = (string)ob;
773                                 s = s.Replace ("\\", "\\\\");
774                                 s = s.Replace ("\"", "\\\"");
775                                 return "\"" + s + "\"";
776                         } else if (ob is bool) {
777                                 return ob.ToString ().ToLower (CultureInfo.InvariantCulture);
778                         } else {
779                                 return ob.ToString ();
780                         }
781                 }
782
783                 sealed class ScriptEntry
784                 {
785                         public readonly Type Type;
786                         public readonly string Key;
787                         public readonly string Script;
788                         public readonly ScriptEntryFormat Format;
789                         public ScriptEntry Next;
790
791                         public ScriptEntry (Type type, string key, string script, ScriptEntryFormat format) {
792                                 Key = key;
793                                 Type = type;
794                                 Script = script;
795                                 Format = format;
796                         }
797                 }
798
799                 enum ScriptEntryFormat
800                 {
801                         None,
802                         AddScriptTag,
803                         Include,
804                 }
805
806 #if NET_2_0
807                 // helper method
808                 internal static string EnsureEndsWithSemicolon (string value) {
809                         if (value != null && value.Length > 0 && value [value.Length - 1] != ';')
810                                 return value += ";";
811                         return value;
812                 }
813 #endif
814         }
815 }