Initial AsyncPostBackTrigger implementation
[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
44 namespace System.Web.UI
45 {
46         [ParseChildrenAttribute (true)]
47         [DefaultPropertyAttribute ("Scripts")]
48         [DesignerAttribute ("System.Web.UI.Design.ScriptManagerDesigner, System.Web.Extensions.Design, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
49         [NonVisualControlAttribute]
50         [PersistChildrenAttribute (false)]
51         [AspNetHostingPermissionAttribute (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
52         [AspNetHostingPermissionAttribute (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
53         public class ScriptManager : Control, IPostBackDataHandler
54         {
55                 // the keywords are used in fomatting async response
56                 const string updatePanel = "updatePanel";
57                 const string hiddenField = "hiddenField";
58                 const string arrayDeclaration = "arrayDeclaration";
59                 const string scriptBlock = "scriptBlock";
60                 const string expando = "expando";
61                 const string onSubmit = "onSubmit";
62                 const string asyncPostBackControlIDs = "asyncPostBackControlIDs";
63                 const string postBackControlIDs = "postBackControlIDs";
64                 const string updatePanelIDs = "updatePanelIDs";
65                 const string asyncPostBackTimeout = "asyncPostBackTimeout";
66                 const string childUpdatePanelIDs = "childUpdatePanelIDs";
67                 const string panelsToRefreshIDs = "panelsToRefreshIDs";
68                 const string formAction = "formAction";
69                 const string dataItem = "dataItem";
70                 const string dataItemJson = "dataItemJson";
71                 const string scriptDispose = "scriptDispose";
72                 const string pageRedirect = "pageRedirect";
73                 const string error = "error";
74                 const string pageTitle = "pageTitle";
75                 const string focus = "focus";
76
77                 int _asyncPostBackTimeout = 90;
78                 List<Control> _asyncPostBackControls;
79                 List<Control> _postBackControls;
80                 List<UpdatePanel> _updatePanels;
81                 ScriptReferenceCollection _scripts;
82                 bool _isInAsyncPostBack;
83                 string _asyncPostBackSourceElementID;
84                 ScriptMode _scriptMode = ScriptMode.Auto;
85                 
86                 [DefaultValue (true)]
87                 [Category ("Behavior")]
88                 public bool AllowCustomErrorsRedirect {
89                         get {
90                                 throw new NotImplementedException ();
91                         }
92                         set {
93                                 throw new NotImplementedException ();
94                         }
95                 }
96
97                 [Category ("Behavior")]
98                 [DefaultValue ("")]
99                 public string AsyncPostBackErrorMessage {
100                         get {
101                                 throw new NotImplementedException ();
102                         }
103                         set {
104                                 throw new NotImplementedException ();
105                         }
106                 }
107
108                 [Browsable (false)]
109                 public string AsyncPostBackSourceElementID {
110                         get {
111                                 if(_asyncPostBackSourceElementID==null)
112                                         return String.Empty;
113                                 return _asyncPostBackSourceElementID;
114                         }
115                 }
116
117                 [DefaultValue (90)]
118                 [Category ("Behavior")]
119                 public int AsyncPostBackTimeout {
120                         get {
121                                 return _asyncPostBackTimeout;
122                         }
123                         set {
124                                 _asyncPostBackTimeout = value;
125                         }
126                 }
127
128                 [Category ("Behavior")]
129                 [MergableProperty (false)]
130                 [DefaultValue ("")]
131                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
132                 [PersistenceMode (PersistenceMode.InnerProperty)]
133                 public AuthenticationServiceManager AuthenticationService {
134                         get {
135                                 throw new NotImplementedException ();
136                         }
137                 }
138
139                 [Category ("Behavior")]
140                 [DefaultValue (false)]
141                 public bool EnablePageMethods {
142                         get {
143                                 throw new NotImplementedException ();
144                         }
145                         set {
146                                 throw new NotImplementedException ();
147                         }
148                 }
149
150                 [DefaultValue (true)]
151                 [Category ("Behavior")]
152                 public bool EnablePartialRendering {
153                         get {
154                                 throw new NotImplementedException ();
155                         }
156                         set {
157                                 throw new NotImplementedException ();
158                         }
159                 }
160
161                 [DefaultValue (false)]
162                 [Category ("Behavior")]
163                 public bool EnableScriptGlobalization {
164                         get {
165                                 throw new NotImplementedException ();
166                         }
167                         set {
168                                 throw new NotImplementedException ();
169                         }
170                 }
171
172                 [Category ("Behavior")]
173                 [DefaultValue (false)]
174                 public bool EnableScriptLocalization {
175                         get {
176                                 throw new NotImplementedException ();
177                         }
178                         set {
179                                 throw new NotImplementedException ();
180                         }
181                 }
182
183                 [Browsable (false)]
184                 public bool IsDebuggingEnabled {
185                         get {
186                                 DeploymentSection deployment = (DeploymentSection) WebConfigurationManager.GetSection ("system.web/deployment");
187                                 if (deployment.Retail)
188                                         return false;
189
190                                 CompilationSection compilation = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation");
191                                 if (!compilation.Debug && (ScriptMode == ScriptMode.Auto || ScriptMode == ScriptMode.Inherit))
192                                         return false;
193
194                                 if (ScriptMode == ScriptMode.Release)
195                                         return false;
196
197                                 return true;
198                         }
199                 }
200
201                 [Browsable (false)]
202                 public bool IsInAsyncPostBack {
203                         get {
204                                 return _isInAsyncPostBack;
205                         }
206                 }
207
208                 [Category ("Behavior")]
209                 [DefaultValue (true)]
210                 public bool LoadScriptsBeforeUI {
211                         get {
212                                 throw new NotImplementedException ();
213                         }
214                         set {
215                                 throw new NotImplementedException ();
216                         }
217                 }
218
219                 [PersistenceMode (PersistenceMode.InnerProperty)]
220                 [DefaultValue ("")]
221                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
222                 [Category ("Behavior")]
223                 [MergableProperty (false)]
224                 public ProfileServiceManager ProfileService {
225                         get {
226                                 throw new NotImplementedException ();
227                         }
228                 }
229
230                 [Category ("Behavior")]
231                 public ScriptMode ScriptMode {
232                         get {
233                                 return _scriptMode;
234                         }
235                         set {
236                                 if (value == ScriptMode.Inherit)
237                                         value = ScriptMode.Auto;
238                                 _scriptMode = value;
239                         }
240                 }
241
242                 [DefaultValue ("")]
243                 [Category ("Behavior")]
244                 public string ScriptPath {
245                         get {
246                                 throw new NotImplementedException ();
247                         }
248                         set {
249                                 throw new NotImplementedException ();
250                         }
251                 }
252
253                 [PersistenceMode (PersistenceMode.InnerProperty)]
254                 [DefaultValue ("")]
255                 [Category ("Behavior")]
256                 [MergableProperty (false)]
257                 public ScriptReferenceCollection Scripts {
258                         get {
259                                 if (_scripts == null)
260                                         _scripts = new ScriptReferenceCollection ();
261
262                                 return _scripts;
263                         }
264                 }
265
266                 [PersistenceMode (PersistenceMode.InnerProperty)]
267                 [DefaultValue ("")]
268                 [MergableProperty (false)]
269                 [Category ("Behavior")]
270                 public ServiceReferenceCollection Services {
271                         get {
272                                 throw new NotImplementedException ();
273                         }
274                 }
275
276                 [DefaultValue (true)]
277                 [Browsable (false)]
278                 public bool SupportsPartialRendering {
279                         get {
280                                 throw new NotImplementedException ();
281                         }
282                         set {
283                                 throw new NotImplementedException ();
284                         }
285                 }
286
287                 [EditorBrowsable (EditorBrowsableState.Never)]
288                 [Browsable (false)]
289                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
290                 public override bool Visible {
291                         get {
292                                 return true;
293                         }
294                         set {
295                                 throw new NotImplementedException ();
296                         }
297                 }
298
299                 [Category ("Action")]
300                 public event EventHandler<AsyncPostBackErrorEventArgs> AsyncPostBackError;
301
302                 [Category ("Action")]
303                 public event EventHandler<ScriptReferenceEventArgs> ResolveScriptReference;
304
305                 public static ScriptManager GetCurrent (Page page)
306                 {
307                         HttpContext ctx = HttpContext.Current;
308                         if (ctx == null)
309                                 return null;
310
311                         return (ScriptManager) ctx.Items [page];
312                 }
313                 
314                 static void SetCurrent (Page page, ScriptManager instance) {
315                         HttpContext ctx = HttpContext.Current;
316                         ctx.Items [page] = instance;
317                 }
318
319                 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection)
320                 {
321                         _isInAsyncPostBack = true;
322                         string arg = postCollection [postDataKey];
323                         if (!String.IsNullOrEmpty (arg)) {
324                                 string [] args = arg.Split ('|');
325                                 Control c = Page.FindControl (args [0]);
326                                 UpdatePanel up = c as UpdatePanel;
327                                 if (up != null && up.ChildrenAsTriggers)
328                                         up.Update ();
329                                 _asyncPostBackSourceElementID = args[1];
330                         }
331                         return false;
332                 }
333
334                 protected internal virtual void OnAsyncPostBackError (AsyncPostBackErrorEventArgs e)
335                 {
336                         if (AsyncPostBackError != null)
337                                 AsyncPostBackError (this, e);
338                 }
339
340                 protected override void OnInit (EventArgs e)
341                 {
342                         base.OnInit (e);
343
344                         if (GetCurrent (Page) != null)
345                                 throw new InvalidOperationException ("Only one instance of a ScriptManager can be added to the page.");
346
347                         SetCurrent (Page, this);
348                 }
349
350                 protected override void OnPreRender (EventArgs e)
351                 {
352                         base.OnPreRender (e);
353                         
354                         if (IsInAsyncPostBack) {
355                                 Page.SetRenderMethodDelegate (RenderPageCallback);
356                         }
357                         
358                         // Register Scripts
359                         foreach (ScriptReference script in GetScriptReferences ()) {
360                                 OnResolveScriptReference (new ScriptReferenceEventArgs (script));
361                                 RegisterScriptReference (script);
362                         }
363
364                         // Register startup script
365                         RegisterStartupScript (this, typeof (ScriptManager), "Sys.Application.initialize();", "Sys.Application.initialize();", true);
366                 }
367
368                 IEnumerable GetScriptReferences () {
369                         ScriptReference script;
370
371                         script = new ScriptReference ("MicrosoftAjax.js", String.Empty);
372                         script.NotifyScriptLoaded = false;
373                         yield return script;
374
375                         script = new ScriptReference ("MicrosoftAjaxWebForms.js", String.Empty);
376                         script.NotifyScriptLoaded = false;
377                         yield return script;
378
379                         if (_scripts != null && _scripts.Count > 0) {
380                                 for (int i = 0; i < _scripts.Count; i++) {
381                                         yield return _scripts [i];
382                                 }
383                         }
384                 }
385
386                 protected virtual void OnResolveScriptReference (ScriptReferenceEventArgs e)
387                 {
388                         if (ResolveScriptReference != null)
389                                 ResolveScriptReference (this, e);
390                 }
391
392                 protected virtual void RaisePostDataChangedEvent ()
393                 {
394                         throw new NotImplementedException ();
395                 }
396
397                 public static void RegisterArrayDeclaration (Control control, string arrayName, string arrayValue)
398                 {
399                         throw new NotImplementedException ();
400                 }
401
402                 public static void RegisterArrayDeclaration (Page page, string arrayName, string arrayValue)
403                 {
404                         throw new NotImplementedException ();
405                 }
406
407                 public void RegisterAsyncPostBackControl (Control control)
408                 {
409                         if(control==null)
410                                 return;
411
412                         if (_asyncPostBackControls == null)
413                                 _asyncPostBackControls = new List<Control> ();
414
415                         if (_asyncPostBackControls.Contains (control))
416                                 return;
417
418                         _asyncPostBackControls.Add (control);
419                 }
420
421                 public static void RegisterClientScriptBlock (Control control, Type type, string key, string script, bool addScriptTags)
422                 {
423                         throw new NotImplementedException ();
424                 }
425
426                 public static void RegisterClientScriptBlock (Page page, Type type, string key, string script, bool addScriptTags)
427                 {
428                         throw new NotImplementedException ();
429                 }
430
431                 public static void RegisterClientScriptInclude (Control control, Type type, string key, string url)
432                 {
433                         RegisterClientScriptInclude (control.Page, type, key, url);
434                 }
435
436                 public static void RegisterClientScriptInclude (Page page, Type type, string key, string url)
437                 {
438                         page.ClientScript.RegisterClientScriptInclude (type, key, url);
439                 }
440
441                 public static void RegisterClientScriptResource (Control control, Type type, string resourceName)
442                 {
443                         RegisterClientScriptResource (control.Page, type, resourceName);
444                 }
445
446                 public static void RegisterClientScriptResource (Page page, Type type, string resourceName)
447                 {
448                         page.ClientScript.RegisterClientScriptResource (type, resourceName);
449                 }
450
451                 void RegisterScriptReference (ScriptReference script) {
452
453                         // TODO: consider 'retail' attribute of the 'deployment' configuration element in Web.config, 
454                         // IsDebuggingEnabled and ScriptMode properties to determine whether to render debug scripts.
455
456                         string url;
457                         if (!String.IsNullOrEmpty (script.Path)) {
458                                 url = script.Path;
459                         }
460                         else if (!String.IsNullOrEmpty (script.Name)) {
461                                 Assembly assembly;
462                                 if (String.IsNullOrEmpty (script.Assembly))
463                                         assembly = typeof (ScriptManager).Assembly;
464                                 else
465                                         assembly = Assembly.Load (script.Assembly);
466                                 url = ScriptResourceHandler.GetResourceUrl (assembly, script.Name, script.NotifyScriptLoaded);
467                         }
468                         else {
469                                 throw new InvalidOperationException ("Name and Path cannot both be empty.");
470                         }
471
472                         RegisterClientScriptInclude (this, typeof (ScriptManager), url, url);
473                 }
474
475                 public void RegisterDataItem (Control control, string dataItem)
476                 {
477                         throw new NotImplementedException ();
478                 }
479
480                 public void RegisterDataItem (Control control, string dataItem, bool isJsonSerialized)
481                 {
482                         throw new NotImplementedException ();
483                 }
484
485                 public void RegisterDispose (Control control, string disposeScript)
486                 {
487                         throw new NotImplementedException ();
488                 }
489
490                 public static void RegisterExpandoAttribute (Control control, string controlId, string attributeName, string attributeValue, bool encode)
491                 {
492                         throw new NotImplementedException ();
493                 }
494
495                 public static void RegisterHiddenField (Control control, string hiddenFieldName, string hiddenFieldInitialValue)
496                 {
497                         throw new NotImplementedException ();
498                 }
499
500                 public static void RegisterHiddenField (Page page, string hiddenFieldName, string hiddenFieldInitialValue)
501                 {
502                         throw new NotImplementedException ();
503                 }
504
505                 public static void RegisterOnSubmitStatement (Control control, Type type, string key, string script)
506                 {
507                         throw new NotImplementedException ();
508                 }
509
510                 public static void RegisterOnSubmitStatement (Page page, Type type, string key, string script)
511                 {
512                         throw new NotImplementedException ();
513                 }
514
515                 public void RegisterPostBackControl (Control control)
516                 {
517                         if (control == null)
518                                 return;
519
520                         if (_postBackControls == null)
521                                 _postBackControls = new List<Control> ();
522
523                         if (_postBackControls.Contains (control))
524                                 return;
525
526                         _postBackControls.Add (control);
527                 }
528
529                 internal void RegisterUpdatePanel (UpdatePanel updatePanel) {
530                         if (_updatePanels == null)
531                                 _updatePanels = new List<UpdatePanel> ();
532
533                         if (_updatePanels.Contains (updatePanel))
534                                 return;
535
536                         _updatePanels.Add (updatePanel);
537                 }
538
539                 public void RegisterScriptDescriptors (IExtenderControl extenderControl)
540                 {
541                         throw new NotImplementedException ();
542                 }
543
544                 public void RegisterScriptDescriptors (IScriptControl scriptControl)
545                 {
546                         throw new NotImplementedException ();
547                 }
548
549                 public static void RegisterStartupScript (Control control, Type type, string key, string script, bool addScriptTags)
550                 {
551                         RegisterStartupScript (control.Page, type, key, script, addScriptTags);
552                 }
553
554                 public static void RegisterStartupScript (Page page, Type type, string key, string script, bool addScriptTags)
555                 {
556                         page.ClientScript.RegisterStartupScript (type, key, script, addScriptTags);
557                 }
558
559                 protected override void Render (HtmlTextWriter writer)
560                 {
561                         // MSDN: This method is used by control developers to extend the ScriptManager control. 
562                         // Notes to Inheritors: 
563                         // When overriding this method, call the base Render(HtmlTextWriter) method 
564                         // so that PageRequestManager is rendered on the page.
565                         writer.WriteLine ("<script type=\"text/javascript\">");
566                         writer.WriteLine ("//<![CDATA[");
567                         writer.WriteLine ("Sys.WebForms.PageRequestManager._initialize('{0}', document.getElementById('{1}'));", UniqueID, Page.Form.ClientID);
568                         writer.WriteLine ("Sys.WebForms.PageRequestManager.getInstance()._updateControls([{0}], [{1}], [{2}], {3});", FormatUpdatePanelIDs (_updatePanels, true), FormatListIDs (_asyncPostBackControls, true), FormatListIDs (_postBackControls, true), AsyncPostBackTimeout);
569                         writer.WriteLine ("//]]");
570                         writer.WriteLine ("</script>");
571                         base.Render (writer);
572                 }
573
574                 static string FormatUpdatePanelIDs (List<UpdatePanel> list, bool useSingleQuote) {
575                         if (list == null || list.Count == 0)
576                                 return null;
577
578                         StringBuilder sb = new StringBuilder ();
579                         for (int i = 0; i < list.Count; i++) {
580                                 sb.AppendFormat ("{0}{1}{2}{0},", useSingleQuote ? "'" : String.Empty, list [i].ChildrenAsTriggers ? "t" : "f", list [i].UniqueID);
581                         }
582                         if (sb.Length > 0)
583                                 sb.Length--;
584
585                         return sb.ToString ();
586                 }
587
588                 static string FormatListIDs (List<Control> list, bool useSingleQuote)
589                 {
590                         if (list == null || list.Count == 0)
591                                 return null;
592
593                         StringBuilder sb = new StringBuilder ();
594                         for (int i = 0; i < list.Count; i++) {
595                                 sb.AppendFormat ("{0}{1}{0},", useSingleQuote ? "'" : String.Empty, list [i].UniqueID);
596                         }
597                         if (sb.Length > 0)
598                                 sb.Length--;
599
600                         return sb.ToString ();
601                 }
602
603                 public void SetFocus (Control control)
604                 {
605                         throw new NotImplementedException ();
606                 }
607
608                 public void SetFocus (string clientID)
609                 {
610                         throw new NotImplementedException ();
611                 }
612
613                 #region IPostBackDataHandler Members
614
615                 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
616                 {
617                         return LoadPostData (postDataKey, postCollection);
618                 }
619
620                 void IPostBackDataHandler.RaisePostDataChangedEvent ()
621                 {
622                         RaisePostDataChangedEvent ();
623                 }
624
625                 #endregion
626
627                 static internal void WriteCallbackRedirect (TextWriter output, string redirectUrl) {
628                         WriteCallbackOutput (output, pageRedirect, null, redirectUrl);
629                 }
630
631                 static void WriteCallbackOutput (TextWriter output, string type, string name, string value) {
632                         output.Write ("{0}|{1}|{2}|{3}|", value == null ? 0 : value.Length, type, name, value);
633                 }
634
635                 void RenderPageCallback (HtmlTextWriter output, Control container) {
636                         Page page = (Page) container;
637
638                         page.Form.SetRenderMethodDelegate (RenderFormCallback);
639                         HtmlTextParser parser = new HtmlTextParser (output);
640                         page.Form.RenderControl (parser);
641
642                         parser.WriteOutput (output);
643                         WriteCallbackOutput (output, asyncPostBackControlIDs, null, FormatListIDs (_asyncPostBackControls, false));
644                         WriteCallbackOutput (output, postBackControlIDs, null, FormatListIDs (_postBackControls, false));
645                         WriteCallbackOutput (output, updatePanelIDs, null, FormatUpdatePanelIDs (_updatePanels, false));
646                         WriteCallbackOutput (output, asyncPostBackTimeout, null, AsyncPostBackTimeout.ToString());
647                         WriteCallbackOutput (output, pageTitle, null, Page.Title);  
648                 }
649
650                 void RenderFormCallback (HtmlTextWriter output, Control container) {
651                         output = ((HtmlTextParser) output).ResponseOutput;
652                         if (_updatePanels != null && _updatePanels.Count > 0) {
653                                 StringBuilder sb = new StringBuilder ();
654                                 HtmlTextWriter w = new HtmlTextWriter (new StringWriter (sb));
655                                 for (int i = 0; i < _updatePanels.Count; i++) {
656                                         UpdatePanel panel = _updatePanels [i];
657                                         if (panel.Visible) {
658                                                 panel.RenderChildrenInternal (w);
659                                                 w.Flush ();
660                                                 if (panel.RequiresUpdate) {
661                                                         string panelOutput = sb.ToString ();
662                                                         WriteCallbackOutput (output, updatePanel, panel.ClientID, panelOutput);
663                                                 }
664                                                 sb.Length = 0;
665                                         }
666                                 }
667                         }
668                         
669                         HtmlForm form = (HtmlForm) container;
670                         HtmlTextWriter writer = new HtmlTextWriter (new DropWriter ());
671                         if (form.HasControls ()) {
672                                 for (int i = 0; i < form.Controls.Count; i++) {
673                                         form.Controls [i].RenderControl (writer);
674                                 }
675                         }
676                 }
677
678                 sealed class HtmlTextParser : HtmlTextWriter
679                 {
680                         readonly HtmlTextWriter _responseOutput;
681
682                         public HtmlTextWriter ResponseOutput {
683                                 get { return _responseOutput; }
684                         }
685
686                         public HtmlTextParser (HtmlTextWriter responseOutput)
687                                 : base (new TextParser ()) {
688                                 _responseOutput = responseOutput;
689                         }
690
691                         public void WriteOutput (HtmlTextWriter output) {
692                                 ((TextParser) InnerWriter).WriteOutput (output);
693                         }
694                 }
695
696                 sealed class TextParser : TextWriter
697                 {
698                         int _state;
699                         char _charState = (char) 255;
700                         const char nullCharState = (char) 255;
701                         StringBuilder _sb = new StringBuilder ();
702                         List<Hashtable> _hiddenFields;
703                         Hashtable _currentField;
704                         string _currentAttribute;
705
706                         public override Encoding Encoding {
707                                 get { return Encoding.UTF8; }
708                         }
709
710                         public override void Write (char value) {
711                                 switch (_state) {
712                                 case 0:
713                                         ParseBeginTag (value);
714                                         break;
715                                 case 1:
716                                         ParseAttributeName (value);
717                                         break;
718                                 case 2:
719                                         ParseAttributeValue (value);
720                                         break;
721                                 }
722                         }
723
724                         private void ParseAttributeValue (char value) {
725                                 switch (value) {
726                                 case '>':
727                                         ResetState ();
728                                         break;
729                                 case '"':
730                                         _currentField [_currentAttribute] = _sb.ToString ();
731                                         _state = 1;
732                                         _sb.Length = 0;
733                                         break;
734                                 default:
735                                         _sb.Append (value);
736                                         break;
737                                 }
738                         }
739
740                         private void ParseAttributeName (char value) {
741                                 switch (value) {
742                                 case '>':
743                                         ResetState ();
744                                         break;
745                                 case ' ':
746                                 case '=':
747                                         break;
748                                 case '"':
749                                         _currentAttribute = _sb.ToString ();
750                                         _state = 2;
751                                         _sb.Length = 0;
752                                         break;
753                                 default:
754                                         _sb.Append (value);
755                                         break;
756                                 }
757                         }
758
759                         void ParseBeginTag (char value) {
760                                 switch (_charState) {
761                                 case nullCharState:
762                                         if (value == '<')
763                                                 _charState = value;
764                                         break;
765                                 case '<':
766                                         if (value == 'i')
767                                                 _charState = value;
768                                         else
769                                                 ResetState ();
770                                         break;
771                                 case 'i':
772                                         if (value == 'n')
773                                                 _charState = value;
774                                         else
775                                                 ResetState ();
776                                         break;
777                                 case 'n':
778                                         if (value == 'p')
779                                                 _charState = value;
780                                         else
781                                                 ResetState ();
782                                         break;
783                                 case 'p':
784                                         if (value == 'u')
785                                                 _charState = value;
786                                         else
787                                                 ResetState ();
788                                         break;
789                                 case 'u':
790                                         if (value == 't')
791                                                 _charState = value;
792                                         else
793                                                 ResetState ();
794                                         break;
795                                 case 't':
796                                         if (value == ' ') {
797                                                 _state = 1;
798                                                 _currentField = new Hashtable ();
799                                                 if (_hiddenFields == null)
800                                                         _hiddenFields = new List<Hashtable> ();
801                                                 _hiddenFields.Add (_currentField);
802                                         }
803                                         else
804                                                 ResetState ();
805                                         break;
806                                 }
807                         }
808
809                         private void ResetState () {
810                                 _charState = nullCharState;
811                                 _state = 0;
812                                 _sb.Length = 0;
813                         }
814
815                         public void WriteOutput (HtmlTextWriter output) {
816                                 if (_hiddenFields == null)
817                                         return;
818                                 
819                                 for (int i = 0; i < _hiddenFields.Count; i++) {
820                                         Hashtable field = _hiddenFields [i];
821                                         
822                                         string value = (string) field ["value"];
823                                         if (String.IsNullOrEmpty (value))
824                                                 continue;
825
826                                         ScriptManager.WriteCallbackOutput (output, ScriptManager.hiddenField, (string) field ["name"], value);
827                                 }
828                         }
829                 }
830
831                 sealed class DropWriter : TextWriter
832                 {
833                         public override Encoding Encoding {
834                                 get { return Encoding.UTF8; }
835                         }
836                 }
837         }
838 }