ScriptRegistrationManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / xsp / System / Web / Extensions / ui / ScriptRegistrationManager.cs / 1 / ScriptRegistrationManager.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

 
namespace System.Web.UI { 
    using System;
    using System.Collections.Generic; 
    using System.Collections.Specialized;
    using System.Diagnostics;
    using System.Globalization;
    using System.Text; 
    using System.Text.RegularExpressions;
    using System.Web.UI; 
    using System.Web.Resources; 
    using System.Web.Script.Serialization;
 
    internal sealed class ScriptRegistrationManager {
        private static Regex ScriptTagRegex = new Regex(
            @"\w[-\w:]*)" +          // Attribute name
                @"(" + 
                    @"\s*=\s*""(?[^""]*)""|" + // ="bar" attribute value 
                    @"\s*=\s*'(?[^']*)'" +     // ='bar' attribute value
                @")" + 
            @")*" +
            @"\s*(?/)?>",
            RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
 
        private ScriptManager _scriptManager;
        private List _scriptDisposes; 
        private List _scriptArrays; 
        private List _clientScriptBlocks;
        private List _startupScriptBlocks; 
        private List _hiddenFields;
        private List _expandos;
        private List _submitStatements;
 
        public ScriptRegistrationManager(ScriptManager scriptManager) {
            _scriptManager = scriptManager; 
        } 

        public List ScriptArrays { 
            get {
                if (_scriptArrays == null) {
                    _scriptArrays = new List();
                } 
                return _scriptArrays;
            } 
        } 

        public List ScriptBlocks { 
            get {
                if (_clientScriptBlocks == null) {
                    _clientScriptBlocks = new List();
                } 
                return _clientScriptBlocks;
            } 
        } 

        public List ScriptDisposes { 
            get {
                if (_scriptDisposes == null) {
                    _scriptDisposes = new List();
                } 
                return _scriptDisposes;
            } 
        } 

        public List ScriptExpandos { 
            get {
                if (_expandos == null) {
                    _expandos = new List();
                } 
                return _expandos;
            } 
        } 

        public List ScriptHiddenFields { 
            get {
                if (_hiddenFields == null) {
                    _hiddenFields = new List();
                } 
                return _hiddenFields;
            } 
        } 

        public List ScriptStartupBlocks { 
            get {
                if (_startupScriptBlocks == null) {
                    _startupScriptBlocks = new List();
                } 
                return _startupScriptBlocks;
            } 
        } 

        public List ScriptSubmitStatements { 
            get {
                if (_submitStatements == null) {
                    _submitStatements = new List();
                } 
                return _submitStatements;
            } 
        } 

        private static void CheckScriptTagTweenSpace(RegisteredScript entry, string text, int start, int length) { 
            // Check the range between the matches to make sure there is no extraneous content
            string tweenSpace = text.Substring(start, length);
            if (tweenSpace.Trim().Length != 0) {
                throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptRegistrationManager_InvalidChars, entry.Type.FullName, entry.Key, tweenSpace)); 
            }
        } 
 
        private bool IsControlRegistrationActive(
            List updatingUpdatePanels, 
            Control child,
            bool pageAlwaysActive) {

            // Determines if a registered resource, like a client script block, should be included in the partial 
            // update response. It should be included if the owning control is a child of an updating update panel
            // or if the owning control is the Page and this is a type of resource where Page is allowed as an owner. 
            // When page is the owner, it means always include the resource regardless of which update panels are 
            // updating. Expandos and dispose scripts do not support Page as the owner.
 
            // is this a resource that allows Page as the owner, and is the owner the Page?
            if (pageAlwaysActive) {
                Page childAsPage = child as Page;
                if (childAsPage == _scriptManager.Page) { 
                    // owner is page so the registration is automatically active
                    return true; 
                } 
            }
 
            // registration is active if owner is a child of any updating update panels
            if (updatingUpdatePanels != null && updatingUpdatePanels.Count > 0) {
                // navigate up the parent controls and see if any are an updating update panel.
                while (child != null) { 
                    if (child is UpdatePanel) {
                        // enumerate with for loop instead of foreach so we don't recreate an enumerator. 
                        // enumerate instead of using Contains so we do not have to cast or use a comparer. 
                        for (int i = 0; i < updatingUpdatePanels.Count; i++) {
                            if (child == updatingUpdatePanels[i]) { 
                                return true;
                            }
                        }
                    } 
                    child = child.Parent;
                } 
            } 

            return false; 
        }

        public static void RegisterArrayDeclaration(Control control, string arrayName, string arrayValue) {
            if (control == null) { 
                throw new ArgumentNullException("control");
            } 
            if (control.Page == null) { 
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control");
            } 

            control.Page.ClientScript.RegisterArrayDeclaration(arrayName, arrayValue);

            ScriptManager sm = ScriptManager.GetCurrent(control.Page); 
            if (sm != null) {
                RegisteredArrayDeclaration entry = new RegisteredArrayDeclaration(control, arrayName, arrayValue); 
                sm.ScriptRegistration.ScriptArrays.Add(entry); 
            }
        } 

        public static void RegisterClientScriptBlock(Control control, Type type, string key, string script, bool addScriptTags) {
            if (control == null) {
                throw new ArgumentNullException("control"); 
            }
            if (control.Page == null) { 
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control"); 
            }
 
            control.Page.ClientScript.RegisterClientScriptBlock(type, key, script, addScriptTags);

            ScriptManager sm = ScriptManager.GetCurrent(control.Page);
            if (sm != null) { 
                RegisteredScript entry =
                    new RegisteredScript(RegisteredScriptType.ClientScriptBlock, 
                        control, 
                        type,
                        key, 
                        script,
                        addScriptTags);
                sm.ScriptRegistration.ScriptBlocks.Add(entry);
            } 
        }
 
