5 // Igor Zelmanovich <igorz@mainsoft.com>
7 // (C) 2007 Mainsoft, Inc. http://www.mainsoft.com
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
31 using System.Collections.Generic;
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;
42 using System.Globalization;
43 using System.Threading;
44 using System.Web.Script.Serialization;
45 using System.Web.Script.Services;
48 namespace System.Web.UI
50 [ParseChildrenAttribute (true)]
51 [DefaultPropertyAttribute ("Scripts")]
52 [DesignerAttribute ("System.Web.UI.Design.ScriptManagerDesigner, System.Web.Extensions.Design, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")]
53 [NonVisualControlAttribute]
54 [PersistChildrenAttribute (false)]
55 [AspNetHostingPermissionAttribute (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
56 [AspNetHostingPermissionAttribute (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
57 public class ScriptManager : Control, IPostBackDataHandler
59 // the keywords are used in fomatting async response
60 const string updatePanel = "updatePanel";
61 const string hiddenField = "hiddenField";
62 const string arrayDeclaration = "arrayDeclaration";
63 const string scriptBlock = "scriptBlock";
64 const string expando = "expando";
65 const string onSubmit = "onSubmit";
66 const string asyncPostBackControlIDs = "asyncPostBackControlIDs";
67 const string postBackControlIDs = "postBackControlIDs";
68 const string updatePanelIDs = "updatePanelIDs";
69 const string asyncPostBackTimeout = "asyncPostBackTimeout";
70 const string childUpdatePanelIDs = "childUpdatePanelIDs";
71 const string panelsToRefreshIDs = "panelsToRefreshIDs";
72 const string formAction = "formAction";
73 const string dataItem = "dataItem";
74 const string dataItemJson = "dataItemJson";
75 const string scriptDispose = "scriptDispose";
76 const string pageRedirect = "pageRedirect";
77 const string error = "error";
78 const string pageTitle = "pageTitle";
79 const string focus = "focus";
80 const string scriptContentNoTags = "ScriptContentNoTags";
81 const string scriptContentWithTags = "ScriptContentWithTags";
82 const string scriptPath = "ScriptPath";
84 static readonly object ScriptManagerKey = new object ();
86 int _asyncPostBackTimeout = 90;
87 List<Control> _asyncPostBackControls;
88 List<Control> _postBackControls;
89 List<UpdatePanel> _childUpdatePanels;
90 List<UpdatePanel> _panelsToRefresh;
91 List<UpdatePanel> _updatePanels;
92 ScriptReferenceCollection _scripts;
93 ServiceReferenceCollection _services;
94 bool _isInAsyncPostBack;
95 bool _isInPartialRendering;
96 string _asyncPostBackSourceElementID;
97 ScriptMode _scriptMode = ScriptMode.Auto;
98 bool _enableScriptGlobalization;
99 bool _enableScriptLocalization;
101 ScriptEntry _clientScriptBlocks;
102 ScriptEntry _startupScriptBlocks;
103 ScriptEntry _scriptIncludes;
104 ScriptEntry _onSubmitStatements;
105 List<ArrayDeclaration> _arrayDeclarations;
106 Hashtable _hiddenFields;
107 List<IScriptControl> _registeredScriptControls;
108 Dictionary<IExtenderControl, Control> _registeredExtenderControls;
109 bool? _supportsPartialRendering;
110 bool _enablePartialRendering = true;
112 string _panelToRefreshID;
113 Dictionary<Control, DataItemEntry> _dataItems;
114 bool _enablePageMethods;
115 string _controlIDToFocus;
116 bool _allowCustomErrorsRedirect = true;
117 string _asyncPostBackErrorMessage;
118 List<DisposeScriptEntry> _disposeScripts;
119 List<ScriptReferenceEntry> _scriptToRegister;
120 bool _loadScriptsBeforeUI = true;
121 AuthenticationServiceManager _authenticationService;
122 ProfileServiceManager _profileService;
124 [DefaultValue (true)]
125 [Category ("Behavior")]
126 public bool AllowCustomErrorsRedirect {
128 return _allowCustomErrorsRedirect;
131 _allowCustomErrorsRedirect = value;
135 [Category ("Behavior")]
137 public string AsyncPostBackErrorMessage {
139 if (String.IsNullOrEmpty (_asyncPostBackErrorMessage))
141 return _asyncPostBackErrorMessage;
144 _asyncPostBackErrorMessage = value;
149 public string AsyncPostBackSourceElementID {
151 if (_asyncPostBackSourceElementID == null)
153 return _asyncPostBackSourceElementID;
158 [Category ("Behavior")]
159 public int AsyncPostBackTimeout {
161 return _asyncPostBackTimeout;
164 _asyncPostBackTimeout = value;
168 [Category ("Behavior")]
169 [MergableProperty (false)]
171 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
172 [PersistenceMode (PersistenceMode.InnerProperty)]
173 public AuthenticationServiceManager AuthenticationService {
175 if (_authenticationService == null)
176 _authenticationService = new AuthenticationServiceManager ();
177 return _authenticationService;
181 [Category ("Behavior")]
182 [DefaultValue (false)]
183 public bool EnablePageMethods {
185 return _enablePageMethods;
188 _enablePageMethods = value;
192 [DefaultValue (true)]
193 [Category ("Behavior")]
194 public bool EnablePartialRendering {
196 return _enablePartialRendering;
200 throw new InvalidOperationException ();
201 _enablePartialRendering = value;
205 [DefaultValue (false)]
206 [Category ("Behavior")]
207 public bool EnableScriptGlobalization {
209 return _enableScriptGlobalization;
212 _enableScriptGlobalization = value;
216 [Category ("Behavior")]
217 [DefaultValue (false)]
218 public bool EnableScriptLocalization {
220 return _enableScriptLocalization;
223 _enableScriptLocalization = value;
228 public bool IsDebuggingEnabled {
230 if (IsDeploymentRetail)
233 CompilationSection compilation = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation");
234 if (!compilation.Debug && (ScriptMode == ScriptMode.Auto || ScriptMode == ScriptMode.Inherit))
237 if (ScriptMode == ScriptMode.Release)
244 bool IsDeploymentRetail {
249 DeploymentSection deployment = (DeploymentSection) WebConfigurationManager.GetSection ("system.web/deployment");
250 return deployment.Retail;
256 public bool IsInAsyncPostBack {
258 return _isInAsyncPostBack;
262 internal bool IsInPartialRendering {
264 return _isInPartialRendering;
267 _isInPartialRendering = value;
271 [Category ("Behavior")]
272 [DefaultValue (true)]
273 public bool LoadScriptsBeforeUI {
275 return _loadScriptsBeforeUI;
278 _loadScriptsBeforeUI = value;
282 [PersistenceMode (PersistenceMode.InnerProperty)]
284 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
285 [Category ("Behavior")]
286 [MergableProperty (false)]
287 public ProfileServiceManager ProfileService {
289 if (_profileService == null)
290 _profileService = new ProfileServiceManager ();
291 return _profileService;
295 [Category ("Behavior")]
297 [MonoLimitation ("The 'Auto' value is the same as 'Debug'.")]
299 public ScriptMode ScriptMode {
304 if (value == ScriptMode.Inherit)
305 value = ScriptMode.Auto;
311 [Category ("Behavior")]
312 public string ScriptPath {
314 if (_scriptPath == null)
323 [PersistenceMode (PersistenceMode.InnerProperty)]
325 [Category ("Behavior")]
326 [MergableProperty (false)]
327 public ScriptReferenceCollection Scripts {
329 if (_scripts == null)
330 _scripts = new ScriptReferenceCollection ();
336 [PersistenceMode (PersistenceMode.InnerProperty)]
338 [MergableProperty (false)]
339 [Category ("Behavior")]
340 public ServiceReferenceCollection Services {
342 if (_services == null)
343 _services = new ServiceReferenceCollection ();
349 [DefaultValue (true)]
351 public bool SupportsPartialRendering {
353 if (!_supportsPartialRendering.HasValue)
354 _supportsPartialRendering = CheckSupportsPartialRendering ();
355 return _supportsPartialRendering.Value;
359 throw new InvalidOperationException ();
360 if (!EnablePartialRendering && value)
361 throw new InvalidOperationException ("The SupportsPartialRendering property cannot be set when EnablePartialRendering is false.");
363 _supportsPartialRendering = value;
367 bool CheckSupportsPartialRendering () {
368 if (!EnablePartialRendering)
370 // TODO: consider browser capabilities
374 [EditorBrowsable (EditorBrowsableState.Never)]
376 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
377 public override bool Visible {
382 throw new NotImplementedException ();
386 [Category ("Action")]
387 public event EventHandler<AsyncPostBackErrorEventArgs> AsyncPostBackError;
389 [Category ("Action")]
390 public event EventHandler<ScriptReferenceEventArgs> ResolveScriptReference;
392 public static ScriptManager GetCurrent (Page page) {
394 throw new ArgumentNullException("page");
395 return (ScriptManager) page.Items [ScriptManagerKey];
398 static void SetCurrent (Page page, ScriptManager instance) {
399 page.Items [ScriptManagerKey] = instance;
402 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection) {
403 _isInAsyncPostBack = true;
404 string arg = postCollection [postDataKey];
405 if (!String.IsNullOrEmpty (arg)) {
406 string [] args = arg.Split ('|');
407 _panelToRefreshID = args [0];
408 _asyncPostBackSourceElementID = args [1];
414 protected internal virtual void OnAsyncPostBackError (AsyncPostBackErrorEventArgs e) {
415 if (AsyncPostBackError != null)
416 AsyncPostBackError (this, e);
419 protected override void OnInit (EventArgs e) {
422 if (GetCurrent (Page) != null)
423 throw new InvalidOperationException ("Only one instance of a ScriptManager can be added to the page.");
425 SetCurrent (Page, this);
426 Page.Error += new EventHandler (OnPageError);
430 void OnPageError (object sender, EventArgs e) {
431 if (IsInAsyncPostBack)
432 OnAsyncPostBackError (new AsyncPostBackErrorEventArgs (Context.Error));
435 protected override void OnPreRender (EventArgs e) {
436 base.OnPreRender (e);
438 Page.PreRenderComplete += new EventHandler (OnPreRenderComplete);
440 if (IsInAsyncPostBack) {
441 Page.SetRenderMethodDelegate (RenderPageCallback);
444 if (EnableScriptGlobalization) {
445 CultureInfo culture = Thread.CurrentThread.CurrentCulture;
446 string script = String.Format ("var __cultureInfo = '{0}';", JavaScriptSerializer.DefaultSerializer.Serialize (new CultureInfoSerializer (culture)));
447 RegisterClientScriptBlock (this, typeof (ScriptManager), "ScriptGlobalization", script, true);
450 // Register dispose script
451 if (_disposeScripts != null && _disposeScripts.Count > 0) {
452 StringBuilder sb = new StringBuilder ();
454 for (int i = 0; i < _disposeScripts.Count; i++) {
455 DisposeScriptEntry entry = _disposeScripts [i];
457 sb.Append ("Sys.WebForms.PageRequestManager.getInstance($get(\"" + Page.Form.ClientID + "\"))._registerDisposeScript(\"");
459 sb.Append ("Sys.WebForms.PageRequestManager.getInstance()._registerDisposeScript(\"");
460 sb.Append (entry.UpdatePanel.ClientID);
462 sb.Append (JavaScriptSerializer.DefaultSerializer.Serialize (entry.Script)); //JavaScriptSerializer.Serialize used escape script literal
463 sb.AppendLine (");");
465 RegisterStartupScript (this, typeof (ExtenderControl), "disposeScripts;", sb.ToString (), true);
469 // to cause webform client script being included
470 Page.ClientScript.GetPostBackEventReference (new PostBackOptions (this, null, null, false, false, false, true, true, null));
472 Page.ClientScript.GetPostBackEventReference (this, null);
477 void OnPreRenderComplete (object sender, EventArgs e) {
479 ScriptReference ajaxScript = new ScriptReference ("MicrosoftAjax.js", String.Empty);
480 ajaxScript.NotifyScriptLoaded = false;
481 OnResolveScriptReference (new ScriptReferenceEventArgs (ajaxScript));
483 ScriptReference ajaxWebFormsScript = new ScriptReference ("MicrosoftAjaxWebForms.js", String.Empty);
484 ajaxWebFormsScript.NotifyScriptLoaded = false;
485 OnResolveScriptReference (new ScriptReferenceEventArgs (ajaxWebFormsScript));
487 ScriptReference ajaxExtensionScript = null;
488 ScriptReference ajaxWebFormsExtensionScript = null;
490 ajaxExtensionScript = new ScriptReference ("MicrosoftAjaxExtension.js", String.Empty);
491 OnResolveScriptReference (new ScriptReferenceEventArgs (ajaxExtensionScript));
493 ajaxWebFormsExtensionScript = new ScriptReference ("MicrosoftAjaxWebFormsExtension.js", String.Empty);
494 OnResolveScriptReference (new ScriptReferenceEventArgs (ajaxWebFormsExtensionScript));
497 foreach (ScriptReferenceEntry script in GetScriptReferences ()) {
498 OnResolveScriptReference (new ScriptReferenceEventArgs (script.ScriptReference));
499 if (!IsInAsyncPostBack || (script.Control != this && HasBeenRendered (script.Control))) {
500 if (_scriptToRegister == null)
501 _scriptToRegister = new List<ScriptReferenceEntry> ();
502 _scriptToRegister.Add (script);
506 if (!IsInAsyncPostBack) {
507 // Register Ajax framework script.
508 RegisterScriptReference (ajaxScript, true);
510 RegisterScriptReference (ajaxExtensionScript, true);
511 RegisterClientScriptBlock (this, typeof (ScriptManager), "Sys.Application", "\nSys.Application._initialize(document.getElementById('" + Page.Form.ClientID + "'));\n", true);
514 StringBuilder sb = new StringBuilder ();
515 sb.AppendLine ("if (typeof(Sys) === 'undefined') throw new Error('ASP.NET Ajax client-side framework failed to load.');");
517 ScriptingProfileServiceSection profileService = (ScriptingProfileServiceSection) WebConfigurationManager.GetSection ("system.web.extensions/scripting/webServices/profileService");
518 if (profileService.Enabled)
519 sb.AppendLine ("Sys.Services._ProfileService.DefaultWebServicePath = '" + ResolveClientUrl ("~" + System.Web.Script.Services.ProfileService.DefaultWebServicePath) + "';");
520 if (_profileService != null && !String.IsNullOrEmpty (_profileService.Path))
521 sb.AppendLine ("Sys.Services.ProfileService.set_path('" + ResolveUrl (_profileService.Path) + "');");
523 ScriptingAuthenticationServiceSection authenticationService = (ScriptingAuthenticationServiceSection) WebConfigurationManager.GetSection ("system.web.extensions/scripting/webServices/authenticationService");
524 if (authenticationService.Enabled)
525 sb.AppendLine ("Sys.Services._AuthenticationService.DefaultWebServicePath = '" + ResolveClientUrl ("~/Authentication_JSON_AppService.axd") + "';");
526 if (_authenticationService != null && !String.IsNullOrEmpty (_authenticationService.Path))
527 sb.AppendLine ("Sys.Services.AuthenticationService.set_path('" + ResolveUrl (_authenticationService.Path) + "');");
529 RegisterClientScriptBlock (this, typeof (ScriptManager), "Framework", sb.ToString (), true);
531 RegisterScriptReference (ajaxWebFormsScript, true);
534 RegisterScriptReference (ajaxWebFormsExtensionScript, true);
538 if (_scriptToRegister != null)
539 for (int i = 0; i < _scriptToRegister.Count; i++)
540 RegisterScriptReference (_scriptToRegister [i].ScriptReference, _scriptToRegister [i].LoadScriptsBeforeUI);
542 if (!IsInAsyncPostBack) {
544 if (_services != null && _services.Count > 0) {
545 for (int i = 0; i < _services.Count; i++) {
546 RegisterServiceReference (_services [i]);
550 if (EnablePageMethods) {
551 LogicalTypeInfo logicalTypeInfo = LogicalTypeInfo.GetLogicalTypeInfo (Page.GetType (), Page.Request.FilePath);
552 RegisterClientScriptBlock (this, typeof (ScriptManager), "PageMethods", logicalTypeInfo.Proxy, true);
555 // Register startup script
557 RegisterStartupScript (this, typeof (ExtenderControl), "Sys.Application.initialize();", "Sys.Application.getInstance($get(\"" + Page.Form.ClientID + "\")).initialize();\n", true);
559 RegisterStartupScript (this, typeof (ExtenderControl), "Sys.Application.initialize();", "Sys.Application.initialize();\n", true);
566 Mainsoft.Web.Configuration.PagesSection pageSection = (Mainsoft.Web.Configuration.PagesSection) WebConfigurationManager.GetSection ("mainsoft.web/pages");
567 if (pageSection != null)
568 return pageSection.MultiForm;
574 get { return false; }
578 static bool HasBeenRendered (Control control) {
582 UpdatePanel parent = control.Parent as UpdatePanel;
583 if (parent != null && parent.RequiresUpdate)
586 return HasBeenRendered (control.Parent);
589 IEnumerable<ScriptReferenceEntry> GetScriptReferences () {
590 if (_scripts != null && _scripts.Count > 0) {
591 for (int i = 0; i < _scripts.Count; i++) {
592 yield return new ScriptReferenceEntry (this, _scripts [i], LoadScriptsBeforeUI);
596 if (_registeredScriptControls != null && _registeredScriptControls.Count > 0) {
597 for (int i = 0; i < _registeredScriptControls.Count; i++) {
598 IEnumerable<ScriptReference> scripts = _registeredScriptControls [i].GetScriptReferences ();
600 foreach (ScriptReference s in scripts)
601 yield return new ScriptReferenceEntry ((Control) _registeredScriptControls [i], s, LoadScriptsBeforeUI);
605 if (_registeredExtenderControls != null && _registeredExtenderControls.Count > 0) {
606 foreach (IExtenderControl ex in _registeredExtenderControls.Keys) {
607 IEnumerable<ScriptReference> scripts = ex.GetScriptReferences ();
609 foreach (ScriptReference s in scripts)
610 yield return new ScriptReferenceEntry ((Control) ex, s, LoadScriptsBeforeUI);
615 protected virtual void OnResolveScriptReference (ScriptReferenceEventArgs e) {
616 if (ResolveScriptReference != null)
617 ResolveScriptReference (this, e);
620 protected virtual void RaisePostDataChangedEvent () {
621 UpdatePanel up = Page.FindControl (_panelToRefreshID) as UpdatePanel;
622 if (up != null && up.ChildrenAsTriggers)
626 public static void RegisterArrayDeclaration (Control control, string arrayName, string arrayValue) {
627 RegisterArrayDeclaration (control.Page, arrayName, arrayValue);
630 public static void RegisterArrayDeclaration (Page page, string arrayName, string arrayValue) {
631 ScriptManager sm = GetCurrent (page);
632 if (sm.IsInAsyncPostBack)
633 sm.RegisterArrayDeclaration (arrayName, arrayValue);
635 page.ClientScript.RegisterArrayDeclaration (arrayName, arrayValue);
638 void RegisterArrayDeclaration (string arrayName, string arrayValue) {
639 if (_arrayDeclarations == null)
640 _arrayDeclarations = new List<ArrayDeclaration> ();
642 _arrayDeclarations.Add (new ArrayDeclaration (arrayName, arrayValue));
645 public void RegisterAsyncPostBackControl (Control control) {
649 if (_asyncPostBackControls == null)
650 _asyncPostBackControls = new List<Control> ();
652 if (_asyncPostBackControls.Contains (control))
655 _asyncPostBackControls.Add (control);
658 public static void RegisterClientScriptBlock (Control control, Type type, string key, string script, bool addScriptTags) {
659 RegisterClientScriptBlock (control.Page, type, key, script, addScriptTags);
662 public static void RegisterClientScriptBlock (Page page, Type type, string key, string script, bool addScriptTags) {
663 ScriptManager sm = GetCurrent (page);
664 if (sm.IsInAsyncPostBack)
665 RegisterScript (ref sm._clientScriptBlocks, type, key, script, addScriptTags ? ScriptEntryType.ScriptContentNoTags : ScriptEntryType.ScriptContentWithTags);
667 page.ClientScript.RegisterClientScriptBlock (type, key, script, addScriptTags);
670 public static void RegisterClientScriptInclude (Control control, Type type, string key, string url) {
671 RegisterClientScriptInclude (control.Page, type, key, url);
674 public static void RegisterClientScriptInclude (Page page, Type type, string key, string url) {
675 ScriptManager sm = GetCurrent (page);
676 if (sm.IsInAsyncPostBack)
677 RegisterScript (ref sm._scriptIncludes, type, key, url, ScriptEntryType.ScriptPath);
679 page.ClientScript.RegisterClientScriptInclude (type, key, url);
682 public static void RegisterClientScriptResource (Control control, Type type, string resourceName) {
683 RegisterClientScriptResource (control.Page, type, resourceName);
686 public static void RegisterClientScriptResource (Page page, Type type, string resourceName) {
687 RegisterClientScriptInclude (page, type, "resource-" + resourceName, ScriptResourceHandler.GetResourceUrl (type.Assembly, resourceName, true));
690 void RegisterScriptReference (ScriptReference script, bool loadScriptsBeforeUI) {
692 bool isDebugMode = IsDeploymentRetail ? false : (script.ScriptModeInternal == ScriptMode.Inherit ? IsDebuggingEnabled : (script.ScriptModeInternal == ScriptMode.Debug));
694 if (!String.IsNullOrEmpty (script.Path)) {
695 url = GetScriptName (ResolveClientUrl (script.Path), isDebugMode, EnableScriptLocalization ? script.ResourceUICultures : null);
697 else if (!String.IsNullOrEmpty (script.Name)) {
699 if (String.IsNullOrEmpty (script.Assembly))
700 assembly = typeof (ScriptManager).Assembly;
702 assembly = Assembly.Load (script.Assembly);
703 string name = GetScriptName (script.Name, isDebugMode, null);
704 if (script.IgnoreScriptPath || String.IsNullOrEmpty (ScriptPath))
705 url = ScriptResourceHandler.GetResourceUrl (assembly, name, script.NotifyScriptLoaded);
707 AssemblyName an = assembly.GetName ();
708 url = ResolveClientUrl (String.Concat (VirtualPathUtility.AppendTrailingSlash (ScriptPath), an.Name, '/', an.Version, '/', name));
712 throw new InvalidOperationException ("Name and Path cannot both be empty.");
715 if (loadScriptsBeforeUI)
716 RegisterClientScriptInclude (this, typeof (ScriptManager), url, url);
718 RegisterStartupScript (this, typeof (ScriptManager), url, String.Format ("<script src=\"{0}\" type=\"text/javascript\"></script>", url), false);
721 static string GetScriptName (string releaseName, bool isDebugMode, string [] supportedUICultures) {
722 if (!isDebugMode && (supportedUICultures == null || supportedUICultures.Length == 0))
725 if (releaseName.Length < 3 || !releaseName.EndsWith (".js", StringComparison.OrdinalIgnoreCase))
726 throw new InvalidOperationException (String.Format ("'{0}' is not a valid script path. The path must end in '.js'.", releaseName));
728 StringBuilder sb = new StringBuilder (releaseName);
731 sb.Append (".debug");
732 string culture = Thread.CurrentThread.CurrentUICulture.Name;
733 if (supportedUICultures != null && Array.IndexOf<string> (supportedUICultures, culture) >= 0)
734 sb.AppendFormat (".{0}", culture);
737 return sb.ToString ();
740 void RegisterServiceReference (ServiceReference serviceReference) {
741 if (serviceReference.InlineScript) {
742 string url = ResolveUrl (serviceReference.Path);
743 LogicalTypeInfo logicalTypeInfo = LogicalTypeInfo.GetLogicalTypeInfo (WebServiceParser.GetCompiledType (url, Context), url);
744 RegisterClientScriptBlock (this, typeof (ScriptManager), url, logicalTypeInfo.Proxy, true);
748 string pathInfo = "/js.invoke";
750 string pathInfo = "/js";
752 string url = String.Concat (ResolveClientUrl (serviceReference.Path), pathInfo);
753 RegisterClientScriptInclude (this, typeof (ScriptManager), url, url);
757 public void RegisterDataItem (Control control, string dataItem) {
758 RegisterDataItem (control, dataItem, false);
761 public void RegisterDataItem (Control control, string dataItem, bool isJsonSerialized) {
762 if (!IsInAsyncPostBack)
763 throw new InvalidOperationException ("RegisterDataItem can only be called during an async postback.");
765 throw new ArgumentNullException ("control");
767 if (_dataItems == null)
768 _dataItems = new Dictionary<Control, DataItemEntry> ();
770 if (_dataItems.ContainsKey (control))
771 throw new ArgumentException (String.Format ("'{0}' already has a data item registered.", control.ID), "control");
773 _dataItems.Add (control, new DataItemEntry (dataItem, isJsonSerialized));
776 public void RegisterDispose (Control control, string disposeScript) {
778 throw new ArgumentNullException ("control");
779 if (disposeScript == null)
780 throw new ArgumentNullException ("disposeScript");
782 UpdatePanel updatePanel = GetUpdatePanel (control);
783 if (updatePanel == null)
786 if (_disposeScripts == null)
787 _disposeScripts = new List<DisposeScriptEntry> ();
788 _disposeScripts.Add (new DisposeScriptEntry (updatePanel, disposeScript));
791 static UpdatePanel GetUpdatePanel (Control control) {
795 UpdatePanel parent = control.Parent as UpdatePanel;
799 return GetUpdatePanel (control.Parent);
802 public static void RegisterExpandoAttribute (Control control, string controlId, string attributeName, string attributeValue, bool encode) {
803 Page page = control.Page;
804 ScriptManager sm = GetCurrent (page);
805 if (sm.IsInAsyncPostBack)
806 sm.RegisterExpandoAttribute (controlId, attributeName, attributeValue, encode);
808 page.ClientScript.RegisterExpandoAttribute (controlId, attributeName, attributeValue, encode);
811 private void RegisterExpandoAttribute (string controlId, string attributeName, string attributeValue, bool encode) {
812 // seems MS do nothing.
815 public static void RegisterHiddenField (Control control, string hiddenFieldName, string hiddenFieldInitialValue) {
816 RegisterHiddenField (control.Page, hiddenFieldName, hiddenFieldInitialValue);
819 public static void RegisterHiddenField (Page page, string hiddenFieldName, string hiddenFieldInitialValue) {
820 ScriptManager sm = GetCurrent (page);
821 if (sm.IsInAsyncPostBack)
822 sm.RegisterHiddenField (hiddenFieldName, hiddenFieldInitialValue);
824 page.ClientScript.RegisterHiddenField (hiddenFieldName, hiddenFieldInitialValue);
827 void RegisterHiddenField (string hiddenFieldName, string hiddenFieldInitialValue) {
828 if (_hiddenFields == null)
829 _hiddenFields = new Hashtable ();
831 if (!_hiddenFields.ContainsKey (hiddenFieldName))
832 _hiddenFields.Add (hiddenFieldName, hiddenFieldInitialValue);
835 public static void RegisterOnSubmitStatement (Control control, Type type, string key, string script) {
836 RegisterOnSubmitStatement (control.Page, type, key, script);
839 public static void RegisterOnSubmitStatement (Page page, Type type, string key, string script) {
840 ScriptManager sm = GetCurrent (page);
841 if (sm.IsInAsyncPostBack)
842 RegisterScript (ref sm._onSubmitStatements, type, key, script, ScriptEntryType.OnSubmit);
844 page.ClientScript.RegisterOnSubmitStatement (type, key, script);
847 public void RegisterPostBackControl (Control control) {
851 if (_postBackControls == null)
852 _postBackControls = new List<Control> ();
854 if (_postBackControls.Contains (control))
857 _postBackControls.Add (control);
860 internal void RegisterUpdatePanel (UpdatePanel updatePanel) {
861 if (_updatePanels == null)
862 _updatePanels = new List<UpdatePanel> ();
864 if (_updatePanels.Contains (updatePanel))
867 _updatePanels.Add (updatePanel);
870 public void RegisterScriptDescriptors (IExtenderControl extenderControl) {
871 if (extenderControl == null)
874 if (_registeredExtenderControls == null || !_registeredExtenderControls.ContainsKey (extenderControl))
877 Control targetControl = _registeredExtenderControls [extenderControl];
878 RegisterScriptDescriptors (extenderControl.GetScriptDescriptors (targetControl));
881 public void RegisterScriptDescriptors (IScriptControl scriptControl) {
882 if (scriptControl == null)
885 if (_registeredScriptControls == null || !_registeredScriptControls.Contains (scriptControl))
888 RegisterScriptDescriptors (scriptControl.GetScriptDescriptors ());
891 void RegisterScriptDescriptors (IEnumerable<ScriptDescriptor> scriptDescriptors) {
892 if (scriptDescriptors == null)
894 if (IsInAsyncPostBack && !IsInPartialRendering)
897 StringBuilder sb = new StringBuilder ();
898 foreach (ScriptDescriptor scriptDescriptor in scriptDescriptors) {
900 scriptDescriptor.FormID = Page.Form.ClientID;
901 sb.AppendLine ("Sys.Application.getInstance($get(\"" + Page.Form.ClientID + "\")).add_init(function() {");
904 sb.AppendLine ("Sys.Application.add_init(function() {");
905 sb.AppendLine (scriptDescriptor.GetScript ());
906 sb.AppendLine ("});");
908 string script = sb.ToString ();
909 RegisterStartupScript (this, typeof (ExtenderControl), script, script, true);
912 public static void RegisterStartupScript (Control control, Type type, string key, string script, bool addScriptTags) {
913 RegisterStartupScript (control.Page, type, key, script, addScriptTags);
916 public static void RegisterStartupScript (Page page, Type type, string key, string script, bool addScriptTags) {
917 ScriptManager sm = GetCurrent (page);
918 if (sm.IsInAsyncPostBack)
919 RegisterScript (ref sm._startupScriptBlocks, type, key, script, addScriptTags ? ScriptEntryType.ScriptContentNoTags : ScriptEntryType.ScriptContentWithTags);
921 page.ClientScript.RegisterStartupScript (type, key, script, addScriptTags);
924 public void RegisterScriptControl<TScriptControl> (TScriptControl scriptControl) where TScriptControl : Control, IScriptControl {
925 if (scriptControl == null)
926 throw new ArgumentNullException ("scriptControl");
928 if (_registeredScriptControls == null)
929 _registeredScriptControls = new List<IScriptControl> ();
931 if (!_registeredScriptControls.Contains (scriptControl))
932 _registeredScriptControls.Add (scriptControl);
935 public void RegisterExtenderControl<TExtenderControl> (TExtenderControl extenderControl, Control targetControl) where TExtenderControl : Control, IExtenderControl {
936 if (extenderControl == null)
937 throw new ArgumentNullException ("extenderControl");
938 if (targetControl == null)
939 throw new ArgumentNullException ("targetControl");
941 if (_registeredExtenderControls == null)
942 _registeredExtenderControls = new Dictionary<IExtenderControl, Control> ();
944 if (!_registeredExtenderControls.ContainsKey (extenderControl))
945 _registeredExtenderControls.Add (extenderControl, targetControl);
948 static void RegisterScript (ref ScriptEntry scriptList, Type type, string key, string script, ScriptEntryType scriptEntryType) {
949 ScriptEntry last = null;
950 ScriptEntry entry = scriptList;
952 while (entry != null) {
953 if (entry.Type == type && entry.Key == key)
959 entry = new ScriptEntry (type, key, script, scriptEntryType);
967 protected override void Render (HtmlTextWriter writer) {
968 // MSDN: This method is used by control developers to extend the ScriptManager control.
969 // Notes to Inheritors:
970 // When overriding this method, call the base Render(HtmlTextWriter) method
971 // so that PageRequestManager is rendered on the page.
972 if (SupportsPartialRendering) {
973 writer.WriteLine ("<script type=\"text/javascript\">");
974 writer.WriteLine ("//<![CDATA[");
975 writer.WriteLine ("Sys.WebForms.PageRequestManager._initialize('{0}', document.getElementById('{1}'));", UniqueID, Page.Form.ClientID);
977 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);
979 writer.WriteLine ("Sys.WebForms.PageRequestManager.getInstance()._updateControls([{0}], [{1}], [{2}], {3});", FormatUpdatePanelIDs (_updatePanels, true), FormatListIDs (_asyncPostBackControls, true), FormatListIDs (_postBackControls, true), AsyncPostBackTimeout);
980 writer.WriteLine ("//]]");
981 writer.WriteLine ("</script>");
983 base.Render (writer);
986 static string FormatUpdatePanelIDs (List<UpdatePanel> list, bool useSingleQuote) {
987 if (list == null || list.Count == 0)
990 StringBuilder sb = new StringBuilder ();
991 for (int i = 0; i < list.Count; i++) {
992 sb.AppendFormat ("{0}{1}{2}{0},", useSingleQuote ? "'" : String.Empty, list [i].ChildrenAsTriggers ? "t" : "f", list [i].UniqueID);
997 return sb.ToString ();
1000 static string FormatListIDs<T> (List<T> list, bool useSingleQuote) where T : Control {
1001 if (list == null || list.Count == 0)
1004 StringBuilder sb = new StringBuilder ();
1005 for (int i = 0; i < list.Count; i++) {
1006 sb.AppendFormat ("{0}{1}{0},", useSingleQuote ? "'" : String.Empty, list [i].UniqueID);
1011 return sb.ToString ();
1014 public void SetFocus (Control control) {
1015 if (control == null)
1016 throw new ArgumentNullException ("control");
1018 if (IsInAsyncPostBack) {
1019 EnsureFocusClientScript ();
1020 _controlIDToFocus = control.ClientID;
1023 Page.SetFocus (control);
1026 public void SetFocus (string clientID) {
1027 if (String.IsNullOrEmpty (clientID))
1028 throw new ArgumentNullException ("control");
1030 if (IsInAsyncPostBack) {
1031 EnsureFocusClientScript ();
1032 _controlIDToFocus = clientID;
1035 Page.SetFocus (clientID);
1038 void EnsureFocusClientScript () {
1040 RegisterClientScriptResource (this, typeof (ClientScriptManager), "Focus.js");
1044 #region IPostBackDataHandler Members
1046 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection) {
1047 return LoadPostData (postDataKey, postCollection);
1050 void IPostBackDataHandler.RaisePostDataChangedEvent () {
1051 RaisePostDataChangedEvent ();
1056 internal void WriteCallbackException (TextWriter output, Exception ex, bool writeMessage) {
1058 if (ex is HttpUnhandledException)
1059 ex = ex.InnerException;
1061 HttpException httpEx = ex as HttpException;
1062 string message = AsyncPostBackErrorMessage;
1063 if (String.IsNullOrEmpty (message) && writeMessage)
1064 message = ex.Message;
1065 WriteCallbackOutput (output, error, httpEx == null ? "500" : httpEx.GetHttpCode ().ToString (), message);
1068 static internal void WriteCallbackRedirect (TextWriter output, string redirectUrl) {
1069 WriteCallbackOutput (output, pageRedirect, null, redirectUrl);
1072 internal void WriteCallbackPanel (TextWriter output, UpdatePanel panel, StringBuilder panelOutput) {
1073 if (_panelsToRefresh == null)
1074 _panelsToRefresh = new List<UpdatePanel> ();
1075 _panelsToRefresh.Add (panel);
1077 WriteCallbackOutput (output, updatePanel, panel.ClientID, panelOutput);
1080 internal void RegisterChildUpdatePanel (UpdatePanel updatePanel) {
1081 if (_childUpdatePanels == null)
1082 _childUpdatePanels = new List<UpdatePanel> ();
1083 _childUpdatePanels.Add (updatePanel);
1086 static void WriteCallbackOutput (TextWriter output, string type, string name, object value) {
1087 string str = value as string;
1088 StringBuilder sb = value as StringBuilder;
1091 length = str.Length;
1092 else if (sb != null)
1095 //output.Write ("{0}|{1}|{2}|{3}|", value == null ? 0 : value.Length, type, name, value);
1096 output.Write (length);
1098 output.Write (type);
1100 output.Write (name);
1102 for (int i = 0; i < length; i++)
1104 output.Write (str [i]);
1106 output.Write (sb [i]);
1110 void RenderPageCallback (HtmlTextWriter output, Control container) {
1111 Page page = (Page) container;
1113 page.Form.SetRenderMethodDelegate (RenderFormCallback);
1114 HtmlTextParser parser = new HtmlTextParser (output);
1115 page.Form.RenderControl (parser);
1117 WriteCallbackOutput (output, asyncPostBackControlIDs, null, FormatListIDs (_asyncPostBackControls, false));
1118 WriteCallbackOutput (output, postBackControlIDs, null, FormatListIDs (_postBackControls, false));
1119 WriteCallbackOutput (output, updatePanelIDs, null, FormatUpdatePanelIDs (_updatePanels, false));
1120 WriteCallbackOutput (output, childUpdatePanelIDs, null, FormatListIDs (_childUpdatePanels, false));
1121 WriteCallbackOutput (output, panelsToRefreshIDs, null, FormatListIDs (_panelsToRefresh, false));
1122 WriteCallbackOutput (output, asyncPostBackTimeout, null, AsyncPostBackTimeout.ToString ());
1124 WriteCallbackOutput (output, pageTitle, null, Page.Title);
1126 if (_dataItems != null)
1127 foreach (Control control in _dataItems.Keys) {
1128 DataItemEntry entry = _dataItems [control];
1129 WriteCallbackOutput (output, entry.IsJsonSerialized ? dataItemJson : dataItem, control.ClientID, entry.DataItem);
1132 WriteArrayDeclarations (output);
1133 WriteScriptBlocks (output, _clientScriptBlocks);
1134 WriteScriptBlocks (output, _scriptIncludes);
1135 WriteScriptBlocks (output, _startupScriptBlocks);
1136 WriteScriptBlocks (output, _onSubmitStatements);
1137 WriteHiddenFields (output);
1139 if (!String.IsNullOrEmpty (_controlIDToFocus))
1140 WriteCallbackOutput (output, focus, null, _controlIDToFocus);
1142 if (_disposeScripts != null)
1143 for (int i = 0; i < _disposeScripts.Count; i++) {
1144 DisposeScriptEntry entry = _disposeScripts [i];
1145 if ((_panelsToRefresh != null && _panelsToRefresh.IndexOf (entry.UpdatePanel) >= 0) || (_childUpdatePanels != null && _childUpdatePanels.IndexOf (entry.UpdatePanel) >= 0))
1146 WriteCallbackOutput (output, scriptDispose, entry.UpdatePanel.ClientID, entry.Script);
1150 void WriteArrayDeclarations (HtmlTextWriter writer) {
1151 if (_arrayDeclarations != null) {
1152 for (int i = 0; i < _arrayDeclarations.Count; i++) {
1153 ArrayDeclaration array = _arrayDeclarations [i];
1154 WriteCallbackOutput (writer, arrayDeclaration, array.ArrayName, array.ArrayValue);
1159 void WriteScriptBlocks (HtmlTextWriter output, ScriptEntry scriptList) {
1160 while (scriptList != null) {
1161 switch (scriptList.ScriptEntryType) {
1162 case ScriptEntryType.ScriptContentNoTags:
1163 WriteCallbackOutput (output, scriptBlock, scriptContentNoTags, scriptList.Script);
1165 case ScriptEntryType.ScriptContentWithTags:
1166 string script = SerializeScriptBlock (scriptList);
1167 WriteCallbackOutput (output, scriptBlock, scriptContentWithTags, script);
1169 case ScriptEntryType.ScriptPath:
1170 WriteCallbackOutput (output, scriptBlock, scriptPath, scriptList.Script);
1172 case ScriptEntryType.OnSubmit:
1173 WriteCallbackOutput (output, onSubmit, null, scriptList.Script);
1176 scriptList = scriptList.Next;
1180 void WriteHiddenFields (HtmlTextWriter output) {
1181 if (_hiddenFields == null)
1183 foreach (string key in _hiddenFields.Keys) {
1184 string value = _hiddenFields [key] as string;
1185 WriteCallbackOutput (output, hiddenField, key, value);
1189 static string SerializeScriptBlock (ScriptEntry scriptList) {
1191 XmlTextReader reader = new XmlTextReader (new StringReader (scriptList.Script));
1192 while (reader.Read ()) {
1193 switch (reader.NodeType) {
1194 case XmlNodeType.Element:
1195 if (String.Compare ("script", reader.Name, StringComparison.OrdinalIgnoreCase) == 0) {
1196 Dictionary<string, string> dic = new Dictionary<string, string> ();
1197 while (reader.MoveToNextAttribute ()) {
1198 dic.Add (reader.Name, reader.Value);
1200 reader.MoveToContent ();
1201 dic.Add ("text", reader.ReadInnerXml ());
1202 return JavaScriptSerializer.DefaultSerializer.Serialize (dic);
1212 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));
1215 void RenderFormCallback (HtmlTextWriter output, Control container) {
1216 output = ((HtmlTextParser) output).ResponseOutput;
1217 HtmlForm form = (HtmlForm) container;
1218 HtmlTextWriter writer = new HtmlDropWriter (output);
1219 if (form.HasControls ()) {
1220 for (int i = 0; i < form.Controls.Count; i++) {
1221 form.Controls [i].RenderControl (writer);
1226 internal class AlternativeHtmlTextWriter : HtmlTextWriter
1228 readonly HtmlTextWriter _responseOutput;
1230 public HtmlTextWriter ResponseOutput {
1231 get { return _responseOutput; }
1234 public AlternativeHtmlTextWriter (TextWriter writer, HtmlTextWriter responseOutput)
1236 _responseOutput = responseOutput;
1240 sealed class HtmlTextParser : AlternativeHtmlTextWriter
1242 public HtmlTextParser (HtmlTextWriter responseOutput)
1243 : base (new TextParser (responseOutput), responseOutput) {
1247 sealed class TextParser : TextWriter
1250 char _charState = (char) 255;
1251 const char nullCharState = (char) 255;
1252 StringBuilder _sb = new StringBuilder ();
1253 Dictionary<string, string> _currentField;
1254 string _currentAttribute;
1255 readonly HtmlTextWriter _responseOutput;
1257 public override Encoding Encoding {
1258 get { return Encoding.UTF8; }
1261 public TextParser (HtmlTextWriter responseOutput) {
1262 _responseOutput = responseOutput;
1265 public override void Write (char value) {
1268 ParseBeginTag (value);
1271 ParseAttributeName (value);
1274 ParseAttributeValue (value);
1279 private void ParseAttributeValue (char value) {
1285 _currentField.Add (_currentAttribute, _sb.ToString ());
1288 ProbeWriteOutput ();
1296 private void ParseAttributeName (char value) {
1305 _currentAttribute = _sb.ToString ();
1315 void ParseBeginTag (char value) {
1316 switch (_charState) {
1354 _currentField = new Dictionary<string, string> ();
1362 private void ResetState () {
1363 _charState = nullCharState;
1368 private void ProbeWriteOutput () {
1369 if (!_currentField.ContainsKey ("name"))
1371 if (!_currentField.ContainsKey ("value"))
1374 string value = _currentField ["value"];
1375 if (String.IsNullOrEmpty (value))
1378 ScriptManager.WriteCallbackOutput (_responseOutput, hiddenField, _currentField ["name"], HttpUtility.HtmlDecode (value));
1382 sealed class HtmlDropWriter : AlternativeHtmlTextWriter
1384 public HtmlDropWriter (HtmlTextWriter responseOutput)
1385 : base (new DropWriter (), responseOutput) {
1389 sealed class DropWriter : TextWriter
1391 public override Encoding Encoding {
1392 get { return Encoding.UTF8; }
1396 sealed class ScriptEntry
1398 readonly public Type Type;
1399 readonly public string Key;
1400 readonly public string Script;
1401 readonly public ScriptEntryType ScriptEntryType;
1402 public ScriptEntry Next;
1404 public ScriptEntry (Type type, string key, string script, ScriptEntryType scriptEntryType) {
1408 ScriptEntryType = scriptEntryType;
1412 enum ScriptEntryType
1414 ScriptContentNoTags,
1415 ScriptContentWithTags,
1420 sealed class ArrayDeclaration
1422 readonly public string ArrayName;
1423 readonly public string ArrayValue;
1425 public ArrayDeclaration (string arrayName, string arrayValue) {
1426 ArrayName = arrayName;
1427 ArrayValue = arrayValue;
1431 sealed class CultureInfoSerializer : JavaScriptSerializer.LazyDictionary
1433 readonly CultureInfo _ci;
1434 public CultureInfoSerializer (CultureInfo ci) {
1436 throw new ArgumentNullException ("ci");
1439 protected override IEnumerator<KeyValuePair<string, object>> GetEnumerator () {
1440 yield return new KeyValuePair<string, object> ("name", _ci.Name);
1441 yield return new KeyValuePair<string, object> ("numberFormat", _ci.NumberFormat);
1442 yield return new KeyValuePair<string, object> ("dateTimeFormat", _ci.DateTimeFormat);
1446 sealed class ScriptReferenceEntry
1448 readonly Control _control;
1449 readonly ScriptReference _scriptReference;
1450 readonly bool _loadBeforeUI;
1452 public Control Control { get { return _control; } }
1453 public ScriptReference ScriptReference { get { return _scriptReference; } }
1454 public bool LoadScriptsBeforeUI { get { return _loadBeforeUI; } }
1456 public ScriptReferenceEntry (Control control, ScriptReference scriptReference, bool loadBeforeUI) {
1458 _scriptReference = scriptReference;
1459 _loadBeforeUI = loadBeforeUI;
1463 sealed class DataItemEntry
1465 readonly string _dataItem;
1466 readonly bool _isJsonSerialized;
1468 public string DataItem { get { return _dataItem; } }
1469 public bool IsJsonSerialized { get { return _isJsonSerialized; } }
1471 public DataItemEntry (string dataItem, bool isJsonSerialized) {
1472 _dataItem = dataItem;
1473 _isJsonSerialized = isJsonSerialized;
1477 sealed class DisposeScriptEntry
1479 readonly UpdatePanel _updatePanel;
1480 readonly string _script;
1482 public UpdatePanel UpdatePanel { get { return _updatePanel; } }
1483 public string Script { get { return _script; } }
1485 public DisposeScriptEntry (UpdatePanel updatePanel, string script) {
1486 _updatePanel = updatePanel;