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;
44 namespace System.Web.UI
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
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";
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;
87 [Category ("Behavior")]
88 public bool AllowCustomErrorsRedirect {
90 throw new NotImplementedException ();
93 throw new NotImplementedException ();
97 [Category ("Behavior")]
99 public string AsyncPostBackErrorMessage {
101 throw new NotImplementedException ();
104 throw new NotImplementedException ();
109 public string AsyncPostBackSourceElementID {
111 if(_asyncPostBackSourceElementID==null)
113 return _asyncPostBackSourceElementID;
118 [Category ("Behavior")]
119 public int AsyncPostBackTimeout {
121 return _asyncPostBackTimeout;
124 _asyncPostBackTimeout = value;
128 [Category ("Behavior")]
129 [MergableProperty (false)]
131 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
132 [PersistenceMode (PersistenceMode.InnerProperty)]
133 public AuthenticationServiceManager AuthenticationService {
135 throw new NotImplementedException ();
139 [Category ("Behavior")]
140 [DefaultValue (false)]
141 public bool EnablePageMethods {
143 throw new NotImplementedException ();
146 throw new NotImplementedException ();
150 [DefaultValue (true)]
151 [Category ("Behavior")]
152 public bool EnablePartialRendering {
154 throw new NotImplementedException ();
157 throw new NotImplementedException ();
161 [DefaultValue (false)]
162 [Category ("Behavior")]
163 public bool EnableScriptGlobalization {
165 throw new NotImplementedException ();
168 throw new NotImplementedException ();
172 [Category ("Behavior")]
173 [DefaultValue (false)]
174 public bool EnableScriptLocalization {
176 throw new NotImplementedException ();
179 throw new NotImplementedException ();
184 public bool IsDebuggingEnabled {
186 DeploymentSection deployment = (DeploymentSection) WebConfigurationManager.GetSection ("system.web/deployment");
187 if (deployment.Retail)
190 CompilationSection compilation = (CompilationSection) WebConfigurationManager.GetSection ("system.web/compilation");
191 if (!compilation.Debug && (ScriptMode == ScriptMode.Auto || ScriptMode == ScriptMode.Inherit))
194 if (ScriptMode == ScriptMode.Release)
202 public bool IsInAsyncPostBack {
204 return _isInAsyncPostBack;
208 [Category ("Behavior")]
209 [DefaultValue (true)]
210 public bool LoadScriptsBeforeUI {
212 throw new NotImplementedException ();
215 throw new NotImplementedException ();
219 [PersistenceMode (PersistenceMode.InnerProperty)]
221 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
222 [Category ("Behavior")]
223 [MergableProperty (false)]
224 public ProfileServiceManager ProfileService {
226 throw new NotImplementedException ();
230 [Category ("Behavior")]
231 public ScriptMode ScriptMode {
236 if (value == ScriptMode.Inherit)
237 value = ScriptMode.Auto;
243 [Category ("Behavior")]
244 public string ScriptPath {
246 throw new NotImplementedException ();
249 throw new NotImplementedException ();
253 [PersistenceMode (PersistenceMode.InnerProperty)]
255 [Category ("Behavior")]
256 [MergableProperty (false)]
257 public ScriptReferenceCollection Scripts {
259 if (_scripts == null)
260 _scripts = new ScriptReferenceCollection ();
266 [PersistenceMode (PersistenceMode.InnerProperty)]
268 [MergableProperty (false)]
269 [Category ("Behavior")]
270 public ServiceReferenceCollection Services {
272 throw new NotImplementedException ();
276 [DefaultValue (true)]
278 public bool SupportsPartialRendering {
280 throw new NotImplementedException ();
283 throw new NotImplementedException ();
287 [EditorBrowsable (EditorBrowsableState.Never)]
289 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
290 public override bool Visible {
295 throw new NotImplementedException ();
299 [Category ("Action")]
300 public event EventHandler<AsyncPostBackErrorEventArgs> AsyncPostBackError;
302 [Category ("Action")]
303 public event EventHandler<ScriptReferenceEventArgs> ResolveScriptReference;
305 public static ScriptManager GetCurrent (Page page)
307 HttpContext ctx = HttpContext.Current;
311 return (ScriptManager) ctx.Items [page];
314 static void SetCurrent (Page page, ScriptManager instance) {
315 HttpContext ctx = HttpContext.Current;
316 ctx.Items [page] = instance;
319 protected virtual bool LoadPostData (string postDataKey, NameValueCollection postCollection)
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)
329 _asyncPostBackSourceElementID = args[1];
334 protected internal virtual void OnAsyncPostBackError (AsyncPostBackErrorEventArgs e)
336 if (AsyncPostBackError != null)
337 AsyncPostBackError (this, e);
340 protected override void OnInit (EventArgs e)
344 if (GetCurrent (Page) != null)
345 throw new InvalidOperationException ("Only one instance of a ScriptManager can be added to the page.");
347 SetCurrent (Page, this);
350 protected override void OnPreRender (EventArgs e)
352 base.OnPreRender (e);
354 if (IsInAsyncPostBack) {
355 Page.SetRenderMethodDelegate (RenderPageCallback);
359 foreach (ScriptReference script in GetScriptReferences ()) {
360 OnResolveScriptReference (new ScriptReferenceEventArgs (script));
361 RegisterScriptReference (script);
364 // Register startup script
365 RegisterStartupScript (this, typeof (ScriptManager), "Sys.Application.initialize();", "Sys.Application.initialize();", true);
368 IEnumerable GetScriptReferences () {
369 ScriptReference script;
371 script = new ScriptReference ("MicrosoftAjax.js", String.Empty);
372 script.NotifyScriptLoaded = false;
375 script = new ScriptReference ("MicrosoftAjaxWebForms.js", String.Empty);
376 script.NotifyScriptLoaded = false;
379 if (_scripts != null && _scripts.Count > 0) {
380 for (int i = 0; i < _scripts.Count; i++) {
381 yield return _scripts [i];
386 protected virtual void OnResolveScriptReference (ScriptReferenceEventArgs e)
388 if (ResolveScriptReference != null)
389 ResolveScriptReference (this, e);
392 protected virtual void RaisePostDataChangedEvent ()
394 throw new NotImplementedException ();
397 public static void RegisterArrayDeclaration (Control control, string arrayName, string arrayValue)
399 throw new NotImplementedException ();
402 public static void RegisterArrayDeclaration (Page page, string arrayName, string arrayValue)
404 throw new NotImplementedException ();
407 public void RegisterAsyncPostBackControl (Control control)
412 if (_asyncPostBackControls == null)
413 _asyncPostBackControls = new List<Control> ();
415 if (_asyncPostBackControls.Contains (control))
418 _asyncPostBackControls.Add (control);
421 public static void RegisterClientScriptBlock (Control control, Type type, string key, string script, bool addScriptTags)
423 throw new NotImplementedException ();
426 public static void RegisterClientScriptBlock (Page page, Type type, string key, string script, bool addScriptTags)
428 throw new NotImplementedException ();
431 public static void RegisterClientScriptInclude (Control control, Type type, string key, string url)
433 RegisterClientScriptInclude (control.Page, type, key, url);
436 public static void RegisterClientScriptInclude (Page page, Type type, string key, string url)
438 page.ClientScript.RegisterClientScriptInclude (type, key, url);
441 public static void RegisterClientScriptResource (Control control, Type type, string resourceName)
443 RegisterClientScriptResource (control.Page, type, resourceName);
446 public static void RegisterClientScriptResource (Page page, Type type, string resourceName)
448 page.ClientScript.RegisterClientScriptResource (type, resourceName);
451 void RegisterScriptReference (ScriptReference script) {
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.
457 if (!String.IsNullOrEmpty (script.Path)) {
460 else if (!String.IsNullOrEmpty (script.Name)) {
462 if (String.IsNullOrEmpty (script.Assembly))
463 assembly = typeof (ScriptManager).Assembly;
465 assembly = Assembly.Load (script.Assembly);
466 url = ScriptResourceHandler.GetResourceUrl (assembly, script.Name, script.NotifyScriptLoaded);
469 throw new InvalidOperationException ("Name and Path cannot both be empty.");
472 RegisterClientScriptInclude (this, typeof (ScriptManager), url, url);
475 public void RegisterDataItem (Control control, string dataItem)
477 throw new NotImplementedException ();
480 public void RegisterDataItem (Control control, string dataItem, bool isJsonSerialized)
482 throw new NotImplementedException ();
485 public void RegisterDispose (Control control, string disposeScript)
487 throw new NotImplementedException ();
490 public static void RegisterExpandoAttribute (Control control, string controlId, string attributeName, string attributeValue, bool encode)
492 throw new NotImplementedException ();
495 public static void RegisterHiddenField (Control control, string hiddenFieldName, string hiddenFieldInitialValue)
497 throw new NotImplementedException ();
500 public static void RegisterHiddenField (Page page, string hiddenFieldName, string hiddenFieldInitialValue)
502 throw new NotImplementedException ();
505 public static void RegisterOnSubmitStatement (Control control, Type type, string key, string script)
507 throw new NotImplementedException ();
510 public static void RegisterOnSubmitStatement (Page page, Type type, string key, string script)
512 throw new NotImplementedException ();
515 public void RegisterPostBackControl (Control control)
520 if (_postBackControls == null)
521 _postBackControls = new List<Control> ();
523 if (_postBackControls.Contains (control))
526 _postBackControls.Add (control);
529 internal void RegisterUpdatePanel (UpdatePanel updatePanel) {
530 if (_updatePanels == null)
531 _updatePanels = new List<UpdatePanel> ();
533 if (_updatePanels.Contains (updatePanel))
536 _updatePanels.Add (updatePanel);
539 public void RegisterScriptDescriptors (IExtenderControl extenderControl)
541 throw new NotImplementedException ();
544 public void RegisterScriptDescriptors (IScriptControl scriptControl)
546 throw new NotImplementedException ();
549 public static void RegisterStartupScript (Control control, Type type, string key, string script, bool addScriptTags)
551 RegisterStartupScript (control.Page, type, key, script, addScriptTags);
554 public static void RegisterStartupScript (Page page, Type type, string key, string script, bool addScriptTags)
556 page.ClientScript.RegisterStartupScript (type, key, script, addScriptTags);
559 protected override void Render (HtmlTextWriter writer)
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);
574 static string FormatUpdatePanelIDs (List<UpdatePanel> list, bool useSingleQuote) {
575 if (list == null || list.Count == 0)
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);
585 return sb.ToString ();
588 static string FormatListIDs (List<Control> list, bool useSingleQuote)
590 if (list == null || list.Count == 0)
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);
600 return sb.ToString ();
603 public void SetFocus (Control control)
605 throw new NotImplementedException ();
608 public void SetFocus (string clientID)
610 throw new NotImplementedException ();
613 #region IPostBackDataHandler Members
615 bool IPostBackDataHandler.LoadPostData (string postDataKey, NameValueCollection postCollection)
617 return LoadPostData (postDataKey, postCollection);
620 void IPostBackDataHandler.RaisePostDataChangedEvent ()
622 RaisePostDataChangedEvent ();
627 static internal void WriteCallbackRedirect (TextWriter output, string redirectUrl) {
628 WriteCallbackOutput (output, pageRedirect, null, redirectUrl);
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);
635 void RenderPageCallback (HtmlTextWriter output, Control container) {
636 Page page = (Page) container;
638 page.Form.SetRenderMethodDelegate (RenderFormCallback);
639 HtmlTextParser parser = new HtmlTextParser (output);
640 page.Form.RenderControl (parser);
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);
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];
658 panel.RenderChildrenInternal (w);
660 if (panel.RequiresUpdate) {
661 string panelOutput = sb.ToString ();
662 WriteCallbackOutput (output, updatePanel, panel.ClientID, panelOutput);
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);
678 sealed class HtmlTextParser : HtmlTextWriter
680 readonly HtmlTextWriter _responseOutput;
682 public HtmlTextWriter ResponseOutput {
683 get { return _responseOutput; }
686 public HtmlTextParser (HtmlTextWriter responseOutput)
687 : base (new TextParser ()) {
688 _responseOutput = responseOutput;
691 public void WriteOutput (HtmlTextWriter output) {
692 ((TextParser) InnerWriter).WriteOutput (output);
696 sealed class TextParser : TextWriter
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;
706 public override Encoding Encoding {
707 get { return Encoding.UTF8; }
710 public override void Write (char value) {
713 ParseBeginTag (value);
716 ParseAttributeName (value);
719 ParseAttributeValue (value);
724 private void ParseAttributeValue (char value) {
730 _currentField [_currentAttribute] = _sb.ToString ();
740 private void ParseAttributeName (char value) {
749 _currentAttribute = _sb.ToString ();
759 void ParseBeginTag (char value) {
760 switch (_charState) {
798 _currentField = new Hashtable ();
799 if (_hiddenFields == null)
800 _hiddenFields = new List<Hashtable> ();
801 _hiddenFields.Add (_currentField);
809 private void ResetState () {
810 _charState = nullCharState;
815 public void WriteOutput (HtmlTextWriter output) {
816 if (_hiddenFields == null)
819 for (int i = 0; i < _hiddenFields.Count; i++) {
820 Hashtable field = _hiddenFields [i];
822 string value = (string) field ["value"];
823 if (String.IsNullOrEmpty (value))
826 ScriptManager.WriteCallbackOutput (output, ScriptManager.hiddenField, (string) field ["name"], value);
831 sealed class DropWriter : TextWriter
833 public override Encoding Encoding {
834 get { return Encoding.UTF8; }