        public static void RegisterClientScriptInclude(Control control, Type type, string key, string url) { 
            if (control == null) {
                throw new ArgumentNullException("control"); 
            }
            if (control.Page == null) {
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control");
            } 

            control.Page.ClientScript.RegisterClientScriptInclude(type, key, url); 
 
            ScriptManager sm = ScriptManager.GetCurrent(control.Page);
            if (sm != null) { 
                RegisteredScript entry = new RegisteredScript(control, type, key, url);
                sm.ScriptRegistration.ScriptBlocks.Add(entry);
            }
        } 

        public static void RegisterClientScriptResource(Control control, Type type, string resourceName) { 
            if (control == null) { 
                throw new ArgumentNullException("control");
            } 
            if (control.Page == null) {
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control");
            }
 
            ScriptManager sm = ScriptManager.GetCurrent(control.Page);
            if (sm == null) { 
                control.Page.ClientScript.RegisterClientScriptResource(type, resourceName); 
            }
            else { 
                string resourceUrl = sm.GetScriptResourceUrl(resourceName, type.Assembly);
                control.Page.ClientScript.RegisterClientScriptInclude(type, resourceName, resourceUrl);
                RegisteredScript entry = new RegisteredScript(control, type, resourceName, resourceUrl);
                sm.ScriptRegistration.ScriptBlocks.Add(entry); 
            }
        } 
 
        internal void RegisterDispose(Control control, string disposeScript) {
            if (control == null) { 
                throw new ArgumentNullException("control");
            }
            if (control.Page == null) {
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control"); 
            }
            if (disposeScript == null) { 
                throw new ArgumentNullException("disposeScript"); 
            }
 
            // Locate the parent UpdatePanel of the control
            Control parent = control.Parent;
            UpdatePanel parentUpdatePanel = null;
            while (parent != null) { 
                parentUpdatePanel = parent as UpdatePanel;
                if (parentUpdatePanel != null) { 
                    break; 
                }
                parent = parent.Parent; 
            }
            if (parentUpdatePanel != null) {
                // During async posts we build up a list of ScriptDisposes. Later
                // we go through the list and filter out ones that aren't inside 
                // UpdatePanels that are refreshing.
                // DevDiv Bugs 128123: Build the list on non-async postbacks as well, 
                // so that GetRegisteredDisposeScripts returns them. 
                RegisteredDisposeScript entry = new RegisteredDisposeScript(control, disposeScript, parentUpdatePanel);
                ScriptDisposes.Add(entry); 

                if (!_scriptManager.IsInAsyncPostBack) {
                    // During non-async requests we register script immediately to do the
                    // dispose. This is necessary because some controls will register as late 
                    // as Render(), at which point it would be too late to build up a list
                    // for processing later. 
                    JavaScriptSerializer serializer = new JavaScriptSerializer(); 
                    // 256 seems like a nice number so that we don't have to resize the StringBuilder except in very rare cases
                    StringBuilder sb = new StringBuilder(256); 
                    sb.Append("Sys.WebForms.PageRequestManager.getInstance()._registerDisposeScript(");
                    serializer.Serialize(parentUpdatePanel.ClientID, sb);
                    sb.Append(", ");
                    serializer.Serialize(disposeScript, sb); 
                    sb.AppendLine(");");
 
                    // DevDiv Bugs 128123: Register directly with ClientScriptManager so that a RegisteredScript 
                    // entry is not created. Otherwise, calls to RegisterDispose would result in viewable
                    // RegisteredScript entries through GetRegisteredStartupScripts(). 
                    _scriptManager.IPage.ClientScript.RegisterStartupScript(typeof(ScriptRegistrationManager),
                        _scriptManager.CreateUniqueScriptKey(),
                        sb.ToString(),
                        true); 
                }
            } 
        } 

        public static void RegisterExpandoAttribute(Control control, string controlId, string attributeName, string attributeValue, bool encode) { 
            if (control == null) {
                throw new ArgumentNullException("control");
            }
            if (control.Page == null) { 
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control");
            } 
 
            control.Page.ClientScript.RegisterExpandoAttribute(controlId, attributeName, attributeValue, encode);
 
            ScriptManager sm = ScriptManager.GetCurrent(control.Page);
            if (sm != null) {
                RegisteredExpandoAttribute entry =
                    new RegisteredExpandoAttribute(control, 
                        controlId,
                        attributeName, 
                        attributeValue, 
                        encode);
                sm.ScriptRegistration.ScriptExpandos.Add(entry); 
            }
        }

        public static void RegisterHiddenField(Control control, string hiddenFieldName, string hiddenFieldInitialValue) { 
            if (control == null) {
                throw new ArgumentNullException("control"); 
            } 
            if (control.Page == null) {
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control"); 
            }

            control.Page.ClientScript.RegisterHiddenField(hiddenFieldName, hiddenFieldInitialValue);
 
            ScriptManager sm = ScriptManager.GetCurrent(control.Page);
            if (sm != null) { 
                RegisteredHiddenField entry = 
                    new RegisteredHiddenField(control,
                        hiddenFieldName, 
                        hiddenFieldInitialValue);
                sm.ScriptRegistration.ScriptHiddenFields.Add(entry);
            }
        } 

        public static void RegisterOnSubmitStatement(Control control, Type type, string key, string script) { 
            if (control == null) { 
                throw new ArgumentNullException("control");
            } 
            if (control.Page == null) {
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control");
            }
 
            control.Page.ClientScript.RegisterOnSubmitStatement(type, key, script);
 
            ScriptManager sm = ScriptManager.GetCurrent(control.Page); 
            if (sm != null) {
                RegisteredScript entry = 
                    new RegisteredScript(RegisteredScriptType.OnSubmitStatement,
                        control,
                        type,
                        key, 
                        script,
                        false); 
                sm.ScriptRegistration.ScriptSubmitStatements.Add(entry); 
            }
        } 

