Implemented RegisterHiddenField
[mono.git] / mcs / class / System.Web.Extensions / System.Web.UI / ScriptManager.cs
1 //
2 // ScriptManager.cs
3 //
4 // Author:
5 //   Igor Zelmanovich <igorz@mainsoft.com>
6 //
7 // (C) 2007 Mainsoft, Inc.  http://www.mainsoft.com
8 //
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System;
31 using System.Collections.Generic;
32 using System.Text;
33 using System.ComponentModel;
34 using System.Security.Permissions;
35 using System.Collections.Specialized;
36 using System.Collections;
37 using System.Web.Handlers;
38 using System.Reflection;
39 using System.Web.Configuration;
40 using System.Web.UI.HtmlControls;
41 using System.IO;
42 using System.Globalization;
43 using System.Threading;
44
45 namespace System.Web.UI
46 {
47         [ParseChildrenAttribute (true)]
48         [DefaultPropertyAttribute ("Scripts")]
49         [DesignerAttribute ("System.Web.UI.Design.ScriptManagerDesigner, System.Web.Extensions.Design, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
50         [NonVisualControlAttribute]
51         [PersistChildrenAttribute (false)]
52         [AspNetHostingPermissionAttribute (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
53         [AspNetHostingPermissionAttribute (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
54         public class ScriptManager : Control, IPostBackDataHandler
55         {
56                 // the keywords are used in fomatting async response
57                 const string updatePanel = "updatePanel";
58                 const string hiddenField = "hiddenField";
59                 const string arrayDeclaration = "arrayDeclaration";
60                 const string scriptBlock = "scriptBlock";
61                 const string expando = "expando";
62                 const string onSubmit = "onSubmit";
63                 const string asyncPostBackControlIDs = "asyncPostBackControlIDs";
64                 const string postBackControlIDs = "postBackControlIDs";
65                 const string updatePanelIDs = "updatePanelIDs";
66                 const string asyncPostBackTimeout = "asyncPostBackTimeout";
67                 const string childUpdatePanelIDs = "childUpdatePanelIDs";
68                 const string panelsToRefreshIDs = "panelsToRefreshIDs";
69                 const string formAction = "formAction";
70                 const string dataItem = "dataItem";
71                 const string dataItemJson = "dataItemJson";
72                 const string scriptDispose = "scriptDispose";
73                 const string pageRedirect = "pageRedirect";
74                 const string error = "error";
75                 const string pageTitle = "pageTitle";
76                 const string focus = "focus";
77                 const string scriptContentNoTags = "ScriptContentNoTags";
78                 const string scriptContentWithTags = "ScriptContentWithTags";
79                 const string scriptPath = "ScriptPath";
80
81                 int _asyncPostBackTimeout = 90;
82                 List<Control> _asyncPostBackControls;
83                 List<Control> _postBackControls;
84                 List<UpdatePanel> _updatePanels;
85                 ScriptReferenceCollection _scripts;
86                 bool _isInAsyncPostBack;
87                 string _asyncPostBackSourceElementID;
88                 ScriptMode _scriptMode = ScriptMode.Auto;
89                 bool _enableScriptGlobalization;
90                 bool _enableScriptLocalization;
91                 string _scriptPath;
92                 ScriptEntry _clientScriptBlocks;
93                 ScriptEntry _startupScriptBlocks;
94                 List<ArrayDeclaration> _arrayDeclarations;
95                 Hashtable _hiddenFields;
96
97                 [DefaultValue (true)]
98                 [Category ("Behavior")]
99                 public bool AllowCustomErrorsRedirect {
100                         get {
101                                 throw new NotImplementedException ();
102                         }
103                         set {
104                                 throw new NotImplementedException ();
105                         }
106                 }
107
108                 [Category ("Behavior")]
109                 [DefaultValue ("")]
110                 public string AsyncPostBackErrorMessage {
111                         get {
112                                 throw new NotImplementedException ();
113                         }
114                         set {
115                                 throw new NotImplementedException ();
116                         }
117                 }
118
119                 [Browsable (false)]
120                 public string AsyncPostBackSourceElementID {
121                         get {
122                                 if(_asyncPostBackSourceElementID==null)
123                                         return String.Empty;
124                                 return _asyncPostBackSourceElementID;
125                         }
126                 }
127
128                 [DefaultValue (90)]
129                 [Category ("Behavior")]
130                 public int AsyncPostBackTimeout {
131                         get {
132                                 return _asyncPostBackTimeout;
133                         }
134                         set {
135                                 _asyncPostBackTimeout = value;
136                         }
137                 }
138
139                 [Category ("Behavior")]
140                 [MergableProperty (false)]
141                 [DefaultValue ("")]
142                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
143                 [PersistenceMode (PersistenceMode.InnerProperty)]
144                 public AuthenticationServiceManager AuthenticationService {
145                         get {
146                                 throw new NotImplementedException ();
147                         }
148                 }
149
150                 [Category ("Behavior")]
151                 [DefaultValue (false)]
152                 public bool EnablePageMethods {
153                         get {
154                                 throw new NotImplementedException ();
155                         }
156                         set {
157                                 throw new NotImplementedException ();
158                         }
159                 }
160
161                 [DefaultValue (true)]
162                 [Category ("Behavior")]
163                 public bool EnablePartialRendering {
164                         get {
165                                 throw new NotImplementedException ();
166                         }
167                         set {
168                                 throw new NotImplementedException ();
169                         }
170                 }
171
172                 [DefaultValue (false)]
173                 [Category ("Behavior")]
174                 public bool EnableScriptGlobalization {
175                         get {
176                                 return _enableScriptGlobalization;
177                         }
178                         set {
179                                 _enableScriptGlobalization = value;
180                         }
181                 }
182
183                 [Category ("Behavior")]
184                 [DefaultValue (false)]
185                 public bool EnableScriptLocalization {
186                         get {
187                                 return _enableScriptLocalization;
188                         }
189                         set {
190                                 _enableScriptLocalization = value;
191                         }
192                 }
193
194                 [Browsable (false)]
195                 public bool IsDebuggingEnabled {
196                         get {
197                                 if (IsDeploymentRetail)
198                                         return false;
199
200                                 CompilationSection compilation = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation");
201                                 if (!compilation.Debug && (ScriptMode == ScriptMode.Auto || ScriptMode == ScriptMode.Inherit))
202                                         return false;
203
204                                 if (ScriptMode == ScriptMode.Release)
205                                         return false;
206
207                                 return true;
208                         }
209                 }
210
211                 bool IsDeploymentRetail {
212                         get {
213                                 DeploymentSection deployment = (DeploymentSection) WebConfigurationManager.GetSection ("system.web/deployment");
214                                 return deployment.Retail;
215                         }
216                 }
217
218                 [Browsable (false)]
219                 public bool IsInAsyncPostBack {
220                         get {
221                                 return _isInAsyncPostBack;
222                         }
223                 }
224
225                 [Category ("Behavior")]
226                 [DefaultValue (true)]
227                 public bool LoadScriptsBeforeUI {
228                         get {
229                                 throw new NotImplementedException ();
230                         }
231                         set {
232                                 throw new NotImplementedException ();
233                         }
234                 }
235
236                 [PersistenceMode (PersistenceMode.InnerProperty)]
237                 [DefaultValue ("")]
238                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
239                 [Category ("Behavior")]
240                 [MergableProperty (false)]
241                 public ProfileServiceManager ProfileService {
242                         get {
243                                 throw new NotImplementedException ();
244                         }
245                 }
246
247                 [Category ("Behavior")]
248                 public ScriptMode ScriptMode {
249                         get {
250                                 return _scriptMode;
251                         }
252                         set {
253                                 if (value == ScriptMode.Inherit)
254                                         value = ScriptMode.Auto;
255                                 _scriptMode = value;
256                         }
257                 }
258
259                 [DefaultValue ("")]
260                 [Category ("Behavior")]
261                 public string ScriptPath {
262                         get {
263                                 if (_scriptPath == null)
264                                         return String.Empty;
265                                 return _scriptPath;
266                         }
267                         set {
268                                 _scriptPath = value;
269                         }
270                 }
271
272                 [PersistenceMode (PersistenceMode.InnerProperty)]
273                 [DefaultValue ("")]
274                 [Category ("Behavior")]
275                 [MergableProperty (false)]
276                 public ScriptReferenceCollection Scripts {
277                         get {
278                                 if (_scripts == null)
279                                         _scripts = new ScriptReferenceCollection ();
280
281                                 return _scripts;
282                         }
283                 }
284
285                 [PersistenceMode (PersistenceMode.InnerProperty)]
286                 [DefaultValue ("")]
287                 [MergableProperty (false)]
288                 [Category ("Behavior")]
289                 public ServiceReferenceCollection Services {
290                         get {
291                                 throw new NotImplementedException ();
292                         }
293                 }
294
295                 [DefaultValue (true)]
296                 [Browsable (false)]
297                 public bool SupportsPartialRendering {
298                         get {
299                                 throw new NotImplementedException ();
300                         }
301                         set {
302                                 throw new NotImplementedException ();
303                         }
304                 }
305
306                 [EditorBrowsable (EditorBrowsableState.Never)]
307                 [Browsable (false)]
308                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
309                 public override bool Visible {
310                         get {
311                                 return true;
312                         }
313                         set {
314                                 throw new NotImplementedException ();
315                         }
316                 }
317
318                 [Category ("Action")]
319                 public event EventHandler<AsyncPostBackErrorEventArgs> AsyncPostBackError;
320
321                 [Category ("Action")]
322                 public event EventHandler<ScriptReferenceEventArgs> ResolveScriptReference;
323
324                 public static ScriptManager GetCurrent (Page page)
325                 {
326                         HttpContext ctx = HttpContext.Current;
327                         if (ctx == null)
328                                 return null;
329
330                         return (ScriptManager) ctx.Items [page];
331                 }
332                 
333                 static void SetCurrent (Page page, ScriptManager instance) {
334                         HttpContext ctx = HttpContext.Current;
335                         ctx.Items [page] = instance;
336                 }
337
338                 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection)
339                 {
340                         _isInAsyncPostBack = true;
341                         string arg = postCollection [postDataKey];
342                         if (!String.IsNullOrEmpty (arg)) {
343                                 string [] args = arg.Split ('|');
344                                 Control c = Page.FindControl (args [0]);
345                                 UpdatePanel up = c as UpdatePanel;
346                                 if (up != null && up.ChildrenAsTriggers)
347                                         up.Update ();
348                                 _asyncPostBackSourceElementID = args[1];
349                         }
350                         return false;
351                 }
352
353                 protected internal virtual void OnAsyncPostBackError (AsyncPostBackErrorEventArgs e)
354                 {
355                         if (AsyncPostBackError != null)
356                                 AsyncPostBackError (this, e);
357                 }
358
359                 protected override void OnInit (EventArgs e)
360                 {
361                         base.OnInit (e);
362
363                         if (GetCurrent (Page) != null)
364                                 throw new InvalidOperationException ("Only one instance of a ScriptManager can be added to the page.");
365
366                         SetCurrent (Page, this);
367                 }
368
369                 protected override void OnPreRender (EventArgs e)
370                 {
371                         base.OnPreRender (e);
372
373                         if (IsInAsyncPostBack) {
374                                 Page.SetRenderMethodDelegate (RenderPageCallback);
375                         }
376                         else {
377                                 if (EnableScriptGlobalization) {
378                                         CultureInfo culture = Thread.CurrentThread.CurrentCulture;
379                                         string script = null; // TODO: Json serialization of culture
380                                         RegisterClientScriptBlock (this, typeof (ScriptManager), "ScriptGlobalization", script, true);
381                                 }
382
383                                 // Register Scripts
384                                 foreach (ScriptReference script in GetScriptReferences ()) {
385                                         OnResolveScriptReference (new ScriptReferenceEventArgs (script));
386                                         RegisterScriptReference (script);
387                                 }
388
389                                 // Register startup script
390                                 RegisterStartupScript (this, typeof (ScriptManager), "Sys.Application.initialize();", "Sys.Application.initialize();", true);
391                         }
392                 }
393
394                 IEnumerable GetScriptReferences () {
395                         ScriptReference script;
396
397                         script = new ScriptReference ("MicrosoftAjax.js", String.Empty);
398                         script.NotifyScriptLoaded = false;
399                         yield return script;
400
401                         script = new ScriptReference ("MicrosoftAjaxWebForms.js", String.Empty);
402                         script.NotifyScriptLoaded = false;
403                         yield return script;
404
405                         if (_scripts != null && _scripts.Count > 0) {
406                                 for (int i = 0; i < _scripts.Count; i++) {
407                                         yield return _scripts [i];
408                                 }
409                         }
410                 }
411
412                 protected virtual void OnResolveScriptReference (ScriptReferenceEventArgs e)
413                 {
414                         if (ResolveScriptReference != null)
415                                 ResolveScriptReference (this, e);
416                 }
417
418                 protected virtual void RaisePostDataChangedEvent ()
419                 {
420                         throw new NotImplementedException ();
421                 }
422
423                 public static void RegisterArrayDeclaration (Control control, string arrayName, string arrayValue)
424                 {
425                         RegisterArrayDeclaration (control.Page, arrayName, arrayValue);
426                 }
427
428                 public static void RegisterArrayDeclaration (Page page, string arrayName, string arrayValue)
429                 {
430                         ScriptManager sm = GetCurrent (page);
431                         if (sm.IsInAsyncPostBack)
432                                 sm.RegisterArrayDeclaration (arrayName, arrayValue);
433                         else
434                                 page.ClientScript.RegisterArrayDeclaration (arrayName, arrayValue);
435                 }
436
437                 void RegisterArrayDeclaration (string arrayName, string arrayValue) {
438                         if (_arrayDeclarations == null)
439                                 _arrayDeclarations = new List<ArrayDeclaration> ();
440
441                         _arrayDeclarations.Add(new ArrayDeclaration(arrayName, arrayValue));
442                 }
443
444                 public void RegisterAsyncPostBackControl (Control control)
445                 {
446                         if(control==null)
447                                 return;
448
449                         if (_asyncPostBackControls == null)
450                                 _asyncPostBackControls = new List<Control> ();
451
452                         if (_asyncPostBackControls.Contains (control))
453                                 return;
454
455                         _asyncPostBackControls.Add (control);
456                 }
457
458                 public static void RegisterClientScriptBlock (Control control, Type type, string key, string script, bool addScriptTags)
459                 {
460                         RegisterClientScriptBlock (control.Page, type, key, script, addScriptTags);
461                 }
462
463                 public static void RegisterClientScriptBlock (Page page, Type type, string key, string script, bool addScriptTags)
464                 {
465                         ScriptManager sm = GetCurrent (page);
466                         if (sm.IsInAsyncPostBack)
467                                 RegisterScript (ref sm._clientScriptBlocks, type, key, script, addScriptTags ? ScriptEntryType.ScriptContentNoTags : ScriptEntryType.ScriptContentWithTags);
468                         else
469                                 page.ClientScript.RegisterClientScriptBlock (type, key, script, addScriptTags);
470                 }
471
472                 public static void RegisterClientScriptInclude (Control control, Type type, string key, string url)
473                 {
474                         RegisterClientScriptInclude (control.Page, type, key, url);
475                 }
476
477                 public static void RegisterClientScriptInclude (Page page, Type type, string key, string url)
478                 {
479                         ScriptManager sm = GetCurrent (page);
480                         if (sm.IsInAsyncPostBack)
481                                 RegisterScript (ref sm._clientScriptBlocks, type, key, url, ScriptEntryType.ScriptPath);
482                         else
483                                 page.ClientScript.RegisterClientScriptInclude (type, key, url);
484                 }
485
486                 public static void RegisterClientScriptResource (Control control, Type type, string resourceName)
487                 {
488                         RegisterClientScriptResource (control.Page, type, resourceName);
489                 }
490
491                 public static void RegisterClientScriptResource (Page page, Type type, string resourceName)
492                 {
493                         RegisterClientScriptInclude (page, type, "resource-" + resourceName, ScriptResourceHandler.GetResourceUrl (type, resourceName));
494                 }
495
496                 void RegisterScriptReference (ScriptReference script) {
497                         
498                         bool isDebugMode = IsDeploymentRetail ? false : (script.ScriptModeInternal == ScriptMode.Inherit ? IsDebuggingEnabled : (script.ScriptModeInternal == ScriptMode.Debug));
499                         string url;
500                         if (!String.IsNullOrEmpty (script.Path)) {
501                                 url = GetScriptName (ResolveClientUrl (script.Path), isDebugMode, EnableScriptLocalization ? script.ResourceUICultures : null);
502                         }
503                         else if (!String.IsNullOrEmpty (script.Name)) {
504                                 Assembly assembly;
505                                 if (String.IsNullOrEmpty (script.Assembly))
506                                         assembly = typeof (ScriptManager).Assembly;
507                                 else
508                                         assembly = Assembly.Load (script.Assembly);
509                                 string name = GetScriptName (script.Name, isDebugMode, null);
510                                 if (script.IgnoreScriptPath || String.IsNullOrEmpty (ScriptPath))
511                                         url = ScriptResourceHandler.GetResourceUrl (assembly, name, script.NotifyScriptLoaded);
512                                 else {
513                                         AssemblyName an = assembly.GetName ();
514                                         url = ResolveClientUrl (String.Concat (VirtualPathUtility.AppendTrailingSlash (ScriptPath), an.Name, '/', an.Version, '/', name));
515                                 }
516                         }
517                         else {
518                                 throw new InvalidOperationException ("Name and Path cannot both be empty.");
519                         }
520
521                         RegisterClientScriptInclude (this, typeof (ScriptManager), url, url);
522                 }
523
524                 static string GetScriptName (string releaseName, bool isDebugMode, string [] supportedUICultures) {
525                         if (!isDebugMode && (supportedUICultures == null || supportedUICultures.Length == 0))
526                                 return releaseName;
527
528                         if (releaseName.Length < 3 || !releaseName.EndsWith (".js", StringComparison.OrdinalIgnoreCase))
529                                 throw new InvalidOperationException (String.Format ("'{0}' is not a valid script path.  The path must end in '.js'.", releaseName));
530
531                         StringBuilder sb = new StringBuilder (releaseName);
532                         sb.Length -= 3;
533                         if (isDebugMode)
534                                 sb.Append (".debug");
535                         string culture=Thread.CurrentThread.CurrentUICulture.Name;
536                         if (supportedUICultures != null && Array.IndexOf<string> (supportedUICultures, culture) >= 0)
537                                 sb.AppendFormat (".{0}", culture);
538                         sb.Append (".js");
539
540                         return sb.ToString ();
541                 }
542
543                 public void RegisterDataItem (Control control, string dataItem)
544                 {
545                         throw new NotImplementedException ();
546                 }
547
548                 public void RegisterDataItem (Control control, string dataItem, bool isJsonSerialized)
549                 {
550                         throw new NotImplementedException ();
551                 }
552
553                 public void RegisterDispose (Control control, string disposeScript)
554                 {
555                         throw new NotImplementedException ();
556                 }
557
558                 public static void RegisterExpandoAttribute (Control control, string controlId, string attributeName, string attributeValue, bool encode)
559                 {
560                         throw new NotImplementedException ();
561                 }
562
563                 public static void RegisterHiddenField (Control control, string hiddenFieldName, string hiddenFieldInitialValue)
564                 {
565                         RegisterHiddenField (control.Page, hiddenFieldName, hiddenFieldInitialValue);
566                 }
567
568                 public static void RegisterHiddenField (Page page, string hiddenFieldName, string hiddenFieldInitialValue)
569                 {
570                         ScriptManager sm = GetCurrent (page);
571                         if (sm.IsInAsyncPostBack)
572                                 sm.RegisterHiddenField (hiddenFieldName, hiddenFieldInitialValue);
573                         else
574                                 page.ClientScript.RegisterHiddenField (hiddenFieldName, hiddenFieldInitialValue);
575                 }
576
577                 void RegisterHiddenField (string hiddenFieldName, string hiddenFieldInitialValue) {
578                         if (_hiddenFields == null)
579                                 _hiddenFields = new Hashtable ();
580
581                         if (!_hiddenFields.ContainsKey (hiddenFieldName))
582                                 _hiddenFields.Add (hiddenFieldName, hiddenFieldInitialValue);
583                 }
584
585                 public static void RegisterOnSubmitStatement (Control control, Type type, string key, string script)
586                 {
587                         throw new NotImplementedException ();
588                 }
589
590                 public static void RegisterOnSubmitStatement (Page page, Type type, string key, string script)
591                 {
592                         throw new NotImplementedException ();
593                 }
594
595                 public void RegisterPostBackControl (Control control)
596                 {
597                         if (control == null)
598                                 return;
599
600                         if (_postBackControls == null)
601                                 _postBackControls = new List<Control> ();
602
603                         if (_postBackControls.Contains (control))
604                                 return;
605
606                         _postBackControls.Add (control);
607                 }
608
609                 internal void RegisterUpdatePanel (UpdatePanel updatePanel) {
610                         if (_updatePanels == null)
611                                 _updatePanels = new List<UpdatePanel> ();
612
613                         if (_updatePanels.Contains (updatePanel))
614                                 return;
615
616                         _updatePanels.Add (updatePanel);
617                 }
618
619                 public void RegisterScriptDescriptors (IExtenderControl extenderControl)
620                 {
621                         throw new NotImplementedException ();
622                 }
623
624                 public void RegisterScriptDescriptors (IScriptControl scriptControl)
625                 {
626                         throw new NotImplementedException ();
627                 }
628
629                 public static void RegisterStartupScript (Control control, Type type, string key, string script, bool addScriptTags)
630                 {
631                         RegisterStartupScript (control.Page, type, key, script, addScriptTags);
632                 }
633
634                 public static void RegisterStartupScript (Page page, Type type, string key, string script, bool addScriptTags)
635                 {
636                         ScriptManager sm = GetCurrent (page);
637                         if (sm.IsInAsyncPostBack)
638                                 RegisterScript (ref sm._startupScriptBlocks, type, key, script, addScriptTags ? ScriptEntryType.ScriptContentNoTags : ScriptEntryType.ScriptContentWithTags);
639                         else
640                                 page.ClientScript.RegisterStartupScript (type, key, script, addScriptTags);
641                 }
642
643                 static void RegisterScript (ref ScriptEntry scriptList, Type type, string key, string script, ScriptEntryType scriptEntryType) {
644                         ScriptEntry last = null;
645                         ScriptEntry entry = scriptList;
646
647                         while (entry != null) {
648                                 if (entry.Type == type && entry.Key == key)
649                                         return;
650                                 last = entry;
651                                 entry = entry.Next;
652                         }
653
654                         entry = new ScriptEntry (type, key, script, scriptEntryType);
655
656                         if (last != null)
657                                 last.Next = entry;
658                         else
659                                 scriptList = entry;
660                 }
661
662                 protected override void Render (HtmlTextWriter writer)
663                 {
664                         // MSDN: This method is used by control developers to extend the ScriptManager control. 
665                         // Notes to Inheritors: 
666                         // When overriding this method, call the base Render(HtmlTextWriter) method 
667                         // so that PageRequestManager is rendered on the page.
668                         writer.WriteLine ("<script type=\"text/javascript\">");
669                         writer.WriteLine ("//<![CDATA[");
670                         writer.WriteLine ("Sys.WebForms.PageRequestManager._initialize('{0}', document.getElementById('{1}'));", UniqueID, Page.Form.ClientID);
671                         writer.WriteLine ("Sys.WebForms.PageRequestManager.getInstance()._updateControls([{0}], [{1}], [{2}], {3});", FormatUpdatePanelIDs (_updatePanels, true), FormatListIDs (_asyncPostBackControls, true), FormatListIDs (_postBackControls, true), AsyncPostBackTimeout);
672                         writer.WriteLine ("//]]");
673                         writer.WriteLine ("</script>");
674                         base.Render (writer);
675                 }
676
677                 static string FormatUpdatePanelIDs (List<UpdatePanel> list, bool useSingleQuote) {
678                         if (list == null || list.Count == 0)
679                                 return null;
680
681                         StringBuilder sb = new StringBuilder ();
682                         for (int i = 0; i < list.Count; i++) {
683                                 sb.AppendFormat ("{0}{1}{2}{0},", useSingleQuote ? "'" : String.Empty, list [i].ChildrenAsTriggers ? "t" : "f", list [i].UniqueID);
684                         }
685                         if (sb.Length > 0)
686                                 sb.Length--;
687
688                         return sb.ToString ();
689                 }
690
691                 static string FormatListIDs (List<Control> list, bool useSingleQuote)
692                 {
693                         if (list == null || list.Count == 0)
694                                 return null;
695
696                         StringBuilder sb = new StringBuilder ();
697                         for (int i = 0; i < list.Count; i++) {
698                                 sb.AppendFormat ("{0}{1}{0},", useSingleQuote ? "'" : String.Empty, list [i].UniqueID);
699                         }
700                         if (sb.Length > 0)
701                                 sb.Length--;
702
703                         return sb.ToString ();
704                 }
705
706                 public void SetFocus (Control control)
707                 {
708                         throw new NotImplementedException ();
709                 }
710
711                 public void SetFocus (string clientID)
712                 {
713                         throw new NotImplementedException ();
714                 }
715
716                 #region IPostBackDataHandler Members
717
718                 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
719                 {
720                         return LoadPostData (postDataKey, postCollection);
721                 }
722
723                 void IPostBackDataHandler.RaisePostDataChangedEvent ()
724                 {
725                         RaisePostDataChangedEvent ();
726                 }
727
728                 #endregion
729
730                 static internal void WriteCallbackException (TextWriter output, Exception ex) {
731                         HttpException httpEx = ex as HttpException;
732                         WriteCallbackOutput (output, error, httpEx == null ? "500" : httpEx.GetHttpCode ().ToString (), ex.GetBaseException ().Message);
733                 }
734
735                 static internal void WriteCallbackRedirect (TextWriter output, string redirectUrl) {
736                         WriteCallbackOutput (output, pageRedirect, null, redirectUrl);
737                 }
738
739                 static void WriteCallbackOutput (TextWriter output, string type, string name, string value) {
740                         output.Write ("{0}|{1}|{2}|{3}|", value == null ? 0 : value.Length, type, name, value);
741                 }
742
743                 void RenderPageCallback (HtmlTextWriter output, Control container) {
744                         Page page = (Page) container;
745
746                         page.Form.SetRenderMethodDelegate (RenderFormCallback);
747                         HtmlTextParser parser = new HtmlTextParser (output);
748                         page.Form.RenderControl (parser);
749
750                         parser.WriteOutput (output);
751                         WriteCallbackOutput (output, asyncPostBackControlIDs, null, FormatListIDs (_asyncPostBackControls, false));
752                         WriteCallbackOutput (output, postBackControlIDs, null, FormatListIDs (_postBackControls, false));
753                         WriteCallbackOutput (output, updatePanelIDs, null, FormatUpdatePanelIDs (_updatePanels, false));
754                         WriteCallbackOutput (output, asyncPostBackTimeout, null, AsyncPostBackTimeout.ToString ());
755                         WriteCallbackOutput (output, pageTitle, null, Page.Title);
756
757                         WriteArrayDeclarations (output);
758                         WriteScriptBlocks (output, _clientScriptBlocks);
759                         WriteScriptBlocks (output, _startupScriptBlocks);
760                         WriteHiddenFields (output);
761                 }
762
763                 void WriteArrayDeclarations (HtmlTextWriter writer) {
764                         if (_arrayDeclarations != null) {
765                                 for (int i = 0; i < _arrayDeclarations.Count; i++) {
766                                         ArrayDeclaration array = _arrayDeclarations [i];
767                                         WriteCallbackOutput (writer, arrayDeclaration, array.ArrayName, array.ArrayValue);
768                                 }
769                         }
770                 }
771
772                 void WriteScriptBlocks (HtmlTextWriter output, ScriptEntry scriptList) {
773                         while (scriptList != null) {
774                                 switch (scriptList.ScriptEntryType) {
775                                 case ScriptEntryType.ScriptContentNoTags:
776                                         WriteCallbackOutput (output, scriptBlock, scriptContentNoTags, scriptList.Script);
777                                         break;
778                                 case ScriptEntryType.ScriptContentWithTags:
779                                         string script = SerializeScriptBlock (scriptList);
780                                         WriteCallbackOutput (output, scriptBlock, scriptContentWithTags, script);
781                                         break;
782                                 case ScriptEntryType.ScriptPath:
783                                         WriteCallbackOutput (output, scriptBlock, scriptPath, scriptList.Script);
784                                         break;
785                                 }
786                                 scriptList = scriptList.Next;
787                         }
788                 }
789
790                 void WriteHiddenFields (HtmlTextWriter output) {
791                         if (_hiddenFields == null)
792                                 return;
793                         foreach (string key in _hiddenFields.Keys) {
794                                 string value = _hiddenFields [key] as string;
795                                 WriteCallbackOutput (output, hiddenField, key, value);
796                         }
797                 }
798
799                 [MonoTODO()]
800                 static string SerializeScriptBlock (ScriptEntry scriptList) {
801                         throw new InvalidOperationException (String.Format ("The script tag registered for type '{0}' and key '{1}' has invalid characters outside of the script tags: {2}. Only properly formatted script tags can be registered.", scriptList.Type, scriptList.Key, scriptList.Script));
802                 }
803
804                 void RenderFormCallback (HtmlTextWriter output, Control container) {
805                         output = ((HtmlTextParser) output).ResponseOutput;
806                         if (_updatePanels != null && _updatePanels.Count > 0) {
807                                 StringBuilder sb = new StringBuilder ();
808                                 HtmlTextWriter w = new HtmlTextWriter (new StringWriter (sb));
809                                 for (int i = 0; i < _updatePanels.Count; i++) {
810                                         UpdatePanel panel = _updatePanels [i];
811                                         if (panel.Visible) {
812                                                 panel.RenderChildrenInternal (w);
813                                                 w.Flush ();
814                                                 if (panel.RequiresUpdate) {
815                                                         string panelOutput = sb.ToString ();
816                                                         WriteCallbackOutput (output, updatePanel, panel.ClientID, panelOutput);
817                                                 }
818                                                 sb.Length = 0;
819                                         }
820                                 }
821                         }
822                         
823                         HtmlForm form = (HtmlForm) container;
824                         HtmlTextWriter writer = new HtmlTextWriter (new DropWriter ());
825                         if (form.HasControls ()) {
826                                 for (int i = 0; i < form.Controls.Count; i++) {
827                                         form.Controls [i].RenderControl (writer);
828                                 }
829                         }
830                 }
831
832                 sealed class HtmlTextParser : HtmlTextWriter
833                 {
834                         readonly HtmlTextWriter _responseOutput;
835
836                         public HtmlTextWriter ResponseOutput {
837                                 get { return _responseOutput; }
838                         }
839
840                         public HtmlTextParser (HtmlTextWriter responseOutput)
841                                 : base (new TextParser ()) {
842                                 _responseOutput = responseOutput;
843                         }
844
845                         public void WriteOutput (HtmlTextWriter output) {
846                                 ((TextParser) InnerWriter).WriteOutput (output);
847                         }
848                 }
849
850                 sealed class TextParser : TextWriter
851                 {
852                         int _state;
853                         char _charState = (char) 255;
854                         const char nullCharState = (char) 255;
855                         StringBuilder _sb = new StringBuilder ();
856                         List<Hashtable> _hiddenFields;
857                         Hashtable _currentField;
858                         string _currentAttribute;
859
860                         public override Encoding Encoding {
861                                 get { return Encoding.UTF8; }
862                         }
863
864                         public override void Write (char value) {
865                                 switch (_state) {
866                                 case 0:
867                                         ParseBeginTag (value);
868                                         break;
869                                 case 1:
870                                         ParseAttributeName (value);
871                                         break;
872                                 case 2:
873                                         ParseAttributeValue (value);
874                                         break;
875                                 }
876                         }
877
878                         private void ParseAttributeValue (char value) {
879                                 switch (value) {
880                                 case '>':
881                                         ResetState ();
882                                         break;
883                                 case '"':
884                                         _currentField [_currentAttribute] = _sb.ToString ();
885                                         _state = 1;
886                                         _sb.Length = 0;
887                                         break;
888                                 default:
889                                         _sb.Append (value);
890                                         break;
891                                 }
892                         }
893
894                         private void ParseAttributeName (char value) {
895                                 switch (value) {
896                                 case '>':
897                                         ResetState ();
898                                         break;
899                                 case ' ':
900                                 case '=':
901                                         break;
902                                 case '"':
903                                         _currentAttribute = _sb.ToString ();
904                                         _state = 2;
905                                         _sb.Length = 0;
906                                         break;
907                                 default:
908                                         _sb.Append (value);
909                                         break;
910                                 }
911                         }
912
913                         void ParseBeginTag (char value) {
914                                 switch (_charState) {
915                                 case nullCharState:
916                                         if (value == '<')
917                                                 _charState = value;
918                                         break;
919                                 case '<':
920                                         if (value == 'i')
921                                                 _charState = value;
922                                         else
923                                                 ResetState ();
924                                         break;
925                                 case 'i':
926                                         if (value == 'n')
927                                                 _charState = value;
928                                         else
929                                                 ResetState ();
930                                         break;
931                                 case 'n':
932                                         if (value == 'p')
933                                                 _charState = value;
934                                         else
935                                                 ResetState ();
936                                         break;
937                                 case 'p':
938                                         if (value == 'u')
939                                                 _charState = value;
940                                         else
941                                                 ResetState ();
942                                         break;
943                                 case 'u':
944                                         if (value == 't')
945                                                 _charState = value;
946                                         else
947                                                 ResetState ();
948                                         break;
949                                 case 't':
950                                         if (value == ' ') {
951                                                 _state = 1;
952                                                 _currentField = new Hashtable ();
953                                                 if (_hiddenFields == null)
954                                                         _hiddenFields = new List<Hashtable> ();
955                                                 _hiddenFields.Add (_currentField);
956                                         }
957                                         else
958                                                 ResetState ();
959                                         break;
960                                 }
961                         }
962
963                         private void ResetState () {
964                                 _charState = nullCharState;
965                                 _state = 0;
966                                 _sb.Length = 0;
967                         }
968
969                         public void WriteOutput (HtmlTextWriter output) {
970                                 if (_hiddenFields == null)
971                                         return;
972                                 
973                                 for (int i = 0; i < _hiddenFields.Count; i++) {
974                                         Hashtable field = _hiddenFields [i];
975                                         
976                                         string value = (string) field ["value"];
977                                         if (String.IsNullOrEmpty (value))
978                                                 continue;
979
980                                         ScriptManager.WriteCallbackOutput (output, ScriptManager.hiddenField, (string) field ["name"], value);
981                                 }
982                         }
983                 }
984
985                 sealed class DropWriter : TextWriter
986                 {
987                         public override Encoding Encoding {
988                                 get { return Encoding.UTF8; }
989                         }
990                 }
991
992                 sealed class ScriptEntry
993                 {
994                         readonly public Type Type;
995                         readonly public string Key;
996                         readonly public string Script;
997                         readonly public ScriptEntryType ScriptEntryType;
998                         public ScriptEntry Next;
999
1000                         public ScriptEntry (Type type, string key, string script, ScriptEntryType scriptEntryType) {
1001                                 Key = key;
1002                                 Type = type;
1003                                 Script = script;
1004                                 ScriptEntryType = scriptEntryType;
1005                         }
1006                 }
1007
1008                 enum ScriptEntryType
1009                 {
1010                         ScriptContentNoTags,
1011                         ScriptContentWithTags,
1012                         ScriptPath
1013                 }
1014
1015                 sealed class ArrayDeclaration
1016                 {
1017                         readonly public string ArrayName;
1018                         readonly public string ArrayValue;
1019
1020                         public ArrayDeclaration (string arrayName, string arrayValue) {
1021                                 ArrayName = arrayName;
1022                                 ArrayValue = arrayValue;
1023                         }
1024                 }
1025         }
1026 }