Merge branch 'master' of github.com:mono/mono
[mono.git] / mcs / class / System.Web.Extensions / System.Web.UI / ScriptManager.cs
index c9fd992453aa758dee10d997b509e2968f4c825b..4c39f6c4e88347fb0a57e34cf12adb72eeee56fd 100644 (file)
@@ -244,7 +244,7 @@ namespace System.Web.UI
                        }
                }
 
-               bool IsDeploymentRetail {
+               internal bool IsDeploymentRetail {
                        get {
 #if TARGET_J2EE
                                return false;
@@ -395,21 +395,52 @@ namespace System.Web.UI
                public static ScriptManager GetCurrent (Page page) {
                        if (page == null)
                                throw new ArgumentNullException ("page");
-                       return (ScriptManager) page.Items [ScriptManagerKey];
+                       return GetCurrentInternal (page);
                }
 
+               static ScriptManager GetCurrentInternal (Page page)
+               {
+                       if (page == null)
+                               return null;
+
+                       return (ScriptManager) page.Items [ScriptManagerKey];
+               }
+               
                static void SetCurrent (Page page, ScriptManager instance) {
                        page.Items [ScriptManagerKey] = instance;
                        page.ClientScript.RegisterWebFormClientScript ();
                }
 
+               UpdatePanel FindPanelWithId (string id)
+               {
+                       if (_updatePanels == null)
+                               return null;
+                       foreach (UpdatePanel panel in _updatePanels) {
+                               if (panel.ID == id)
+                                       return panel;
+                       }
+                       return null;
+               }
+               
                protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection) {
                        _isInAsyncPostBack = true;
                        string arg = postCollection [postDataKey];
                        if (!String.IsNullOrEmpty (arg)) {
                                string [] args = arg.Split ('|');
-                               _panelToRefreshID = args [0];
-                               _asyncPostBackSourceElementID = args [1];
+                               switch (args.Length) {
+                                       case 1:
+                                               _asyncPostBackSourceElementID = args [0];
+                                               break;
+
+                                       case 2:
+                                               _panelToRefreshID = args [0];
+                                               _asyncPostBackSourceElementID = args [1];
+                                               break;
+
+                                       default: // "impossible situation"
+                                               throw new InvalidOperationException ("Unexpected format of post data.");
+                               }
+                               
                                return true;
                        }
                        return false;
@@ -423,7 +454,7 @@ namespace System.Web.UI
                protected override void OnInit (EventArgs e) {
                        base.OnInit (e);
 
-                       if (GetCurrent (Page) != null)
+                       if (GetCurrentInternal (Page) != null)
                                throw new InvalidOperationException ("Only one instance of a ScriptManager can be added to the page.");
 
                        SetCurrent (Page, this);
@@ -514,7 +545,7 @@ namespace System.Web.UI
                                }
 
                                StringBuilder sb = new StringBuilder ();
-                               sb.AppendLine ("if (typeof(Sys) === 'undefined') throw new Error('ASP.NET Ajax client-side framework failed to load.');");
+                               sb.AppendLine ("if (typeof(Sys) === 'undefined') throw new Error('ASP.NET Ajax client-side framework failed to load.');");
 
                                ScriptingProfileServiceSection profileService = (ScriptingProfileServiceSection) WebConfigurationManager.GetSection ("system.web.extensions/scripting/webServices/profileService");
                                if (profileService != null && profileService.Enabled)
@@ -540,7 +571,7 @@ namespace System.Web.UI
                                if (IsMultiForm)
                                        RegisterScriptReference (this, ajaxWebFormsExtensionScript, true);
                        }
-
+                       
                        // Register Scripts
                        if (_scriptToRegister != null)
                                for (int i = 0; i < _scriptToRegister.Count; i++)
@@ -661,11 +692,21 @@ namespace System.Web.UI
                }
 #endif
 
-               static bool HasBeenRendered (Control control) {
+               bool PanelRequiresUpdate (UpdatePanel panel)
+               {
+                       if (panel == null || _panelsToRefresh == null || _panelsToRefresh.Count == 0)
+                               return false;
+
+                       return _panelsToRefresh.Contains (panel);
+               }
+               
+               bool HasBeenRendered (Control control)
+               {
                        if (control == null)
                                return false;
 
-                       if (control is UpdatePanel && ((UpdatePanel) control).RequiresUpdate)
+                       UpdatePanel panel = control as UpdatePanel;
+                       if (PanelRequiresUpdate (panel))
                                return true;
 
                        return HasBeenRendered (control.Parent);
@@ -710,10 +751,9 @@ namespace System.Web.UI
                                ResolveScriptReference (this, e);
                }
 
-               protected virtual void RaisePostDataChangedEvent () {
-                       UpdatePanel up = Page.FindControl (_panelToRefreshID) as UpdatePanel;
-                       if (up != null && up.ChildrenAsTriggers)
-                               up.Update ();
+               protected virtual void RaisePostDataChangedEvent ()
+               {
+                       // Why override?
                }
 
                public static void RegisterArrayDeclaration (Page page, string arrayName, string arrayValue) {
@@ -722,8 +762,11 @@ namespace System.Web.UI
 
                public static void RegisterArrayDeclaration (Control control, string arrayName, string arrayValue) {
                        Page page = control.Page;
-                       ScriptManager sm = GetCurrent (page);
+                       ScriptManager sm = GetCurrentInternal (page);
 
+                       if (sm == null)
+                               return;
+                       
                        if (sm._arrayDeclarations == null)
                                sm._arrayDeclarations = new List<RegisteredArrayDeclaration> ();
 
@@ -752,8 +795,11 @@ namespace System.Web.UI
 
                public static void RegisterClientScriptBlock (Control control, Type type, string key, string script, bool addScriptTags) {
                        Page page = control.Page;
-                       ScriptManager sm = GetCurrent (page);
+                       ScriptManager sm = GetCurrentInternal (page);
 
+                       if (sm == null)
+                               return;
+                       
                        RegisterScript (ref sm._clientScriptBlocks, control, type, key, script, null, addScriptTags, RegisteredScriptType.ClientScriptBlock);
 
                        if (!sm.IsInAsyncPostBack)
@@ -766,8 +812,11 @@ namespace System.Web.UI
 
                public static void RegisterClientScriptInclude (Control control, Type type, string key, string url) {
                        Page page = control.Page;
-                       ScriptManager sm = GetCurrent (page);
+                       ScriptManager sm = GetCurrentInternal (page);
 
+                       if (sm == null)
+                               return;
+                       
                        RegisterScript (ref sm._clientScriptBlocks, control, type, key, null, url, false, RegisteredScriptType.ClientScriptInclude);
 
                        if (!sm.IsInAsyncPostBack)
@@ -782,60 +831,31 @@ namespace System.Web.UI
                        RegisterClientScriptInclude (control, type, resourceName, ScriptResourceHandler.GetResourceUrl (type.Assembly, resourceName, true));
                }
 
-               void RegisterScriptReference (Control control, ScriptReference script, bool loadScriptsBeforeUI) {
-
-                       bool isDebugMode = IsDeploymentRetail ? false : (script.ScriptModeInternal == ScriptMode.Inherit ? IsDebuggingEnabled : (script.ScriptModeInternal == ScriptMode.Debug));
-                       string url;
-                       if (!String.IsNullOrEmpty (script.Path)) {
-                               url = GetScriptName (control.ResolveClientUrl (script.Path), isDebugMode, EnableScriptLocalization ? script.ResourceUICultures : null);
-                       }
-                       else if (!String.IsNullOrEmpty (script.Name)) {
-                               Assembly assembly;
-                               if (String.IsNullOrEmpty (script.Assembly))
-                                       assembly = typeof (ScriptManager).Assembly;
-                               else
-                                       assembly = Assembly.Load (script.Assembly);
-                               string name = GetScriptName (script.Name, isDebugMode, null);
-                               if (script.IgnoreScriptPath || String.IsNullOrEmpty (ScriptPath))
-                                       url = ScriptResourceHandler.GetResourceUrl (assembly, name, script.NotifyScriptLoaded);
-                               else {
-                                       AssemblyName an = assembly.GetName ();
-                                       url = ResolveClientUrl (String.Concat (VirtualPathUtility.AppendTrailingSlash (ScriptPath), an.Name, '/', an.Version, '/', name));
-                               }
-                       }
-                       else {
-                               throw new InvalidOperationException ("Name and Path cannot both be empty.");
-                       }
-
+               void RegisterScriptReference (Control control, ScriptReference script, bool loadScriptsBeforeUI)
+               {
+                       string scriptPath = script.Path;
+                       string url = script.GetUrl (this, false);
+                       if (control != this && !String.IsNullOrEmpty (scriptPath))
+                               url = control.ResolveClientUrl (url);
+                       
                        if (loadScriptsBeforeUI)
                                RegisterClientScriptInclude (control, typeof (ScriptManager), url, url);
                        else
                                RegisterStartupScript (control, typeof (ScriptManager), url, String.Format ("<script src=\"{0}\" type=\"text/javascript\"></script>", url), false);
                }
 
-               static string GetScriptName (string releaseName, bool isDebugMode, string [] supportedUICultures) {
-                       if (!isDebugMode && (supportedUICultures == null || supportedUICultures.Length == 0))
-                               return releaseName;
-
-                       if (releaseName.Length < 3 || !releaseName.EndsWith (".js", StringComparison.OrdinalIgnoreCase))
-                               throw new InvalidOperationException (String.Format ("'{0}' is not a valid script path.  The path must end in '.js'.", releaseName));
-
-                       StringBuilder sb = new StringBuilder (releaseName);
-                       sb.Length -= 3;
-                       if (isDebugMode)
-                               sb.Append (".debug");
-                       string culture = Thread.CurrentThread.CurrentUICulture.Name;
-                       if (supportedUICultures != null && Array.IndexOf<string> (supportedUICultures, culture) >= 0)
-                               sb.AppendFormat (".{0}", culture);
-                       sb.Append (".js");
-
-                       return sb.ToString ();
-               }
-
-               void RegisterServiceReference (Control control, ServiceReference serviceReference) {
+               void RegisterServiceReference (Control control, ServiceReference serviceReference)
+               {
                        if (serviceReference.InlineScript) {
                                string url = control.ResolveUrl (serviceReference.Path);
-                               LogicalTypeInfo logicalTypeInfo = LogicalTypeInfo.GetLogicalTypeInfo (WebServiceParser.GetCompiledType (url, Context), url);
+                               Type type = WebServiceParser.GetCompiledType (url, Context);
+                               if (type != null) {
+                                       object[] attributes = type.GetCustomAttributes (typeof (ScriptServiceAttribute), true);
+                                       if (attributes.Length == 0)
+                                               throw new InvalidOperationException ("Only Web services with a [ScriptService] attribute on the class definition can be called from script.");
+                               }
+                               
+                               LogicalTypeInfo logicalTypeInfo = LogicalTypeInfo.GetLogicalTypeInfo (type, url);
                                RegisterClientScriptBlock (control, typeof (ScriptManager), url, logicalTypeInfo.Proxy, true);
                        }
                        else {
@@ -843,6 +863,8 @@ namespace System.Web.UI
                                string pathInfo = "/js.invoke";
 #else
                                string pathInfo = "/js";
+                               if (IsDebuggingEnabled)
+                                       pathInfo += "debug";
 #endif
                                string url = String.Concat (control.ResolveClientUrl (serviceReference.Path), pathInfo);
                                RegisterClientScriptInclude (control, typeof (ScriptManager), url, url);
@@ -896,8 +918,11 @@ namespace System.Web.UI
 
                public static void RegisterExpandoAttribute (Control control, string controlId, string attributeName, string attributeValue, bool encode) {
                        Page page = control.Page;
-                       ScriptManager sm = GetCurrent (page);
+                       ScriptManager sm = GetCurrentInternal (page);
 
+                       if (sm == null)
+                               return;
+                       
                        if (sm._expandoAttributes == null)
                                sm._expandoAttributes = new List<RegisteredExpandoAttribute> ();
 
@@ -913,8 +938,11 @@ namespace System.Web.UI
 
                public static void RegisterHiddenField (Control control, string hiddenFieldName, string hiddenFieldInitialValue) {
                        Page page = control.Page;
-                       ScriptManager sm = GetCurrent (page);
+                       ScriptManager sm = GetCurrentInternal (page);
 
+                       if (sm == null)
+                               return;
+                       
                        if (sm._hiddenFields == null)
                                sm._hiddenFields = new List<RegisteredHiddenField> ();
 
@@ -930,8 +958,11 @@ namespace System.Web.UI
 
                public static void RegisterOnSubmitStatement (Control control, Type type, string key, string script) {
                        Page page = control.Page;
-                       ScriptManager sm = GetCurrent (page);
+                       ScriptManager sm = GetCurrentInternal (page);
 
+                       if (sm == null)
+                               return;
+                       
                        RegisterScript (ref sm._onSubmitStatements, control, type, key, script, null, false, RegisteredScriptType.OnSubmitStatement);
 
                        if (!sm.IsInAsyncPostBack)
@@ -982,7 +1013,8 @@ namespace System.Web.UI
                        RegisterScriptDescriptors ((Control) scriptControl, scriptControl.GetScriptDescriptors ());
                }
 
-               void RegisterScriptDescriptors (Control control, IEnumerable<ScriptDescriptor> scriptDescriptors) {
+               void RegisterScriptDescriptors (Control control, IEnumerable<ScriptDescriptor> scriptDescriptors)
+               {
                        if (scriptDescriptors == null)
                                return;
 
@@ -994,6 +1026,7 @@ namespace System.Web.UI
                                }
                                else
                                        sb.AppendLine ("Sys.Application.add_init(function() {");
+                               sb.Append ("\t");
                                sb.AppendLine (scriptDescriptor.GetScript ());
                                sb.AppendLine ("});");
                        }
@@ -1007,8 +1040,11 @@ namespace System.Web.UI
 
                public static void RegisterStartupScript (Control control, Type type, string key, string script, bool addScriptTags) {
                        Page page = control.Page;
-                       ScriptManager sm = GetCurrent (page);
+                       ScriptManager sm = GetCurrentInternal (page);
 
+                       if (sm == null)
+                               return;
+                       
                        RegisterScript (ref sm._startupScriptBlocks, control, type, key, script, null, addScriptTags, RegisteredScriptType.ClientStartupScript);
 
                        if (!sm.IsInAsyncPostBack)
@@ -1056,9 +1092,18 @@ namespace System.Web.UI
                                writer.WriteLine ("//<![CDATA[");
                                writer.WriteLine ("Sys.WebForms.PageRequestManager._initialize('{0}', document.getElementById('{1}'));", UniqueID, Page.Form.ClientID);
                                if (IsMultiForm)
-                                       writer.WriteLine ("Sys.WebForms.PageRequestManager.getInstance($get(\"{0}\"))._updateControls([{1}], [{2}], [{3}], {4});", Page.Form.ClientID, FormatUpdatePanelIDs (_updatePanels, true), FormatListIDs (_asyncPostBackControls, true), FormatListIDs (_postBackControls, true), AsyncPostBackTimeout);
+                                       writer.WriteLine ("Sys.WebForms.PageRequestManager.getInstance($get(\"{0}\"))._updateControls([{1}], [{2}], [{3}], {4});",
+                                                         Page.Form.ClientID,
+                                                         FormatUpdatePanelIDs (_updatePanels, true),
+                                                         FormatListIDs (_asyncPostBackControls, true, false),
+                                                         FormatListIDs (_postBackControls, true, false),
+                                                         AsyncPostBackTimeout);
                                else
-                                       writer.WriteLine ("Sys.WebForms.PageRequestManager.getInstance()._updateControls([{0}], [{1}], [{2}], {3});", FormatUpdatePanelIDs (_updatePanels, true), FormatListIDs (_asyncPostBackControls, true), FormatListIDs (_postBackControls, true), AsyncPostBackTimeout);
+                                       writer.WriteLine ("Sys.WebForms.PageRequestManager.getInstance()._updateControls([{0}], [{1}], [{2}], {3});",
+                                                         FormatUpdatePanelIDs (_updatePanels, true),
+                                                         FormatListIDs (_asyncPostBackControls, true, false),
+                                                         FormatListIDs (_postBackControls, true, false),
+                                                         AsyncPostBackTimeout);
                                writer.WriteLine ("//]]");
                                writer.WriteLine ("</script>");
                        }
@@ -1070,21 +1115,29 @@ namespace System.Web.UI
                                return null;
 
                        StringBuilder sb = new StringBuilder ();
-                       for (int i = 0; i < list.Count; i++) {
-                               sb.AppendFormat ("{0}{1}{2}{0},", useSingleQuote ? "'" : String.Empty, list [i].ChildrenAsTriggers ? "t" : "f", list [i].UniqueID);
+                       foreach (UpdatePanel panel in list) {
+                               if (!panel.Visible)
+                                       continue;
+                               
+                               sb.AppendFormat ("{0}{1}{2}{0},", useSingleQuote ? "'" : String.Empty, panel.ChildrenAsTriggers ? "t" : "f", panel.UniqueID);
                        }
+                       
                        if (sb.Length > 0)
                                sb.Length--;
 
                        return sb.ToString ();
                }
 
-               static string FormatListIDs<T> (List<T> list, bool useSingleQuote) where T : Control {
+               static string FormatListIDs<T> (List<T> list, bool useSingleQuote, bool skipInvisible) where T : Control
+               {
                        if (list == null || list.Count == 0)
                                return null;
 
                        StringBuilder sb = new StringBuilder ();
                        for (int i = 0; i < list.Count; i++) {
+                               if (skipInvisible && !list [i].Visible)
+                                       continue;
+                               
                                sb.AppendFormat ("{0}{1}{0},", useSingleQuote ? "'" : String.Empty, list [i].UniqueID);
                        }
                        if (sb.Length > 0)
@@ -1158,11 +1211,18 @@ namespace System.Web.UI
                        WriteCallbackOutput (output, pageRedirect, null, redirectUrl);
                }
 
-               internal void WriteCallbackPanel (TextWriter output, UpdatePanel panel, StringBuilder panelOutput) {
+               void RegisterPanelForRefresh (UpdatePanel panel)
+               {
                        if (_panelsToRefresh == null)
                                _panelsToRefresh = new List<UpdatePanel> ();
-                       _panelsToRefresh.Add (panel);
+                       else if (_panelsToRefresh.Contains (panel))
+                               return;
 
+                       _panelsToRefresh.Add (panel);
+               }
+               
+               internal void WriteCallbackPanel (TextWriter output, UpdatePanel panel, StringBuilder panelOutput)
+               {
                        WriteCallbackOutput (output, updatePanel, panel.ClientID, panelOutput);
                }
 
@@ -1196,18 +1256,89 @@ namespace System.Web.UI
                        output.Write ('|');
                }
 
-               void RenderPageCallback (HtmlTextWriter output, Control container) {
+               void RenderPageCallback (HtmlTextWriter output, Control container)
+               {
                        Page page = (Page) container;
 
+                       // MSDN: http://msdn.microsoft.com/en-us/library/system.web.ui.updatepanel.aspx
+                       //
+                       // Refreshing UpdatePanel Content
+                       //
+                       // When partial-page rendering is enabled, a control can perform a postback
+                       // that updates the whole page or an asynchronous postback that updates the
+                       // content of one or more UpdatePanel controls. Whether a control causes an
+                       // asynchronous postback and updates an UpdatePanel control depends on the
+                       // following:
+                       //
+                       // * If the UpdateMode property of the UpdatePanel control is set to Always,
+                       //   the UpdatePanel control's content is updated on every postback that
+                       //   originates from the page. This includes asynchronous postbacks from
+                       //   controls that are inside other UpdatePanel controls and postbacks from
+                       //   controls that are not inside UpdatePanel controls.
+                       //
+                       // * If the UpdateMode property is set to Conditional, the UpdatePanel
+                       //   control's content is updated in the following circumstances:
+                       //
+                       //       o When you call the Update method of the UpdatePanel control
+                       //         explicitly.
+                       //       o When the UpdatePanel control is nested inside another UpdatePanel
+                       //         control, and the parent panel is updated.
+                       //       o When a postback is caused by a control that is defined as a
+                       //         trigger by using the Triggers property of the UpdatePanel
+                       //         control. In this scenario, the control explicitly triggers an
+                       //         update of the panel content. The control can be either inside or
+                       //         outside the UpdatePanel control that the trigger is associated
+                       //         with.
+                       //       o When the ChildrenAsTriggers property is set to true and a child
+                       //         control of the UpdatePanel control causes a postback. Child
+                       //         controls of nested UpdatePanel controls do not cause an update to
+                       //         the outer UpdatePanel control unless they are explicitly defined
+                       //         as triggers.
+                       //
+                       if (_updatePanels != null && _updatePanels.Count > 0) {
+                               bool needsUpdate;
+                               
+                               foreach (UpdatePanel panel in _updatePanels) {
+                                       if (panel.RequiresUpdate || (!String.IsNullOrEmpty (_panelToRefreshID) && String.Compare (_panelToRefreshID, panel.UniqueID, StringComparison.Ordinal) == 0))
+                                               needsUpdate = true;
+                                       else
+                                               needsUpdate = false;
+                                       
+                                       if (needsUpdate == false) {
+                                               Control parent = panel.Parent;
+                                               UpdatePanel parentPanel;
+                                               
+                                               bool havePanelsToRefresh = _panelsToRefresh != null ? _panelsToRefresh.Count > 0 : false;
+                                               while (parent != null) {
+                                                       parentPanel = parent as UpdatePanel;
+                                                       if (havePanelsToRefresh && parentPanel != null && _panelsToRefresh.Contains (parentPanel)) {
+                                                               needsUpdate = true;
+                                                               break;
+                                                       }
+                                                       parent = parent.Parent;
+                                               }
+                                       }
+                                       
+                                       panel.SetInPartialRendering (needsUpdate);
+                                       if (needsUpdate)
+                                               RegisterPanelForRefresh (panel);
+                               }
+                       }
+                       
                        page.Form.SetRenderMethodDelegate (RenderFormCallback);
                        HtmlTextParser parser = new HtmlTextParser (output);
                        page.Form.RenderControl (parser);
 
-                       WriteCallbackOutput (output, asyncPostBackControlIDs, null, FormatListIDs (_asyncPostBackControls, false));
-                       WriteCallbackOutput (output, postBackControlIDs, null, FormatListIDs (_postBackControls, false));
+                       Dictionary <string, string> pageHiddenFields = parser.HiddenFields;
+                       if (pageHiddenFields != null)
+                               foreach (KeyValuePair <string, string> kvp in pageHiddenFields)
+                                       WriteCallbackOutput (output, hiddenField, kvp.Key, kvp.Value);
+                       
+                       WriteCallbackOutput (output, asyncPostBackControlIDs, null, FormatListIDs (_asyncPostBackControls, false, false));
+                       WriteCallbackOutput (output, postBackControlIDs, null, FormatListIDs (_postBackControls, false, false));
                        WriteCallbackOutput (output, updatePanelIDs, null, FormatUpdatePanelIDs (_updatePanels, false));
-                       WriteCallbackOutput (output, childUpdatePanelIDs, null, FormatListIDs (_childUpdatePanels, false));
-                       WriteCallbackOutput (output, panelsToRefreshIDs, null, FormatListIDs (_panelsToRefresh, false));
+                       WriteCallbackOutput (output, childUpdatePanelIDs, null, FormatListIDs (_childUpdatePanels, false, true));
+                       WriteCallbackOutput (output, panelsToRefreshIDs, null, FormatListIDs (_panelsToRefresh, false, true));
                        WriteCallbackOutput (output, asyncPostBackTimeout, null, AsyncPostBackTimeout.ToString ());
                        if (!IsMultiForm)
                                WriteCallbackOutput (output, pageTitle, null, Page.Title);
@@ -1268,32 +1399,37 @@ namespace System.Web.UI
                void WriteScriptBlocks (HtmlTextWriter output, List<RegisteredScript> scriptList) {
                        if (scriptList == null)
                                return;
-                       Hashtable registeredScripts = new Hashtable ();
+                       var registeredScripts = new Dictionary <string, RegisteredScript> ();
+                       Control control;
+                       Page page = Page;
+                       
                        for (int i = 0; i < scriptList.Count; i++) {
                                RegisteredScript scriptEntry = scriptList [i];
                                if (registeredScripts.ContainsKey (scriptEntry.Key))
                                        continue;
-                               if (Page == scriptEntry.Control || HasBeenRendered (scriptEntry.Control)) {
+
+                               control = scriptEntry.Control;
+                               if (page == control || HasBeenRendered (control)) {
                                        registeredScripts.Add (scriptEntry.Key, scriptEntry);
                                        switch (scriptEntry.ScriptType) {
-                                       case RegisteredScriptType.ClientScriptBlock:
-                                               if (scriptEntry.AddScriptTags)
-                                                       WriteCallbackOutput (output, scriptBlock, scriptContentNoTags, scriptEntry.Script);
-                                               else
-                                                       WriteCallbackOutput (output, scriptBlock, scriptContentWithTags, SerializeScriptBlock (scriptEntry));
-                                               break;
-                                       case RegisteredScriptType.ClientStartupScript:
-                                               if (scriptEntry.AddScriptTags)
-                                                       WriteCallbackOutput (output, scriptStartupBlock, scriptContentNoTags, scriptEntry.Script);
-                                               else
-                                                       WriteCallbackOutput (output, scriptStartupBlock, scriptContentWithTags, SerializeScriptBlock (scriptEntry));
-                                               break;
-                                       case RegisteredScriptType.ClientScriptInclude:
-                                               WriteCallbackOutput (output, scriptBlock, scriptPath, scriptEntry.Url);
-                                               break;
-                                       case RegisteredScriptType.OnSubmitStatement:
-                                               WriteCallbackOutput (output, onSubmit, null, scriptEntry.Script);
-                                               break;
+                                               case RegisteredScriptType.ClientScriptBlock:
+                                                       if (scriptEntry.AddScriptTags)
+                                                               WriteCallbackOutput (output, scriptBlock, scriptContentNoTags, scriptEntry.Script);
+                                                       else
+                                                               WriteCallbackOutput (output, scriptBlock, scriptContentWithTags, SerializeScriptBlock (scriptEntry));
+                                                       break;
+                                               case RegisteredScriptType.ClientStartupScript:
+                                                       if (scriptEntry.AddScriptTags)
+                                                               WriteCallbackOutput (output, scriptStartupBlock, scriptContentNoTags, scriptEntry.Script);
+                                                       else
+                                                               WriteCallbackOutput (output, scriptStartupBlock, scriptContentWithTags, SerializeScriptBlock (scriptEntry));
+                                                       break;
+                                               case RegisteredScriptType.ClientScriptInclude:
+                                                       WriteCallbackOutput (output, scriptBlock, scriptPath, scriptEntry.Url);
+                                                       break;
+                                               case RegisteredScriptType.OnSubmitStatement:
+                                                       WriteCallbackOutput (output, onSubmit, null, scriptEntry.Script);
+                                                       break;
                                        }
                                }
                        }
@@ -1340,14 +1476,15 @@ namespace System.Web.UI
                        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.", scriptEntry.Type, scriptEntry.Key, scriptEntry.Script));
                }
 
-               void RenderFormCallback (HtmlTextWriter output, Control container) {
+               void RenderFormCallback (HtmlTextWriter output, Control container)
+               {
                        output = ((HtmlTextParser) output).ResponseOutput;
                        HtmlForm form = (HtmlForm) container;
                        HtmlTextWriter writer = new HtmlDropWriter (output);
+                       
                        if (form.HasControls ()) {
-                               for (int i = 0; i < form.Controls.Count; i++) {
-                                       form.Controls [i].RenderControl (writer);
-                               }
+                               foreach (Control control in form.Controls)
+                                       control.RenderControl (writer);
                        }
                }
 
@@ -1369,10 +1506,29 @@ namespace System.Web.UI
                {
                        bool _done;
 
+                       public Dictionary <string, string> _hiddenFields;
+
+                       public Dictionary <string, string> HiddenFields {
+                               get { return _hiddenFields; }
+                       }
+                       
                        public HtmlTextParser (HtmlTextWriter responseOutput)
-                               : base (new TextParser (responseOutput), responseOutput) {
+                               : this (new TextParser (responseOutput), responseOutput) {
                        }
 
+                       HtmlTextParser (TextParser parser, HtmlTextWriter responseOutput)
+                               : base (parser, responseOutput)
+                       {
+                               parser.HiddenFieldParsed += new TextParser.TextParserHiddenFieldParsedEventHandler (OnHiddenFieldParsed);
+                       }
+                       
+                       void OnHiddenFieldParsed (TextParser sender, TextParserHiddenFieldParsedEventArgs args)
+                       {
+                               if (_hiddenFields == null)
+                                       _hiddenFields = new Dictionary <string, string> ();
+                               _hiddenFields [args.Name] = args.Value;
+                       }
+                       
                        public override void WriteAttribute (string name, string value) {
                                if (!_done && String.Compare ("action", name, StringComparison.OrdinalIgnoreCase) == 0) {
                                        _done = true;
@@ -1383,8 +1539,31 @@ namespace System.Web.UI
                        }
                }
 
+               sealed class TextParserHiddenFieldParsedEventArgs : EventArgs
+               {
+                       public string Name {
+                               get;
+                               private set;
+                       }
+
+                       public string Value {
+                               get;
+                               private set;
+                       }
+                       
+                       public TextParserHiddenFieldParsedEventArgs (string name, string value)
+                       {
+                               this.Name = name;
+                               this.Value = value;
+                       }
+               }
+               
                sealed class TextParser : TextWriter
                {
+                       public delegate void TextParserHiddenFieldParsedEventHandler (TextParser sender, TextParserHiddenFieldParsedEventArgs args);
+
+                       static object textParserHiddenFieldParsedEvent = new object ();
+                       
                        int _state;
                        char _charState = (char) 255;
                        const char nullCharState = (char) 255;
@@ -1392,7 +1571,13 @@ namespace System.Web.UI
                        Dictionary<string, string> _currentField;
                        string _currentAttribute;
                        readonly HtmlTextWriter _responseOutput;
-
+                       TextParserHiddenFieldParsedEventHandler _hiddenFieldParsedHandler;
+                       
+                       public event TextParserHiddenFieldParsedEventHandler HiddenFieldParsed {
+                               add { _hiddenFieldParsedHandler = value; }
+                               remove { _hiddenFieldParsedHandler = null; }
+                       }
+                       
                        public override Encoding Encoding {
                                get { return Encoding.UTF8; }
                        }
@@ -1514,7 +1699,10 @@ namespace System.Web.UI
                                if (value == null)
                                        return;
 
-                               ScriptManager.WriteCallbackOutput (_responseOutput, hiddenField, _currentField ["name"], HttpUtility.HtmlDecode (value));
+                               if (_hiddenFieldParsedHandler != null)
+                                       _hiddenFieldParsedHandler (this, new TextParserHiddenFieldParsedEventArgs (_currentField ["name"], HttpUtility.HtmlDecode (value)));
+                               else
+                                       ScriptManager.WriteCallbackOutput (_responseOutput, hiddenField, _currentField ["name"], HttpUtility.HtmlDecode (value));
                        }
                }
 
@@ -1541,15 +1729,15 @@ namespace System.Web.UI
                                _ci = ci;
                        }
 
-                       public string Name {
+                       public string name {
                                get { return _ci.Name; }
                        }
 
-                       public NumberFormatInfo NumberFormat {
+                       public NumberFormatInfo numberFormat {
                                get { return _ci.NumberFormat; }
                        }
 
-                       public DateTimeFormatInfo DateTimeFormat {
+                       public DateTimeFormatInfo dateTimeFormat {
                                get { return _ci.DateTimeFormat; }
                        }                       
                }