        public static void RegisterStartupScript(Control control, Type type, string key, string script, bool addScriptTags) {
            if (control == null) {
                throw new ArgumentNullException("control"); 
            }
            if (control.Page == null) { 
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control"); 
            }
 
            control.Page.ClientScript.RegisterStartupScript(type, key, script, addScriptTags);

            ScriptManager sm = ScriptManager.GetCurrent(control.Page);
            if (sm != null) { 
                RegisteredScript entry =
                    new RegisteredScript(RegisteredScriptType.ClientStartupScript, 
                        control, 
                        type,
                        key, 
                        script,
                        addScriptTags);
                sm.ScriptRegistration.ScriptStartupBlocks.Add(entry);
            } 
        }
 
        public void RenderActiveArrayDeclarations(List updatePanels, HtmlTextWriter writer) { 
            Debug.Assert(writer != null, "Should always have a writer");
            List entriesToRender = new List(); 

            // For each entry registered in the page, check and see which ones
            // came from controls within UpdatePanels that are going to be updated.
            Control lastControl = null; 
            foreach (RegisteredArrayDeclaration entry in ScriptArrays) {
                Control child = entry.Control; 
                // if the owning control is the same as the last one that we know was active, 
                // no need to check IsControlRegistrationActive
                bool isActive = ((lastControl != null) && (child == lastControl)) || 
                    IsControlRegistrationActive(updatePanels, child, true);

                if (isActive) {
                    lastControl = child; 
                    if (!entriesToRender.Contains(entry)) {
                        entriesToRender.Add(entry); 
                    } 
                }
            } 

            foreach (RegisteredArrayDeclaration activeRegistration in entriesToRender) {
                PageRequestManager.EncodeString(writer,
                    PageRequestManager.ArrayDeclarationToken, 
                    activeRegistration.Name,
                    activeRegistration.Value); 
            } 
        }
 
        public void RenderActiveExpandos(List updatePanels, HtmlTextWriter writer) {
            Debug.Assert(writer != null, "Should always have a writer");
            if (updatePanels == null) {
                return; 
            }
            List entriesToRender = new List(); 
 
            // For each entry registered in the page, check and see which ones
            // came from controls within UpdatePanels that are going to be updated. 
            Control lastControl = null;
            foreach (RegisteredExpandoAttribute entry in ScriptExpandos) {
                Control child = entry.Control;
 
                bool isActive = ((lastControl != null) && (child == lastControl)) ||
                    IsControlRegistrationActive(updatePanels, child, false); 
 
                if (isActive) {
                    lastControl = child; 
                    if (!entriesToRender.Contains(entry)) {
                        entriesToRender.Add(entry);
                    }
                } 
            }
 
            foreach (RegisteredExpandoAttribute activeRegistration in entriesToRender) { 
                string propertyReference = "document.getElementById('" +
                    activeRegistration.ControlId + "')['" + activeRegistration.Name + "']"; 
                string value;
                if (activeRegistration.Encode) {
                    value = "\"" + JavaScriptString.QuoteString(activeRegistration.Value) + "\"";
                } 
                else if (activeRegistration.Value != null) {
                    value = "\"" + activeRegistration.Value + "\""; 
                } 
                else {
                    value = "null"; 
                }
                PageRequestManager.EncodeString(writer, PageRequestManager.ExpandoToken, propertyReference, value);
            }
        } 

        public void RenderActiveHiddenFields(List updatePanels, HtmlTextWriter writer) { 
            Debug.Assert(writer != null, "Should always have a writer"); 
            List entriesToRender = new List();
            ListDictionary uniqueEntries = new ListDictionary(StringComparer.Ordinal); 

            // For each entry registered in the page, check and see which ones
            // came from controls within UpdatePanels that are going to be updated.
            Control lastControl = null; 
            foreach (RegisteredHiddenField entry in ScriptHiddenFields) {
                Control child = entry.Control; 
 
                bool isActive = ((lastControl != null) && (child == lastControl)) ||
                    IsControlRegistrationActive(updatePanels, child, true); 

                if (isActive) {
                    lastControl = child;
                    if (!uniqueEntries.Contains(entry.Name)) { 
                        entriesToRender.Add(entry);
                        uniqueEntries.Add(entry.Name, entry); 
                    } 
                }
            } 

            foreach (RegisteredHiddenField activeRegistration in entriesToRender) {
                PageRequestManager.EncodeString(writer,
                    PageRequestManager.HiddenFieldToken, 
                    activeRegistration.Name,
                    activeRegistration.InitialValue); 
            } 
        }
 
        private void RenderActiveScriptBlocks(List updatePanels,
            HtmlTextWriter writer,
            string token,
            List scriptRegistrations) { 

            List entriesToRender = new List(); 
            // no comparer needed because it will contain ScriptKeys which implement Equals 
            ListDictionary uniqueEntries = new ListDictionary();
 
            // For each entry registered in the page, check and see which ones
            // came from controls within UpdatePanels that are going to be updated.
            Control lastControl = null;
            foreach (RegisteredScript entry in scriptRegistrations) { 
                Control child = entry.Control;
 
                bool isActive = ((lastControl != null) && (child == lastControl)) || 
                    IsControlRegistrationActive(updatePanels, child, true);
 
                if (isActive) {
                    lastControl = child;
                    ScriptKey scriptKey = new ScriptKey(entry.Type, entry.Key);
                    if (!uniqueEntries.Contains(scriptKey)) { 
                        entriesToRender.Add(entry);
                        uniqueEntries.Add(scriptKey, entry); 
                    } 
                }
            } 

            foreach (RegisteredScript activeRegistration in entriesToRender) {
                if (String.IsNullOrEmpty(activeRegistration.Url)) {
                    if (activeRegistration.AddScriptTags) { 
                        PageRequestManager.EncodeString(writer,
                            token, 
                            "ScriptContentNoTags", 
                            activeRegistration.Script);
                    } 
                    else {
                        WriteScriptWithTags(writer, token, activeRegistration);
                    }
                } 
                else {
                    PageRequestManager.EncodeString(writer, 
                        token, 
                        "ScriptPath",
                        activeRegistration.Url); 
                }
            }
        }
 
        public void RenderActiveScriptDisposes(List updatePanels, HtmlTextWriter writer) {
            Debug.Assert(writer != null, "Should always have a writer"); 
            if (updatePanels == null) { 
                return;
            } 

            // For each entry registered in the page, check and see which ones
            // came from controls within UpdatePanels that are going to be updated.
            foreach (RegisteredDisposeScript entry in ScriptDisposes) { 
                if (IsControlRegistrationActive(updatePanels, entry.ParentUpdatePanel, false)) {
                    PageRequestManager.EncodeString( 
                        writer, 
                        PageRequestManager.ScriptDisposeToken,
                        entry.ParentUpdatePanel.ClientID, 
                        entry.Script);
                }
            }
        } 

        public void RenderActiveScripts(List updatePanels, HtmlTextWriter writer) { 
            Debug.Assert(writer != null, "Should always have a writer"); 
            // Client script blocks and includes go first
            RenderActiveScriptBlocks(updatePanels, 
                writer,
                PageRequestManager.ScriptBlockToken,
                ScriptBlocks);
 
            // Startup scripts at end
            RenderActiveScriptBlocks(updatePanels, 
                writer, 
                PageRequestManager.ScriptStartupBlockToken,
                ScriptStartupBlocks); 
        }

        public void RenderActiveSubmitStatements(List updatePanels, HtmlTextWriter writer) {
            Debug.Assert(writer != null, "Should always have a writer"); 
            List entriesToRender = new List();
            // no comparer needed because it will contain ScriptKeys which implement Equals 
            ListDictionary uniqueEntries = new ListDictionary(); 

            // For each entry registered in the page, check and see which ones 
            // came from controls within UpdatePanels that are going to be updated.
            Control lastControl = null;
            foreach (RegisteredScript entry in ScriptSubmitStatements) {
                Control child = entry.Control; 

                bool isActive = ((lastControl != null) && (child == lastControl)) || 
                    IsControlRegistrationActive(updatePanels, child, true); 

                if (isActive) { 
                    lastControl = child;
                    ScriptKey scriptKey = new ScriptKey(entry.Type, entry.Key);
                    if (!uniqueEntries.Contains(scriptKey)) {
                        entriesToRender.Add(entry); 
                        uniqueEntries.Add(scriptKey, entry);
                    } 
                } 
            }
 
            foreach (RegisteredScript activeRegistration in entriesToRender) {
                PageRequestManager.EncodeString(writer, PageRequestManager.OnSubmitToken, null, activeRegistration.Script);
            }
        } 

        private static void WriteScriptWithTags(HtmlTextWriter writer, 
            string token, 
            RegisteredScript activeRegistration) {
 
            // If the content already has script tags, we need to parse out the contents
            // so that the client doesn't have to. The contents may include more than one
            // script tag, but no other content (such as arbitrary HTML).
            string scriptContent = activeRegistration.Script; 

            int lastIndex = 0; 
            for (Match match = ScriptTagRegex.Match(scriptContent, lastIndex); match.Success; match = ScriptTagRegex.Match(scriptContent, lastIndex)) { 
                CheckScriptTagTweenSpace(activeRegistration, scriptContent, lastIndex, match.Index - lastIndex);
 
                OrderedDictionary attrs = new OrderedDictionary();

                if (match.Groups["empty"].Captures.Count > 0) {
                    // Self-closing tag 

                    // No need to do anything since attributes are processed later 
                    lastIndex = match.Index + match.Length; 
                }
                else { 
                    // Open tag with explicit close tag

                    // Need to find close tag so that we can locate the inner contents
                    int indexOfEndOfScriptBeginTag = match.Index + match.Length; 
                    int indexOfScriptEndTag = scriptContent.IndexOf("", indexOfEndOfScriptBeginTag, StringComparison.OrdinalIgnoreCase);
                    if (indexOfScriptEndTag == -1) { 
                        throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptRegistrationManager_NoCloseTag, activeRegistration.Type.FullName, activeRegistration.Key)); 
                    }
                    string scriptBlockContents = scriptContent.Substring(indexOfEndOfScriptBeginTag, (indexOfScriptEndTag - indexOfEndOfScriptBeginTag)); 

                    // Turn the text content into a text attribute
                    attrs.Add("text", scriptBlockContents);
 
                    lastIndex = indexOfScriptEndTag + 9;
                } 
 
                // Process all the explicit attributes on the script tag
                CaptureCollection attrnames = match.Groups["attrname"].Captures; 
                CaptureCollection attrvalues = match.Groups["attrval"].Captures;
                for (int i = 0; i < attrnames.Count; i++) {
                    string attribName = attrnames[i].ToString();
                    string attribValue = attrvalues[i].ToString(); 

                    // DevDev Bugs 123213: script elements registered with RegisterStartupScript are normally rendered 
                    // into the html of the page. Any html encoded values in the attributes are interpreted by the 
                    // browser, so the actual data is not html encoded. We must HtmlDecode any attribute values we find
                    // here to remain consistent during async posts, since the data will be dynamically injected into 
                    // the dom, bypassing the browser's natural html decoding.
                    attribValue = HttpUtility.HtmlDecode(attribValue);
                    attrs.Add(attribName, attribValue);
                } 

                // Serialize the attributes to JSON and write them out 
                JavaScriptSerializer serializer = new JavaScriptSerializer(); 
                string attrText = serializer.Serialize(attrs);
                PageRequestManager.EncodeString(writer, token, "ScriptContentWithTags", attrText); 
            }

            CheckScriptTagTweenSpace(activeRegistration, scriptContent, lastIndex, scriptContent.Length - lastIndex);
 
            if (lastIndex == 0) {
                throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptRegistrationManager_NoTags, activeRegistration.Type.FullName, activeRegistration.Key)); 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

 
namespace System.Web.UI { 
    using System;
    using System.Collections.Generic; 
    using System.Collections.Specialized;
    using System.Diagnostics;
    using System.Globalization;
    using System.Text; 
    using System.Text.RegularExpressions;
    using System.Web.UI; 
    using System.Web.Resources; 
    using System.Web.Script.Serialization;
 
    internal sealed class ScriptRegistrationManager {
        private static Regex ScriptTagRegex = new Regex(
            @"\w[-\w:]*)" +          // Attribute name
                @"(" + 
                    @"\s*=\s*""(?[^""]*)""|" + // ="bar" attribute value 
                    @"\s*=\s*'(?[^']*)'" +     // ='bar' attribute value
                @")" + 
            @")*" +
            @"\s*(?/)?>",
            RegexOptions.Singleline | RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
 
        private ScriptManager _scriptManager;
        private List _scriptDisposes; 
        private List _scriptArrays; 
        private List _clientScriptBlocks;
        private List _startupScriptBlocks; 
        private List _hiddenFields;
        private List _expandos;
        private List _submitStatements;
 
        public ScriptRegistrationManager(ScriptManager scriptManager) {
            _scriptManager = scriptManager; 
        } 

        public List ScriptArrays { 
            get {
                if (_scriptArrays == null) {
                    _scriptArrays = new List();
                } 
                return _scriptArrays;
            } 
        } 

        public List ScriptBlocks { 
            get {
                if (_clientScriptBlocks == null) {
                    _clientScriptBlocks = new List();
                } 
                return _clientScriptBlocks;
            } 
        } 

        public List ScriptDisposes { 
            get {
                if (_scriptDisposes == null) {
                    _scriptDisposes = new List();
                } 
                return _scriptDisposes;
            } 
        } 

        public List ScriptExpandos { 
            get {
                if (_expandos == null) {
                    _expandos = new List();
                } 
                return _expandos;
            } 
        } 

        public List ScriptHiddenFields { 
            get {
                if (_hiddenFields == null) {
                    _hiddenFields = new List();
                } 
                return _hiddenFields;
            } 
        } 

        public List ScriptStartupBlocks { 
            get {
                if (_startupScriptBlocks == null) {
                    _startupScriptBlocks = new List();
                } 
                return _startupScriptBlocks;
            } 
        } 

        public List ScriptSubmitStatements { 
            get {
                if (_submitStatements == null) {
                    _submitStatements = new List();
                } 
                return _submitStatements;
            } 
        } 

        private static void CheckScriptTagTweenSpace(RegisteredScript entry, string text, int start, int length) { 
            // Check the range between the matches to make sure there is no extraneous content
            string tweenSpace = text.Substring(start, length);
            if (tweenSpace.Trim().Length != 0) {
                throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptRegistrationManager_InvalidChars, entry.Type.FullName, entry.Key, tweenSpace)); 
            }
        } 
 
        private bool IsControlRegistrationActive(
            List updatingUpdatePanels, 
            Control child,
            bool pageAlwaysActive) {

            // Determines if a registered resource, like a client script block, should be included in the partial 
            // update response. It should be included if the owning control is a child of an updating update panel
            // or if the owning control is the Page and this is a type of resource where Page is allowed as an owner. 
            // When page is the owner, it means always include the resource regardless of which update panels are 
            // updating. Expandos and dispose scripts do not support Page as the owner.
 
            // is this a resource that allows Page as the owner, and is the owner the Page?
            if (pageAlwaysActive) {
                Page childAsPage = child as Page;
                if (childAsPage == _scriptManager.Page) { 
                    // owner is page so the registration is automatically active
                    return true; 
                } 
            }
 
            // registration is active if owner is a child of any updating update panels
            if (updatingUpdatePanels != null && updatingUpdatePanels.Count > 0) {
                // navigate up the parent controls and see if any are an updating update panel.
                while (child != null) { 
                    if (child is UpdatePanel) {
                        // enumerate with for loop instead of foreach so we don't recreate an enumerator. 
                        // enumerate instead of using Contains so we do not have to cast or use a comparer. 
                        for (int i = 0; i < updatingUpdatePanels.Count; i++) {
                            if (child == updatingUpdatePanels[i]) { 
                                return true;
                            }
                        }
                    } 
                    child = child.Parent;
                } 
            } 

            return false; 
        }

        public static void RegisterArrayDeclaration(Control control, string arrayName, string arrayValue) {
            if (control == null) { 
                throw new ArgumentNullException("control");
            } 
            if (control.Page == null) { 
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control");
            } 

            control.Page.ClientScript.RegisterArrayDeclaration(arrayName, arrayValue);

            ScriptManager sm = ScriptManager.GetCurrent(control.Page); 
            if (sm != null) {
                RegisteredArrayDeclaration entry = new RegisteredArrayDeclaration(control, arrayName, arrayValue); 
                sm.ScriptRegistration.ScriptArrays.Add(entry); 
            }
        } 

        public static void RegisterClientScriptBlock(Control control, Type type, string key, string script, bool addScriptTags) {
            if (control == null) {
                throw new ArgumentNullException("control"); 
            }
            if (control.Page == null) { 
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control"); 
            }
 
            control.Page.ClientScript.RegisterClientScriptBlock(type, key, script, addScriptTags);

            ScriptManager sm = ScriptManager.GetCurrent(control.Page);
            if (sm != null) { 
                RegisteredScript entry =
                    new RegisteredScript(RegisteredScriptType.ClientScriptBlock, 
                        control, 
                        type,
                        key, 
                        script,
                        addScriptTags);
                sm.ScriptRegistration.ScriptBlocks.Add(entry);
            } 
        }
 
        public static void RegisterClientScriptInclude(Control control, Type type, string key, string url) { 
            if (control == null) {
                throw new ArgumentNullException("control"); 
            }
            if (control.Page == null) {
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control");
            } 

            control.Page.ClientScript.RegisterClientScriptInclude(type, key, url); 
 
            ScriptManager sm = ScriptManager.GetCurrent(control.Page);
            if (sm != null) { 
                RegisteredScript entry = new RegisteredScript(control, type, key, url);
                sm.ScriptRegistration.ScriptBlocks.Add(entry);
            }
        } 

        public static void RegisterClientScriptResource(Control control, Type type, string resourceName) { 
            if (control == null) { 
                throw new ArgumentNullException("control");
            } 
            if (control.Page == null) {
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control");
            }
 
            ScriptManager sm = ScriptManager.GetCurrent(control.Page);
            if (sm == null) { 
                control.Page.ClientScript.RegisterClientScriptResource(type, resourceName); 
            }
            else { 
                string resourceUrl = sm.GetScriptResourceUrl(resourceName, type.Assembly);
                control.Page.ClientScript.RegisterClientScriptInclude(type, resourceName, resourceUrl);
                RegisteredScript entry = new RegisteredScript(control, type, resourceName, resourceUrl);
                sm.ScriptRegistration.ScriptBlocks.Add(entry); 
            }
        } 
 
        internal void RegisterDispose(Control control, string disposeScript) {
            if (control == null) { 
                throw new ArgumentNullException("control");
            }
            if (control.Page == null) {
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control"); 
            }
            if (disposeScript == null) { 
                throw new ArgumentNullException("disposeScript"); 
            }
 
            // Locate the parent UpdatePanel of the control
            Control parent = control.Parent;
            UpdatePanel parentUpdatePanel = null;
            while (parent != null) { 
                parentUpdatePanel = parent as UpdatePanel;
                if (parentUpdatePanel != null) { 
                    break; 
                }
                parent = parent.Parent; 
            }
            if (parentUpdatePanel != null) {
                // During async posts we build up a list of ScriptDisposes. Later
                // we go through the list and filter out ones that aren't inside 
                // UpdatePanels that are refreshing.
                // DevDiv Bugs 128123: Build the list on non-async postbacks as well, 
                // so that GetRegisteredDisposeScripts returns them. 
                RegisteredDisposeScript entry = new RegisteredDisposeScript(control, disposeScript, parentUpdatePanel);
                ScriptDisposes.Add(entry); 

                if (!_scriptManager.IsInAsyncPostBack) {
                    // During non-async requests we register script immediately to do the
                    // dispose. This is necessary because some controls will register as late 
                    // as Render(), at which point it would be too late to build up a list
                    // for processing later. 
                    JavaScriptSerializer serializer = new JavaScriptSerializer(); 
                    // 256 seems like a nice number so that we don't have to resize the StringBuilder except in very rare cases
                    StringBuilder sb = new StringBuilder(256); 
                    sb.Append("Sys.WebForms.PageRequestManager.getInstance()._registerDisposeScript(");
                    serializer.Serialize(parentUpdatePanel.ClientID, sb);
                    sb.Append(", ");
                    serializer.Serialize(disposeScript, sb); 
                    sb.AppendLine(");");
 
                    // DevDiv Bugs 128123: Register directly with ClientScriptManager so that a RegisteredScript 
                    // entry is not created. Otherwise, calls to RegisterDispose would result in viewable
                    // RegisteredScript entries through GetRegisteredStartupScripts(). 
                    _scriptManager.IPage.ClientScript.RegisterStartupScript(typeof(ScriptRegistrationManager),
                        _scriptManager.CreateUniqueScriptKey(),
                        sb.ToString(),
                        true); 
                }
            } 
        } 

        public static void RegisterExpandoAttribute(Control control, string controlId, string attributeName, string attributeValue, bool encode) { 
            if (control == null) {
                throw new ArgumentNullException("control");
            }
            if (control.Page == null) { 
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control");
            } 
 
            control.Page.ClientScript.RegisterExpandoAttribute(controlId, attributeName, attributeValue, encode);
 
            ScriptManager sm = ScriptManager.GetCurrent(control.Page);
            if (sm != null) {
                RegisteredExpandoAttribute entry =
                    new RegisteredExpandoAttribute(control, 
                        controlId,
                        attributeName, 
                        attributeValue, 
                        encode);
                sm.ScriptRegistration.ScriptExpandos.Add(entry); 
            }
        }

        public static void RegisterHiddenField(Control control, string hiddenFieldName, string hiddenFieldInitialValue) { 
            if (control == null) {
                throw new ArgumentNullException("control"); 
            } 
            if (control.Page == null) {
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control"); 
            }

            control.Page.ClientScript.RegisterHiddenField(hiddenFieldName, hiddenFieldInitialValue);
 
            ScriptManager sm = ScriptManager.GetCurrent(control.Page);
            if (sm != null) { 
                RegisteredHiddenField entry = 
                    new RegisteredHiddenField(control,
                        hiddenFieldName, 
                        hiddenFieldInitialValue);
                sm.ScriptRegistration.ScriptHiddenFields.Add(entry);
            }
        } 

        public static void RegisterOnSubmitStatement(Control control, Type type, string key, string script) { 
            if (control == null) { 
                throw new ArgumentNullException("control");
            } 
            if (control.Page == null) {
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control");
            }
 
            control.Page.ClientScript.RegisterOnSubmitStatement(type, key, script);
 
            ScriptManager sm = ScriptManager.GetCurrent(control.Page); 
            if (sm != null) {
                RegisteredScript entry = 
                    new RegisteredScript(RegisteredScriptType.OnSubmitStatement,
                        control,
                        type,
                        key, 
                        script,
                        false); 
                sm.ScriptRegistration.ScriptSubmitStatements.Add(entry); 
            }
        } 

        public static void RegisterStartupScript(Control control, Type type, string key, string script, bool addScriptTags) {
            if (control == null) {
                throw new ArgumentNullException("control"); 
            }
            if (control.Page == null) { 
                throw new ArgumentException(AtlasWeb.ScriptRegistrationManager_ControlNotOnPage, "control"); 
            }
 
            control.Page.ClientScript.RegisterStartupScript(type, key, script, addScriptTags);

            ScriptManager sm = ScriptManager.GetCurrent(control.Page);
            if (sm != null) { 
                RegisteredScript entry =
                    new RegisteredScript(RegisteredScriptType.ClientStartupScript, 
                        control, 
                        type,
                        key, 
                        script,
                        addScriptTags);
                sm.ScriptRegistration.ScriptStartupBlocks.Add(entry);
            } 
        }
 
        public void RenderActiveArrayDeclarations(List updatePanels, HtmlTextWriter writer) { 
            Debug.Assert(writer != null, "Should always have a writer");
            List entriesToRender = new List(); 

            // For each entry registered in the page, check and see which ones
            // came from controls within UpdatePanels that are going to be updated.
            Control lastControl = null; 
            foreach (RegisteredArrayDeclaration entry in ScriptArrays) {
                Control child = entry.Control; 
                // if the owning control is the same as the last one that we know was active, 
                // no need to check IsControlRegistrationActive
                bool isActive = ((lastControl != null) && (child == lastControl)) || 
                    IsControlRegistrationActive(updatePanels, child, true);

                if (isActive) {
                    lastControl = child; 
                    if (!entriesToRender.Contains(entry)) {
                        entriesToRender.Add(entry); 
                    } 
                }
            } 

            foreach (RegisteredArrayDeclaration activeRegistration in entriesToRender) {
                PageRequestManager.EncodeString(writer,
                    PageRequestManager.ArrayDeclarationToken, 
                    activeRegistration.Name,
                    activeRegistration.Value); 
            } 
        }
 
        public void RenderActiveExpandos(List updatePanels, HtmlTextWriter writer) {
            Debug.Assert(writer != null, "Should always have a writer");
            if (updatePanels == null) {
                return; 
            }
            List entriesToRender = new List(); 
 
            // For each entry registered in the page, check and see which ones
            // came from controls within UpdatePanels that are going to be updated. 
            Control lastControl = null;
            foreach (RegisteredExpandoAttribute entry in ScriptExpandos) {
                Control child = entry.Control;
 
                bool isActive = ((lastControl != null) && (child == lastControl)) ||
                    IsControlRegistrationActive(updatePanels, child, false); 
 
                if (isActive) {
                    lastControl = child; 
                    if (!entriesToRender.Contains(entry)) {
                        entriesToRender.Add(entry);
                    }
                } 
            }
 
            foreach (RegisteredExpandoAttribute activeRegistration in entriesToRender) { 
                string propertyReference = "document.getElementById('" +
                    activeRegistration.ControlId + "')['" + activeRegistration.Name + "']"; 
                string value;
                if (activeRegistration.Encode) {
                    value = "\"" + JavaScriptString.QuoteString(activeRegistration.Value) + "\"";
                } 
                else if (activeRegistration.Value != null) {
                    value = "\"" + activeRegistration.Value + "\""; 
                } 
                else {
                    value = "null"; 
                }
                PageRequestManager.EncodeString(writer, PageRequestManager.ExpandoToken, propertyReference, value);
            }
        } 

        public void RenderActiveHiddenFields(List updatePanels, HtmlTextWriter writer) { 
            Debug.Assert(writer != null, "Should always have a writer"); 
            List entriesToRender = new List();
            ListDictionary uniqueEntries = new ListDictionary(StringComparer.Ordinal); 

            // For each entry registered in the page, check and see which ones
            // came from controls within UpdatePanels that are going to be updated.
            Control lastControl = null; 
            foreach (RegisteredHiddenField entry in ScriptHiddenFields) {
                Control child = entry.Control; 
 
                bool isActive = ((lastControl != null) && (child == lastControl)) ||
                    IsControlRegistrationActive(updatePanels, child, true); 

                if (isActive) {
                    lastControl = child;
                    if (!uniqueEntries.Contains(entry.Name)) { 
                        entriesToRender.Add(entry);
                        uniqueEntries.Add(entry.Name, entry); 
                    } 
                }
            } 

            foreach (RegisteredHiddenField activeRegistration in entriesToRender) {
                PageRequestManager.EncodeString(writer,
                    PageRequestManager.HiddenFieldToken, 
                    activeRegistration.Name,
                    activeRegistration.InitialValue); 
            } 
        }
 
        private void RenderActiveScriptBlocks(List updatePanels,
            HtmlTextWriter writer,
            string token,
            List scriptRegistrations) { 

            List entriesToRender = new List(); 
            // no comparer needed because it will contain ScriptKeys which implement Equals 
            ListDictionary uniqueEntries = new ListDictionary();
 
            // For each entry registered in the page, check and see which ones
            // came from controls within UpdatePanels that are going to be updated.
            Control lastControl = null;
            foreach (RegisteredScript entry in scriptRegistrations) { 
                Control child = entry.Control;
 
                bool isActive = ((lastControl != null) && (child == lastControl)) || 
                    IsControlRegistrationActive(updatePanels, child, true);
 
                if (isActive) {
                    lastControl = child;
                    ScriptKey scriptKey = new ScriptKey(entry.Type, entry.Key);
                    if (!uniqueEntries.Contains(scriptKey)) { 
                        entriesToRender.Add(entry);
                        uniqueEntries.Add(scriptKey, entry); 
                    } 
                }
            } 

            foreach (RegisteredScript activeRegistration in entriesToRender) {
                if (String.IsNullOrEmpty(activeRegistration.Url)) {
                    if (activeRegistration.AddScriptTags) { 
                        PageRequestManager.EncodeString(writer,
                            token, 
                            "ScriptContentNoTags", 
                            activeRegistration.Script);
                    } 
                    else {
                        WriteScriptWithTags(writer, token, activeRegistration);
                    }
                } 
                else {
                    PageRequestManager.EncodeString(writer, 
                        token, 
                        "ScriptPath",
                        activeRegistration.Url); 
                }
            }
        }
 
        public void RenderActiveScriptDisposes(List updatePanels, HtmlTextWriter writer) {
            Debug.Assert(writer != null, "Should always have a writer"); 
            if (updatePanels == null) { 
                return;
            } 

            // For each entry registered in the page, check and see which ones
            // came from controls within UpdatePanels that are going to be updated.
            foreach (RegisteredDisposeScript entry in ScriptDisposes) { 
                if (IsControlRegistrationActive(updatePanels, entry.ParentUpdatePanel, false)) {
                    PageRequestManager.EncodeString( 
                        writer, 
                        PageRequestManager.ScriptDisposeToken,
                        entry.ParentUpdatePanel.ClientID, 
                        entry.Script);
                }
            }
        } 

        public void RenderActiveScripts(List updatePanels, HtmlTextWriter writer) { 
            Debug.Assert(writer != null, "Should always have a writer"); 
            // Client script blocks and includes go first
            RenderActiveScriptBlocks(updatePanels, 
                writer,
                PageRequestManager.ScriptBlockToken,
                ScriptBlocks);
 
            // Startup scripts at end
            RenderActiveScriptBlocks(updatePanels, 
                writer, 
                PageRequestManager.ScriptStartupBlockToken,
                ScriptStartupBlocks); 
        }

        public void RenderActiveSubmitStatements(List updatePanels, HtmlTextWriter writer) {
            Debug.Assert(writer != null, "Should always have a writer"); 
            List entriesToRender = new List();
            // no comparer needed because it will contain ScriptKeys which implement Equals 
            ListDictionary uniqueEntries = new ListDictionary(); 

            // For each entry registered in the page, check and see which ones 
            // came from controls within UpdatePanels that are going to be updated.
            Control lastControl = null;
            foreach (RegisteredScript entry in ScriptSubmitStatements) {
                Control child = entry.Control; 

                bool isActive = ((lastControl != null) && (child == lastControl)) || 
                    IsControlRegistrationActive(updatePanels, child, true); 

                if (isActive) { 
                    lastControl = child;
                    ScriptKey scriptKey = new ScriptKey(entry.Type, entry.Key);
                    if (!uniqueEntries.Contains(scriptKey)) {
                        entriesToRender.Add(entry); 
                        uniqueEntries.Add(scriptKey, entry);
                    } 
                } 
            }
 
            foreach (RegisteredScript activeRegistration in entriesToRender) {
                PageRequestManager.EncodeString(writer, PageRequestManager.OnSubmitToken, null, activeRegistration.Script);
            }
        } 

        private static void WriteScriptWithTags(HtmlTextWriter writer, 
            string token, 
            RegisteredScript activeRegistration) {
 
            // If the content already has script tags, we need to parse out the contents
            // so that the client doesn't have to. The contents may include more than one
            // script tag, but no other content (such as arbitrary HTML).
            string scriptContent = activeRegistration.Script; 

            int lastIndex = 0; 
            for (Match match = ScriptTagRegex.Match(scriptContent, lastIndex); match.Success; match = ScriptTagRegex.Match(scriptContent, lastIndex)) { 
                CheckScriptTagTweenSpace(activeRegistration, scriptContent, lastIndex, match.Index - lastIndex);
 
                OrderedDictionary attrs = new OrderedDictionary();

                if (match.Groups["empty"].Captures.Count > 0) {
                    // Self-closing tag 

                    // No need to do anything since attributes are processed later 
                    lastIndex = match.Index + match.Length; 
                }
                else { 
                    // Open tag with explicit close tag

                    // Need to find close tag so that we can locate the inner contents
                    int indexOfEndOfScriptBeginTag = match.Index + match.Length; 
                    int indexOfScriptEndTag = scriptContent.IndexOf("", indexOfEndOfScriptBeginTag, StringComparison.OrdinalIgnoreCase);
                    if (indexOfScriptEndTag == -1) { 
                        throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptRegistrationManager_NoCloseTag, activeRegistration.Type.FullName, activeRegistration.Key)); 
                    }
                    string scriptBlockContents = scriptContent.Substring(indexOfEndOfScriptBeginTag, (indexOfScriptEndTag - indexOfEndOfScriptBeginTag)); 

                    // Turn the text content into a text attribute
                    attrs.Add("text", scriptBlockContents);
 
                    lastIndex = indexOfScriptEndTag + 9;
                } 
 
                // Process all the explicit attributes on the script tag
                CaptureCollection attrnames = match.Groups["attrname"].Captures; 
                CaptureCollection attrvalues = match.Groups["attrval"].Captures;
                for (int i = 0; i < attrnames.Count; i++) {
                    string attribName = attrnames[i].ToString();
                    string attribValue = attrvalues[i].ToString(); 

                    // DevDev Bugs 123213: script elements registered with RegisterStartupScript are normally rendered 
                    // into the html of the page. Any html encoded values in the attributes are interpreted by the 
                    // browser, so the actual data is not html encoded. We must HtmlDecode any attribute values we find
                    // here to remain consistent during async posts, since the data will be dynamically injected into 
                    // the dom, bypassing the browser's natural html decoding.
                    attribValue = HttpUtility.HtmlDecode(attribValue);
                    attrs.Add(attribName, attribValue);
                } 

                // Serialize the attributes to JSON and write them out 
                JavaScriptSerializer serializer = new JavaScriptSerializer(); 
                string attrText = serializer.Serialize(attrs);
                PageRequestManager.EncodeString(writer, token, "ScriptContentWithTags", attrText); 
            }

            CheckScriptTagTweenSpace(activeRegistration, scriptContent, lastIndex, scriptContent.Length - lastIndex);
 
            if (lastIndex == 0) {
                throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.ScriptRegistrationManager_NoTags, activeRegistration.Type.FullName, activeRegistration.Key)); 
            } 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK