e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
1488 lines
64 KiB
C#
1488 lines
64 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="ClientScriptManager.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace System.Web.UI {
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.ComponentModel.Design;
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
using System.Web.Compilation;
|
|
using System.Web.Handlers;
|
|
using System.Web.UI.WebControls;
|
|
using System.Web.Util;
|
|
using ExceptionUtil=System.Web.Util.ExceptionUtil;
|
|
using WebUtil = System.Web.Util;
|
|
using System.Security.Permissions;
|
|
using System.Reflection;
|
|
using System.Runtime.Serialization;
|
|
using System.Collections.Generic;
|
|
using System.Web.Security.Cryptography;
|
|
|
|
// The various types of client API's that can be registered
|
|
internal enum ClientAPIRegisterType {
|
|
WebFormsScript,
|
|
PostBackScript,
|
|
FocusScript,
|
|
ClientScriptBlocks,
|
|
ClientScriptBlocksWithoutTags,
|
|
ClientStartupScripts,
|
|
ClientStartupScriptsWithoutTags,
|
|
OnSubmitStatement,
|
|
ArrayDeclaration,
|
|
HiddenField,
|
|
ExpandoAttribute,
|
|
EventValidation,
|
|
}
|
|
|
|
public sealed class ClientScriptManager {
|
|
private const string IncludeScriptBegin = @"
|
|
<script src=""";
|
|
private const string IncludeScriptEnd = @""" type=""text/javascript""></script>";
|
|
internal const string ClientScriptStart = "\r\n<script type=\"text/javascript\">\r\n//<![CDATA[\r\n";
|
|
internal const string ClientScriptStartLegacy = "\r\n<script type=\"text/javascript\">\r\n<!--\r\n";
|
|
internal const string ClientScriptEnd = "//]]>\r\n</script>\r\n";
|
|
internal const string ClientScriptEndLegacy = "// -->\r\n</script>\r\n";
|
|
internal const string JscriptPrefix = "javascript:";
|
|
|
|
private const string _callbackFunctionName = "WebForm_DoCallback";
|
|
private const string _postbackOptionsFunctionName = "WebForm_DoPostBackWithOptions";
|
|
private const string _postBackFunctionName = "__doPostBack";
|
|
private const string PageCallbackScriptKey = "PageCallbackScript";
|
|
|
|
internal static IScriptResourceMapping _scriptResourceMapping;
|
|
|
|
private ListDictionary _registeredClientScriptBlocks;
|
|
private ArrayList _clientScriptBlocks;
|
|
private ListDictionary _registeredClientStartupScripts;
|
|
private ArrayList _clientStartupScripts;
|
|
private Dictionary<Assembly, Dictionary<String, Object>> _registeredResourcesToSuppress;
|
|
private bool _eventValidationFieldLoaded;
|
|
|
|
private ListDictionary _registeredOnSubmitStatements;
|
|
|
|
private IDictionary _registeredArrayDeclares;
|
|
private ListDictionary _registeredHiddenFields;
|
|
private ListDictionary _registeredControlsWithExpandoAttributes;
|
|
|
|
private IEventValidationProvider _eventValidationProvider;
|
|
|
|
private Page _owner;
|
|
|
|
internal ClientScriptManager(Page owner) {
|
|
_owner = owner;
|
|
}
|
|
|
|
internal bool HasRegisteredHiddenFields {
|
|
get {
|
|
return (_registeredHiddenFields != null && _registeredHiddenFields.Count > 0);
|
|
}
|
|
}
|
|
|
|
internal bool HasSubmitStatements {
|
|
get {
|
|
return (_registeredOnSubmitStatements != null && _registeredOnSubmitStatements.Count > 0);
|
|
}
|
|
}
|
|
|
|
internal Dictionary<Assembly, Dictionary<String, Object>> RegisteredResourcesToSuppress {
|
|
get {
|
|
if (_registeredResourcesToSuppress == null) {
|
|
_registeredResourcesToSuppress = new Dictionary<Assembly, Dictionary<String, Object>>();
|
|
}
|
|
return _registeredResourcesToSuppress;
|
|
}
|
|
}
|
|
|
|
private IEventValidationProvider EventValidationProvider {
|
|
get {
|
|
if (_eventValidationProvider == null) {
|
|
if (AppSettings.UseLegacyEventValidationCompatibility) {
|
|
_eventValidationProvider = new LegacyEventValidationProvider(this);
|
|
}
|
|
else {
|
|
_eventValidationProvider = new DefaultEventValidationProvider(this);
|
|
}
|
|
}
|
|
return _eventValidationProvider;
|
|
}
|
|
}
|
|
|
|
internal string GetEventValidationFieldValue() {
|
|
// Access the _eventValidationProvider field instead of the EventValidationProvider property so that we
|
|
// don't end up instantiating objects if not necessary.
|
|
if (_eventValidationProvider != null) {
|
|
object eventValidationStoreObject = _eventValidationProvider.GetEventValidationStoreObject();
|
|
if (eventValidationStoreObject != null) {
|
|
// Make cryptographically secure
|
|
IStateFormatter2 formatter = _owner.CreateStateFormatter();
|
|
return formatter.Serialize(eventValidationStoreObject, Purpose.WebForms_ClientScriptManager_EventValidation);
|
|
}
|
|
}
|
|
|
|
// If we got here, there was no store data.
|
|
return String.Empty;
|
|
}
|
|
|
|
public void RegisterForEventValidation(PostBackOptions options) {
|
|
RegisterForEventValidation(options.TargetControl.UniqueID, options.Argument);
|
|
}
|
|
|
|
public void RegisterForEventValidation(string uniqueId) {
|
|
RegisterForEventValidation(uniqueId, String.Empty);
|
|
}
|
|
|
|
public void RegisterForEventValidation(string uniqueId, string argument) {
|
|
// Step 1: argument and precondition checks
|
|
if (!_owner.EnableEventValidation || _owner.DesignMode) {
|
|
return;
|
|
}
|
|
|
|
// VSWhidbey 497632. Ignore if uniqueID is empty since the postback won't be valid anyway.
|
|
if (String.IsNullOrEmpty(uniqueId)) {
|
|
return;
|
|
}
|
|
|
|
if ((_owner.ControlState < ControlState.PreRendered) && (!_owner.IsCallback)) {
|
|
throw new InvalidOperationException(
|
|
SR.GetString(SR.ClientScriptManager_RegisterForEventValidation_Too_Early));
|
|
}
|
|
|
|
// Step 2: Add this tuple to the list
|
|
EventValidationProvider.RegisterForEventValidation(uniqueId, argument);
|
|
|
|
// Step 3: If there are any partial caching controls on the stack, forward the call to them
|
|
if (_owner.PartialCachingControlStack != null) {
|
|
foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) {
|
|
c.RegisterForEventValidation(uniqueId, argument);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void SaveEventValidationField() {
|
|
string fieldValue = GetEventValidationFieldValue();
|
|
if (!String.IsNullOrEmpty(fieldValue)) {
|
|
RegisterHiddenField(Page.EventValidationPrefixID, fieldValue);
|
|
}
|
|
}
|
|
|
|
// Used by unobtrusive javascript validators to verify that a scriptresource mapping for jquery is registered
|
|
internal static void EnsureJqueryRegistered() {
|
|
if (_scriptResourceMapping != null) {
|
|
if (_scriptResourceMapping.GetDefinition("jquery", typeof(Page).Assembly) == null &&
|
|
_scriptResourceMapping.GetDefinition("jquery") == null) {
|
|
throw new InvalidOperationException(SR.GetString(SR.ClientScriptManager_JqueryNotRegistered));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void EnsureEventValidationFieldLoaded() {
|
|
if (_eventValidationFieldLoaded) {
|
|
return;
|
|
}
|
|
|
|
_eventValidationFieldLoaded = true;
|
|
|
|
// Step 1: Read the event validation field
|
|
string unsafeField = null;
|
|
if (_owner.RequestValueCollection != null) {
|
|
unsafeField = _owner.RequestValueCollection[Page.EventValidationPrefixID];
|
|
}
|
|
|
|
if (String.IsNullOrEmpty(unsafeField)) {
|
|
return;
|
|
}
|
|
|
|
// Step 2: Decrypt the event validation field
|
|
IStateFormatter2 formatter = _owner.CreateStateFormatter();
|
|
object eventValidationField = null;
|
|
try {
|
|
eventValidationField = formatter.Deserialize(unsafeField, Purpose.WebForms_ClientScriptManager_EventValidation);
|
|
}
|
|
catch (Exception ex) {
|
|
// DevDiv #461378: Ignore validation errors for cross-page postbacks. Since the ValidateEvent method
|
|
// is most likely on the call stack right now, this will result in an event validation failure rather
|
|
// than a MAC validation failure.
|
|
if (!_owner.ShouldSuppressMacValidationException(ex)) {
|
|
ViewStateException.ThrowViewStateError(ex, unsafeField);
|
|
}
|
|
}
|
|
|
|
// Step 3: Load the event validation field into the appropriate provider
|
|
if (!EventValidationProvider.TryLoadEventValidationField(eventValidationField)) {
|
|
// Something went wrong while loading the incoming event validation object; the
|
|
// most likely cause is that it wasn't submitted with the correct ViewState.
|
|
ViewStateException.ThrowViewStateError(null, unsafeField);
|
|
}
|
|
}
|
|
|
|
public void ValidateEvent(string uniqueId) {
|
|
ValidateEvent(uniqueId, String.Empty);
|
|
}
|
|
|
|
public void ValidateEvent(string uniqueId, string argument) {
|
|
if (!_owner.EnableEventValidation) {
|
|
return;
|
|
}
|
|
|
|
if (String.IsNullOrEmpty(uniqueId)) {
|
|
throw new ArgumentException(SR.GetString(SR.Parameter_NullOrEmpty, "uniqueId"), "uniqueId");
|
|
}
|
|
|
|
EnsureEventValidationFieldLoaded();
|
|
|
|
// Go against the _eventValidationProvider field instead of the EventValidationProvider
|
|
// property to avoid the lazy instantiation code if not necessary.
|
|
if (_eventValidationProvider == null || !_eventValidationProvider.IsValid(uniqueId, argument)) {
|
|
throw new ArgumentException(SR.GetString(SR.ClientScriptManager_InvalidPostBackArgument));
|
|
}
|
|
}
|
|
|
|
internal void ClearHiddenFields() {
|
|
_registeredHiddenFields = null;
|
|
}
|
|
|
|
internal static ScriptKey CreateScriptKey(Type type, string key) {
|
|
return new ScriptKey(type, key);
|
|
}
|
|
|
|
internal static ScriptKey CreateScriptIncludeKey(Type type, string key, bool isResource) {
|
|
return new ScriptKey(type, key, true, isResource);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Enables controls to obtain client-side script function that will cause
|
|
/// (when invoked) an out-of-band callback to the server
|
|
/// </devdoc>
|
|
public string GetCallbackEventReference(Control control, string argument, string clientCallback, string context) {
|
|
return GetCallbackEventReference(control, argument, clientCallback, context, false);
|
|
}
|
|
|
|
public string GetCallbackEventReference(Control control, string argument, string clientCallback, string context, bool useAsync) {
|
|
return GetCallbackEventReference(control, argument, clientCallback, context, null, useAsync);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Enables controls to obtain client-side script function that will cause
|
|
/// (when invoked) an out-of-band callback to the server and allows the user to specify a client-side error callback
|
|
/// </devdoc>
|
|
public string GetCallbackEventReference(Control control, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync) {
|
|
if (control == null) {
|
|
throw new ArgumentNullException("control");
|
|
}
|
|
if (!(control is ICallbackEventHandler)) {
|
|
throw new InvalidOperationException(SR.GetString(SR.Page_CallBackTargetInvalid, control.UniqueID));
|
|
}
|
|
return GetCallbackEventReference("'" + control.UniqueID + "'", argument, clientCallback, context, clientErrorCallback, useAsync);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Enables controls to obtain client-side script function that will cause
|
|
/// (when invoked) an out-of-band callback to the server and allows the user to specify a client-side error callback
|
|
/// </devdoc>
|
|
public string GetCallbackEventReference(string target, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync) {
|
|
_owner.RegisterWebFormsScript();
|
|
if (_owner.ClientSupportsJavaScript && (_owner.RequestInternal != null) && _owner.RequestInternal.Browser.SupportsCallback) {
|
|
RegisterStartupScript(typeof(Page), PageCallbackScriptKey, (((_owner.RequestInternal != null) &&
|
|
(String.Equals(_owner.RequestInternal.Url.Scheme, "https", StringComparison.OrdinalIgnoreCase))) ?
|
|
@"
|
|
var callBackFrameUrl='" + Util.QuoteJScriptString(GetWebResourceUrl(typeof(Page), "SmartNav.htm"), false) + @"';
|
|
WebForm_InitCallback();" :
|
|
@"
|
|
WebForm_InitCallback();"), true);
|
|
}
|
|
if (argument == null) {
|
|
argument = "null";
|
|
}
|
|
else if (argument.Length == 0) {
|
|
argument = "\"\"";
|
|
}
|
|
if (context == null) {
|
|
context = "null";
|
|
}
|
|
else if (context.Length == 0) {
|
|
context = "\"\"";
|
|
}
|
|
return _callbackFunctionName +
|
|
"(" +
|
|
target +
|
|
"," +
|
|
argument +
|
|
"," +
|
|
clientCallback +
|
|
"," +
|
|
context +
|
|
"," +
|
|
((clientErrorCallback == null) ? "null" : clientErrorCallback) +
|
|
"," +
|
|
(useAsync ? "true" : "false") +
|
|
")";
|
|
}
|
|
|
|
public string GetPostBackClientHyperlink(Control control, string argument) {
|
|
// We're using escapePercent=true here and false in Page
|
|
// because true in Page would be a breaking change:
|
|
// People may already be encoding percent characters before calling this,
|
|
// and we may double encode it.
|
|
// Our own classes and new code should almost always use the override with escapePercent=true.
|
|
return GetPostBackClientHyperlink(control, argument, true, false);
|
|
}
|
|
|
|
public string GetPostBackClientHyperlink(Control control, string argument, bool registerForEventValidation) {
|
|
// We're using escapePercent=true here and false in Page
|
|
// because true in Page would be a breaking change:
|
|
// People may already be encoding percent characters before calling this,
|
|
// and we may double encode it.
|
|
// Our own classes and new code should almost always use the override with escapePercent=true.
|
|
return GetPostBackClientHyperlink(control, argument, true, registerForEventValidation);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>This returs a string that can be put in client event to post back to the named control</para>
|
|
/// </devdoc>
|
|
internal string GetPostBackClientHyperlink(Control control, string argument, bool escapePercent, bool registerForEventValidation) {
|
|
// Hyperlinks always need the language prefix
|
|
// If used in a hyperlink, the event argument needs to be escaped for % characters
|
|
// which will otherwise be interpreted as escape sequences (VSWhidbey 421874)
|
|
return JscriptPrefix + GetPostBackEventReference(control, argument, escapePercent, registerForEventValidation);
|
|
}
|
|
|
|
public string GetPostBackEventReference(Control control, string argument) {
|
|
return GetPostBackEventReference(control, argument, false, false);
|
|
}
|
|
|
|
public string GetPostBackEventReference(Control control, string argument, bool registerForEventValidation) {
|
|
return GetPostBackEventReference(control, argument, false, registerForEventValidation);
|
|
}
|
|
|
|
/*
|
|
* Enables controls to obtain client-side script function that will cause
|
|
* (when invoked) a server post-back to the form.
|
|
* argument: Parameter that will be passed to control on server
|
|
*/
|
|
/// <devdoc>
|
|
/// <para>Passes a parameter to the control that will do the postback processing on the
|
|
/// server.</para>
|
|
/// </devdoc>
|
|
private string GetPostBackEventReference(Control control, string argument, bool forUrl, bool registerForEventValidation) {
|
|
if (control == null) {
|
|
throw new ArgumentNullException("control");
|
|
}
|
|
|
|
_owner.RegisterPostBackScript();
|
|
|
|
string controlID = control.UniqueID;
|
|
|
|
if (registerForEventValidation) {
|
|
RegisterForEventValidation(controlID, argument);
|
|
}
|
|
|
|
// VSWhidbey 475945
|
|
if (control.EnableLegacyRendering && _owner.IsInOnFormRender &&
|
|
controlID != null && controlID.IndexOf(Control.LEGACY_ID_SEPARATOR) >= 0) {
|
|
|
|
controlID = controlID.Replace(Control.LEGACY_ID_SEPARATOR, Control.ID_SEPARATOR);
|
|
}
|
|
|
|
// Split into 2 calls to String.Concat to improve performance.
|
|
// CLR is investigating whether this should be fixed at a lower level.
|
|
string postBackEventReference = _postBackFunctionName + "('" + controlID + "','";
|
|
// The argument needs to be quoted, in case in contains characters that
|
|
// can't be used in JScript strings (ASURT 71818).
|
|
postBackEventReference += Util.QuoteJScriptString(argument, forUrl) + "')";
|
|
|
|
return postBackEventReference;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Passes a parameter to the control that will do the postback processing on the
|
|
/// server.</para>
|
|
/// </devdoc>
|
|
public string GetPostBackEventReference(PostBackOptions options) {
|
|
return GetPostBackEventReference(options, false);
|
|
}
|
|
|
|
public string GetPostBackEventReference(PostBackOptions options, bool registerForEventValidation) {
|
|
if (options == null) {
|
|
throw new ArgumentNullException("options");
|
|
}
|
|
|
|
if (registerForEventValidation) {
|
|
RegisterForEventValidation(options);
|
|
}
|
|
|
|
StringBuilder builder = new StringBuilder();
|
|
bool shouldRenderPostBackReferenceString = false;
|
|
|
|
if (options.RequiresJavaScriptProtocol) {
|
|
builder.Append(JscriptPrefix);
|
|
}
|
|
|
|
if (options.AutoPostBack) {
|
|
builder.Append("setTimeout('");
|
|
}
|
|
|
|
// Use the old __doPostBack method if not using other postback features.
|
|
if (!options.PerformValidation && !options.TrackFocus && options.ClientSubmit &&
|
|
string.IsNullOrEmpty(options.ActionUrl)) {
|
|
string postbackRef = GetPostBackEventReference(options.TargetControl, options.Argument);
|
|
|
|
// Need to quote the string if auto posting back
|
|
if (options.AutoPostBack) {
|
|
builder.Append(Util.QuoteJScriptString(postbackRef));
|
|
builder.Append("', 0)");
|
|
}
|
|
else {
|
|
builder.Append(postbackRef);
|
|
}
|
|
|
|
return builder.ToString();
|
|
}
|
|
|
|
builder.Append(_postbackOptionsFunctionName);
|
|
builder.Append("(new WebForm_PostBackOptions(\"");
|
|
builder.Append(options.TargetControl.UniqueID);
|
|
builder.Append("\", ");
|
|
|
|
if (String.IsNullOrEmpty(options.Argument)) {
|
|
builder.Append("\"\", ");
|
|
}
|
|
else {
|
|
builder.Append("\"");
|
|
builder.Append(Util.QuoteJScriptString(options.Argument));
|
|
builder.Append("\", ");
|
|
}
|
|
|
|
if (options.PerformValidation) {
|
|
shouldRenderPostBackReferenceString = true;
|
|
builder.Append("true, ");
|
|
}
|
|
else {
|
|
builder.Append("false, ");
|
|
}
|
|
|
|
if (options.ValidationGroup != null && options.ValidationGroup.Length > 0) {
|
|
shouldRenderPostBackReferenceString = true;
|
|
|
|
builder.Append("\"");
|
|
builder.Append(options.ValidationGroup);
|
|
builder.Append("\", ");
|
|
}
|
|
else {
|
|
builder.Append("\"\", ");
|
|
}
|
|
|
|
if (options.ActionUrl != null && options.ActionUrl.Length > 0) {
|
|
shouldRenderPostBackReferenceString = true;
|
|
_owner.ContainsCrossPagePost = true;
|
|
|
|
builder.Append("\"");
|
|
builder.Append(Util.QuoteJScriptString(options.ActionUrl));
|
|
builder.Append("\", ");
|
|
}
|
|
else {
|
|
builder.Append("\"\", ");
|
|
}
|
|
|
|
if (options.TrackFocus) {
|
|
_owner.RegisterFocusScript();
|
|
shouldRenderPostBackReferenceString = true;
|
|
builder.Append("true, ");
|
|
}
|
|
else {
|
|
builder.Append("false, ");
|
|
}
|
|
|
|
if (options.ClientSubmit) {
|
|
shouldRenderPostBackReferenceString = true;
|
|
_owner.RegisterPostBackScript();
|
|
|
|
builder.Append("true))");
|
|
}
|
|
else {
|
|
builder.Append("false))");
|
|
}
|
|
|
|
if (options.AutoPostBack) {
|
|
builder.Append("', 0)");
|
|
}
|
|
|
|
string reference = null;
|
|
if (shouldRenderPostBackReferenceString) {
|
|
reference = builder.ToString();
|
|
_owner.RegisterWebFormsScript();
|
|
}
|
|
|
|
return reference;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Gets a URL resource reference to a client-side resource
|
|
/// </devdoc>
|
|
public string GetWebResourceUrl(Type type, string resourceName) {
|
|
return GetWebResourceUrl(_owner, type, resourceName, false,
|
|
(_owner == null ? null : _owner.ScriptManager));
|
|
}
|
|
|
|
internal static string GetWebResourceUrl(Page owner, Type type, string resourceName, bool htmlEncoded, IScriptManager scriptManager) {
|
|
bool enableCdn = scriptManager != null && scriptManager.EnableCdn;
|
|
return GetWebResourceUrl(owner, type, resourceName, htmlEncoded, scriptManager, enableCdn);
|
|
}
|
|
|
|
internal static string GetWebResourceUrl(Page owner, Type type, string resourceName, bool htmlEncoded, IScriptManager scriptManager, bool enableCdn) {
|
|
if (type == null) {
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
|
|
if (String.IsNullOrEmpty(resourceName)) {
|
|
throw new ArgumentNullException("resourceName");
|
|
}
|
|
|
|
if (owner != null && owner.DesignMode) {
|
|
ISite site = ((IComponent)owner).Site;
|
|
if (site != null) {
|
|
IResourceUrlGenerator urlGenerator = site.GetService(typeof(IResourceUrlGenerator)) as IResourceUrlGenerator;
|
|
if (urlGenerator != null) {
|
|
return urlGenerator.GetResourceUrl(type, resourceName);
|
|
}
|
|
}
|
|
|
|
return resourceName;
|
|
}
|
|
else {
|
|
return AssemblyResourceLoader.GetWebResourceUrl(type, resourceName, htmlEncoded, scriptManager, enableCdn: enableCdn);
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Determines if the client script block is registered with the page.</para>
|
|
/// </devdoc>
|
|
public bool IsClientScriptBlockRegistered(string key) {
|
|
return IsClientScriptBlockRegistered(typeof(Page), key);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Determines if the client script block is registered with the page.</para>
|
|
/// </devdoc>
|
|
public bool IsClientScriptBlockRegistered(Type type, string key) {
|
|
if (type == null) {
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
|
|
return (_registeredClientScriptBlocks != null
|
|
&& (_registeredClientScriptBlocks.Contains(CreateScriptKey(type, key))));
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Determines if the onsubmit script is registered with the page.</para>
|
|
/// </devdoc>
|
|
public bool IsClientScriptIncludeRegistered(string key) {
|
|
return IsClientScriptIncludeRegistered(typeof(Page), key);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Determines if the onsubmit script is registered with the page.</para>
|
|
/// </devdoc>
|
|
public bool IsClientScriptIncludeRegistered(Type type, string key) {
|
|
if (type == null) {
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
|
|
return (_registeredClientScriptBlocks != null
|
|
&& (_registeredClientScriptBlocks.Contains(CreateScriptIncludeKey(type, key, false))));
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Determines if the client startup script is registered with the
|
|
/// page.</para>
|
|
/// </devdoc>
|
|
public bool IsStartupScriptRegistered(string key) {
|
|
return IsStartupScriptRegistered(typeof(Page), key);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Determines if the client startup script is registered with the
|
|
/// page.</para>
|
|
/// </devdoc>
|
|
public bool IsStartupScriptRegistered(Type type, string key) {
|
|
if (type == null) {
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
|
|
return (_registeredClientStartupScripts != null
|
|
&& (_registeredClientStartupScripts.Contains(CreateScriptKey(type, key))));
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Determines if the onsubmit script is registered with the page.</para>
|
|
/// </devdoc>
|
|
public bool IsOnSubmitStatementRegistered(string key) {
|
|
return IsOnSubmitStatementRegistered(typeof(Page), key);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Determines if the onsubmit script is registered with the page.</para>
|
|
/// </devdoc>
|
|
public bool IsOnSubmitStatementRegistered(Type type, string key) {
|
|
if (type == null) {
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
|
|
return (_registeredOnSubmitStatements != null
|
|
&& (_registeredOnSubmitStatements.Contains(CreateScriptKey(type, key))));
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Declares a value that will be declared as a JavaScript array declaration
|
|
/// when the page renders. This can be used by script-based controls to declare
|
|
/// themselves within an array so that a client script library can work with
|
|
/// all the controls of the same type.</para>
|
|
/// </devdoc>
|
|
public void RegisterArrayDeclaration(string arrayName, string arrayValue) {
|
|
if (arrayName == null) {
|
|
throw new ArgumentNullException("arrayName");
|
|
}
|
|
if (_registeredArrayDeclares == null) {
|
|
_registeredArrayDeclares = new ListDictionary();
|
|
}
|
|
if (!_registeredArrayDeclares.Contains(arrayName)) {
|
|
_registeredArrayDeclares[arrayName] = new ArrayList();
|
|
}
|
|
|
|
ArrayList elements = (ArrayList)_registeredArrayDeclares[arrayName];
|
|
elements.Add(arrayValue);
|
|
|
|
// If there are any partial caching controls on the stack, forward the call to them
|
|
if (_owner.PartialCachingControlStack != null) {
|
|
foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) {
|
|
c.RegisterArrayDeclaration(arrayName, arrayValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
// RegisterArrayDeclaration implementation that supports partial rendering.
|
|
internal void RegisterArrayDeclaration(Control control, string arrayName, string arrayValue) {
|
|
IScriptManager scriptManager = _owner.ScriptManager;
|
|
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
|
|
scriptManager.RegisterArrayDeclaration(control, arrayName, arrayValue);
|
|
}
|
|
else {
|
|
RegisterArrayDeclaration(arrayName, arrayValue);
|
|
}
|
|
}
|
|
|
|
public void RegisterExpandoAttribute(string controlId, string attributeName, string attributeValue) {
|
|
RegisterExpandoAttribute(controlId, attributeName, attributeValue, true);
|
|
}
|
|
|
|
public void RegisterExpandoAttribute(string controlId, string attributeName, string attributeValue, bool encode) {
|
|
// check paramters
|
|
WebUtil.StringUtil.CheckAndTrimString(controlId, "controlId");
|
|
WebUtil.StringUtil.CheckAndTrimString(attributeName, "attributeName");
|
|
|
|
ListDictionary expandoAttributes = null;
|
|
if (_registeredControlsWithExpandoAttributes == null) {
|
|
_registeredControlsWithExpandoAttributes = new ListDictionary(StringComparer.Ordinal);
|
|
}
|
|
else {
|
|
expandoAttributes = (ListDictionary)_registeredControlsWithExpandoAttributes[controlId];
|
|
}
|
|
|
|
if (expandoAttributes == null) {
|
|
expandoAttributes = new ListDictionary(StringComparer.Ordinal);
|
|
_registeredControlsWithExpandoAttributes.Add(controlId, expandoAttributes);
|
|
}
|
|
|
|
if (encode) {
|
|
attributeValue = Util.QuoteJScriptString(attributeValue);
|
|
}
|
|
|
|
expandoAttributes.Add(attributeName, attributeValue);
|
|
|
|
// If there are any partial caching controls on the stack, forward the call to them
|
|
if (_owner.PartialCachingControlStack != null) {
|
|
foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) {
|
|
c.RegisterExpandoAttribute(controlId, attributeName, attributeValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
// RegisterExpandoAttribute implementation that supports partial rendering.
|
|
internal void RegisterExpandoAttribute(Control control, string controlId, string attributeName, string attributeValue, bool encode) {
|
|
IScriptManager scriptManager = _owner.ScriptManager;
|
|
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
|
|
scriptManager.RegisterExpandoAttribute(control, controlId, attributeName, attributeValue, encode);
|
|
}
|
|
else {
|
|
RegisterExpandoAttribute(controlId, attributeName, attributeValue, encode);
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Allows controls to automatically register a hidden field on the form. The
|
|
/// field will be emitted when the form control renders itself.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void RegisterHiddenField(string hiddenFieldName,
|
|
string hiddenFieldInitialValue) {
|
|
if (hiddenFieldName == null) {
|
|
throw new ArgumentNullException("hiddenFieldName");
|
|
}
|
|
if (_registeredHiddenFields == null)
|
|
_registeredHiddenFields = new ListDictionary();
|
|
|
|
if (!_registeredHiddenFields.Contains(hiddenFieldName))
|
|
_registeredHiddenFields.Add(hiddenFieldName, hiddenFieldInitialValue);
|
|
if (_owner._hiddenFieldsToRender == null) {
|
|
_owner._hiddenFieldsToRender = new Dictionary<String, String>();
|
|
}
|
|
_owner._hiddenFieldsToRender[hiddenFieldName] = hiddenFieldInitialValue;
|
|
|
|
// If there are any partial caching controls on the stack, forward the call to them
|
|
if (_owner.PartialCachingControlStack != null) {
|
|
foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) {
|
|
c.RegisterHiddenField(hiddenFieldName, hiddenFieldInitialValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
// RegisterHiddenField implementation that supports partial rendering.
|
|
internal void RegisterHiddenField(Control control, string hiddenFieldName, string hiddenFieldValue) {
|
|
IScriptManager scriptManager = _owner.ScriptManager;
|
|
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
|
|
scriptManager.RegisterHiddenField(control, hiddenFieldName, hiddenFieldValue);
|
|
}
|
|
else {
|
|
RegisterHiddenField(hiddenFieldName, hiddenFieldValue);
|
|
}
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// Prevents controls from sending duplicate blocks of
|
|
/// client-side script to the client. Any script blocks with the same type and key
|
|
/// values are considered duplicates.</para>
|
|
/// </devdoc>
|
|
public void RegisterClientScriptBlock(Type type, string key, string script) {
|
|
RegisterClientScriptBlock(type, key, script, false);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Prevents controls from sending duplicate blocks of
|
|
/// client-side script to the client. Any script blocks with the same type and key
|
|
/// values are considered duplicates.</para>
|
|
/// </devdoc>
|
|
public void RegisterClientScriptBlock(Type type, string key, string script, bool addScriptTags) {
|
|
if (type == null) {
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
|
|
if (addScriptTags) {
|
|
RegisterScriptBlock(CreateScriptKey(type, key), script, ClientAPIRegisterType.ClientScriptBlocksWithoutTags);
|
|
}
|
|
else {
|
|
RegisterScriptBlock(CreateScriptKey(type, key), script, ClientAPIRegisterType.ClientScriptBlocks);
|
|
}
|
|
}
|
|
|
|
// RegisterClientScriptBlock implementation that supports partial rendering.
|
|
internal void RegisterClientScriptBlock(Control control, Type type, string key, string script, bool addScriptTags) {
|
|
IScriptManager scriptManager = _owner.ScriptManager;
|
|
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
|
|
scriptManager.RegisterClientScriptBlock(control, type, key, script, addScriptTags);
|
|
}
|
|
else {
|
|
RegisterClientScriptBlock(type, key, script, addScriptTags);
|
|
}
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// <para> Prevents controls from sending duplicate blocks of
|
|
/// client-side script to the client. Any script blocks with the same <paramref name="key"/> parameter
|
|
/// values are considered duplicates.</para>
|
|
/// </devdoc>
|
|
public void RegisterClientScriptInclude(string key, string url) {
|
|
RegisterClientScriptInclude(typeof(Page), key, url);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Prevents controls from sending duplicate blocks of
|
|
/// client-side script to the client. Any script blocks with the same type and key
|
|
/// values are considered duplicates.</para>
|
|
/// </devdoc>
|
|
public void RegisterClientScriptInclude(Type type, string key, string url) {
|
|
RegisterClientScriptInclude(type, key, url, false);
|
|
}
|
|
|
|
internal void RegisterClientScriptInclude(Type type, string key, string url, bool isResource) {
|
|
if (type == null) {
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
if (String.IsNullOrEmpty(url)) {
|
|
throw ExceptionUtil.ParameterNullOrEmpty("url");
|
|
}
|
|
|
|
// VSWhidbey 499036: encode the url
|
|
string script = IncludeScriptBegin + HttpUtility.HtmlAttributeEncode(url) + IncludeScriptEnd;
|
|
RegisterScriptBlock(CreateScriptIncludeKey(type, key, isResource), script, ClientAPIRegisterType.ClientScriptBlocks);
|
|
}
|
|
|
|
// RegisterClientScriptInclude implementation that supports partial rendering.
|
|
internal void RegisterClientScriptInclude(Control control, Type type, string key, string url) {
|
|
IScriptManager scriptManager = _owner.ScriptManager;
|
|
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
|
|
scriptManager.RegisterClientScriptInclude(control, type, key, url);
|
|
}
|
|
else {
|
|
RegisterClientScriptInclude(type, key, url);
|
|
}
|
|
}
|
|
|
|
|
|
/// <devdoc>
|
|
/// </devdoc>
|
|
public void RegisterClientScriptResource(Type type, string resourceName) {
|
|
if (type == null) {
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
|
|
RegisterClientScriptInclude(type, resourceName, GetWebResourceUrl(type, resourceName), true);
|
|
}
|
|
|
|
// RegisterClientScriptResource implementation that supports partial rendering.
|
|
internal void RegisterClientScriptResource(Control control, Type type, string resourceName) {
|
|
IScriptManager scriptManager = _owner.ScriptManager;
|
|
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
|
|
scriptManager.RegisterClientScriptResource(control, type, resourceName);
|
|
}
|
|
else {
|
|
RegisterClientScriptResource(type, resourceName);
|
|
}
|
|
}
|
|
|
|
|
|
internal void RegisterDefaultButtonScript(Control button, HtmlTextWriter writer, bool useAddAttribute) {
|
|
_owner.RegisterWebFormsScript();
|
|
if (_owner.EnableLegacyRendering) {
|
|
if (useAddAttribute) {
|
|
writer.AddAttribute("language", "javascript", false);
|
|
}
|
|
else {
|
|
writer.WriteAttribute("language", "javascript", false);
|
|
}
|
|
}
|
|
string keyPress = "javascript:return WebForm_FireDefaultButton(event, '" + button.ClientID + "')";
|
|
if (useAddAttribute) {
|
|
writer.AddAttribute("onkeypress", keyPress);
|
|
}
|
|
else {
|
|
writer.WriteAttribute("onkeypress", keyPress);
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Allows a control to access a the client
|
|
/// <see langword='onsubmit'/> event.
|
|
/// The script should be a function call to client code registered elsewhere.</para>
|
|
/// </devdoc>
|
|
public void RegisterOnSubmitStatement(Type type, string key, string script) {
|
|
if (type == null) {
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
|
|
RegisterOnSubmitStatementInternal(CreateScriptKey(type, key), script);
|
|
}
|
|
|
|
|
|
// RegisterOnSubmitStatement implementation that supports partial rendering.
|
|
internal void RegisterOnSubmitStatement(Control control, Type type, string key, string script) {
|
|
IScriptManager scriptManager = _owner.ScriptManager;
|
|
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
|
|
scriptManager.RegisterOnSubmitStatement(control, type, key, script);
|
|
}
|
|
else {
|
|
RegisterOnSubmitStatement(type, key, script);
|
|
}
|
|
}
|
|
|
|
|
|
internal void RegisterOnSubmitStatementInternal(ScriptKey key, string script) {
|
|
if (String.IsNullOrEmpty(script)) {
|
|
throw ExceptionUtil.ParameterNullOrEmpty("script");
|
|
}
|
|
if (_registeredOnSubmitStatements == null)
|
|
_registeredOnSubmitStatements = new ListDictionary();
|
|
|
|
// Make sure the script block ends in a semicolon
|
|
int index = script.Length - 1;
|
|
while ((index >= 0) && Char.IsWhiteSpace(script, index)) {
|
|
index--;
|
|
}
|
|
|
|
if ((index >= 0) && (script[index] != ';')) {
|
|
script = script.Substring(0, index + 1) + ";" + script.Substring(index + 1);
|
|
}
|
|
|
|
if (!_registeredOnSubmitStatements.Contains(key))
|
|
_registeredOnSubmitStatements.Add(key, script);
|
|
|
|
// If there are any partial caching controls on the stack, forward the call to them
|
|
if (_owner.PartialCachingControlStack != null) {
|
|
foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) {
|
|
c.RegisterOnSubmitStatement(key, script);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void RegisterScriptBlock(ScriptKey key, string script, ClientAPIRegisterType type) {
|
|
|
|
// Call RegisterScriptBlock with the correct collection based on the blockType
|
|
switch (type) {
|
|
case ClientAPIRegisterType.ClientScriptBlocks:
|
|
RegisterScriptBlock(key, script, ref _registeredClientScriptBlocks, ref _clientScriptBlocks, false);
|
|
break;
|
|
case ClientAPIRegisterType.ClientScriptBlocksWithoutTags:
|
|
RegisterScriptBlock(key, script, ref _registeredClientScriptBlocks, ref _clientScriptBlocks, true);
|
|
break;
|
|
case ClientAPIRegisterType.ClientStartupScripts:
|
|
RegisterScriptBlock(key, script, ref _registeredClientStartupScripts, ref _clientStartupScripts, false);
|
|
break;
|
|
case ClientAPIRegisterType.ClientStartupScriptsWithoutTags:
|
|
RegisterScriptBlock(key, script, ref _registeredClientStartupScripts, ref _clientStartupScripts, true);
|
|
break;
|
|
default:
|
|
Debug.Assert(false);
|
|
break;
|
|
}
|
|
|
|
// If there are any partial caching controls on the stack, forward the call to them
|
|
if (_owner.PartialCachingControlStack != null) {
|
|
foreach (BasePartialCachingControl c in _owner.PartialCachingControlStack) {
|
|
c.RegisterScriptBlock(type, key, script);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RegisterScriptBlock(ScriptKey key, string script, ref ListDictionary scriptBlocks, ref ArrayList scriptList, bool needsScriptTags) {
|
|
if (scriptBlocks == null) {
|
|
scriptBlocks = new ListDictionary();
|
|
scriptList = new ArrayList();
|
|
}
|
|
|
|
if (!scriptBlocks.Contains(key)) {
|
|
Tuple<ScriptKey, String, Boolean> entry = new Tuple<ScriptKey, String, Boolean>(key, script, needsScriptTags);
|
|
scriptBlocks.Add(key, null);
|
|
scriptList.Add(entry);
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Allows controls to keep duplicate blocks of client-side script code from
|
|
/// being sent to the client. Any script blocks with the same type and key
|
|
/// value are considered duplicates.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void RegisterStartupScript(Type type, string key, string script) {
|
|
RegisterStartupScript(type, key, script, false);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Allows controls to keep duplicate blocks of client-side script code from
|
|
/// being sent to the client. Any script blocks with the same type and key
|
|
/// value are considered duplicates.
|
|
/// </para>
|
|
/// </devdoc>
|
|
public void RegisterStartupScript(Type type, string key, string script, bool addScriptTags) {
|
|
if (type == null) {
|
|
throw new ArgumentNullException("type");
|
|
}
|
|
|
|
if (addScriptTags) {
|
|
RegisterScriptBlock(CreateScriptKey(type, key), script, ClientAPIRegisterType.ClientStartupScriptsWithoutTags);
|
|
}
|
|
else {
|
|
RegisterScriptBlock(CreateScriptKey(type, key), script, ClientAPIRegisterType.ClientStartupScripts);
|
|
}
|
|
}
|
|
|
|
// RegisterStartupScript implementation that supports partial rendering.
|
|
internal void RegisterStartupScript(Control control, Type type, string key, string script, bool addScriptTags) {
|
|
IScriptManager scriptManager = _owner.ScriptManager;
|
|
if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
|
|
scriptManager.RegisterStartupScript(control, type, key, script, addScriptTags);
|
|
}
|
|
else {
|
|
RegisterStartupScript(type, key, script, addScriptTags);
|
|
}
|
|
}
|
|
|
|
|
|
internal void RenderArrayDeclares(HtmlTextWriter writer) {
|
|
if (_registeredArrayDeclares == null || _registeredArrayDeclares.Count == 0) {
|
|
return;
|
|
}
|
|
|
|
writer.Write(_owner.EnableLegacyRendering ? ClientScriptStartLegacy : ClientScriptStart);
|
|
|
|
// Write out each array
|
|
IDictionaryEnumerator arrays = _registeredArrayDeclares.GetEnumerator();
|
|
while (arrays.MoveNext()) {
|
|
// Write the declaration
|
|
writer.Write("var ");
|
|
writer.Write(arrays.Key);
|
|
writer.Write(" = new Array(");
|
|
|
|
// Write each element
|
|
IEnumerator elements = ((ArrayList)arrays.Value).GetEnumerator();
|
|
bool first = true;
|
|
while (elements.MoveNext()) {
|
|
if (first) {
|
|
first = false;
|
|
}
|
|
else {
|
|
writer.Write(", ");
|
|
}
|
|
writer.Write(elements.Current);
|
|
}
|
|
|
|
// Close the declaration
|
|
writer.WriteLine(");");
|
|
}
|
|
|
|
writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd);
|
|
}
|
|
|
|
internal void RenderExpandoAttribute(HtmlTextWriter writer) {
|
|
if (_registeredControlsWithExpandoAttributes == null ||
|
|
_registeredControlsWithExpandoAttributes.Count == 0) {
|
|
return;
|
|
}
|
|
|
|
writer.Write(_owner.EnableLegacyRendering ? ClientScriptStartLegacy : ClientScriptStart);
|
|
|
|
foreach (DictionaryEntry controlEntry in _registeredControlsWithExpandoAttributes) {
|
|
string controlId = (string)controlEntry.Key;
|
|
writer.Write("var ");
|
|
writer.Write(controlId);
|
|
writer.Write(" = document.all ? document.all[\"");
|
|
writer.Write(controlId);
|
|
writer.Write("\"] : document.getElementById(\"");
|
|
writer.Write(controlId);
|
|
writer.WriteLine("\");");
|
|
|
|
ListDictionary expandoAttributes = (ListDictionary)controlEntry.Value;
|
|
Debug.Assert(expandoAttributes != null && expandoAttributes.Count > 0);
|
|
foreach (DictionaryEntry expandoAttribute in expandoAttributes) {
|
|
writer.Write(controlId);
|
|
writer.Write(".");
|
|
writer.Write(expandoAttribute.Key);
|
|
if (expandoAttribute.Value == null) {
|
|
// VSWhidbey 382151 Render out null string for nulls
|
|
writer.WriteLine(" = null;");
|
|
}
|
|
else {
|
|
writer.Write(" = \"");
|
|
writer.Write(expandoAttribute.Value);
|
|
writer.WriteLine("\";");
|
|
}
|
|
}
|
|
}
|
|
|
|
writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd);
|
|
}
|
|
|
|
internal void RenderHiddenFields(HtmlTextWriter writer) {
|
|
if (_registeredHiddenFields == null || _registeredHiddenFields.Count == 0) {
|
|
return;
|
|
}
|
|
|
|
foreach (DictionaryEntry entry in _registeredHiddenFields) {
|
|
string entryKey = (string)entry.Key;
|
|
if (entryKey == null) {
|
|
entryKey = String.Empty;
|
|
}
|
|
writer.WriteLine();
|
|
writer.Write("<input type=\"hidden\" name=\"");
|
|
writer.Write(entryKey);
|
|
writer.Write("\" id=\"");
|
|
writer.Write(entryKey);
|
|
writer.Write("\" value=\"");
|
|
HttpUtility.HtmlEncode((string)entry.Value, writer);
|
|
writer.Write("\" />");
|
|
}
|
|
|
|
ClearHiddenFields();
|
|
}
|
|
|
|
internal void RenderClientScriptBlocks(HtmlTextWriter writer) {
|
|
bool inScriptBlock = false;
|
|
if (_clientScriptBlocks != null) {
|
|
inScriptBlock = RenderRegisteredScripts(writer, _clientScriptBlocks, true);
|
|
}
|
|
|
|
// Emit the onSubmit function, in necessary
|
|
if (!String.IsNullOrEmpty(_owner.ClientOnSubmitEvent) && _owner.ClientSupportsJavaScript) {
|
|
// If we were already inside a script tag, don't emit a new open script tag
|
|
if (!inScriptBlock) {
|
|
writer.Write(_owner.EnableLegacyRendering ? ClientScriptStartLegacy : ClientScriptStart);
|
|
}
|
|
|
|
writer.Write(@"function WebForm_OnSubmit() {
|
|
");
|
|
if (_registeredOnSubmitStatements != null) {
|
|
foreach (string s in _registeredOnSubmitStatements.Values) {
|
|
writer.Write(s);
|
|
}
|
|
}
|
|
writer.WriteLine(@"
|
|
return true;
|
|
}");
|
|
// We always need to close the script tag
|
|
writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd);
|
|
}
|
|
// If there was no onSubmit function, close the script tag if needed
|
|
else if (inScriptBlock) {
|
|
writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd);
|
|
}
|
|
}
|
|
|
|
internal void RenderClientStartupScripts(HtmlTextWriter writer) {
|
|
if (_clientStartupScripts != null) {
|
|
bool inScriptBlock = RenderRegisteredScripts(writer, _clientStartupScripts, false);
|
|
// Close the script tag if needed
|
|
if (inScriptBlock) {
|
|
writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd);
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool RenderRegisteredScripts(HtmlTextWriter writer, ArrayList scripts, bool checkForScriptManagerRegistrations) {
|
|
writer.WriteLine();
|
|
bool inScriptBlock = false;
|
|
checkForScriptManagerRegistrations &= (_registeredResourcesToSuppress != null);
|
|
// Write out each registered script block
|
|
foreach (Tuple<ScriptKey, String, Boolean> entry in scripts) {
|
|
if (checkForScriptManagerRegistrations) {
|
|
ScriptKey scriptKey = entry.Item1;
|
|
if (scriptKey.IsResource) {
|
|
Dictionary<String, Object> resources;
|
|
if (_registeredResourcesToSuppress.TryGetValue(scriptKey.Assembly, out resources)
|
|
&& resources.ContainsKey(scriptKey.Key)) {
|
|
// this is a suppressed resource
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if (entry.Item3) {
|
|
if (!inScriptBlock) {
|
|
// If we need script tags and we're not in a script tag, emit a start script tag
|
|
writer.Write(_owner.EnableLegacyRendering ? ClientScriptStartLegacy : ClientScriptStart);
|
|
inScriptBlock = true;
|
|
}
|
|
}
|
|
else if (inScriptBlock) {
|
|
// If we don't need script tags, and we're in a script tag, emit an end script tag
|
|
writer.Write(_owner.EnableLegacyRendering ? ClientScriptEndLegacy : ClientScriptEnd);
|
|
inScriptBlock = false;
|
|
}
|
|
writer.Write(entry.Item2);
|
|
}
|
|
return inScriptBlock;
|
|
}
|
|
|
|
internal void RenderWebFormsScript(HtmlTextWriter writer) {
|
|
const string webFormScript = "WebForms.js";
|
|
if (_registeredResourcesToSuppress != null) {
|
|
Dictionary<String, Object> systemWebResources;
|
|
if (_registeredResourcesToSuppress.TryGetValue(AssemblyResourceLoader.GetAssemblyFromType(typeof(Page)),
|
|
out systemWebResources) &&
|
|
systemWebResources.ContainsKey("WebForms.js")) {
|
|
return;
|
|
}
|
|
}
|
|
writer.Write(IncludeScriptBegin);
|
|
writer.Write(GetWebResourceUrl(_owner, typeof(Page), webFormScript, htmlEncoded: true, scriptManager: _owner.ScriptManager));
|
|
writer.Write(IncludeScriptEnd);
|
|
|
|
// Render the fallback script for WebForm.js
|
|
if (_owner.ScriptManager != null && _owner.ScriptManager.EnableCdn && _owner.ScriptManager.EnableCdnFallback) {
|
|
var localPath = GetWebResourceUrl(_owner, typeof(Page), webFormScript, htmlEncoded: true, scriptManager: _owner.ScriptManager, enableCdn: false);
|
|
if (!String.IsNullOrEmpty(localPath)) {
|
|
writer.Write(ClientScriptStart);
|
|
writer.Write(@"window.WebForm_PostBackOptions||document.write('<script type=""text/javascript"" src=""" + localPath + @"""><\/script>');");
|
|
writer.Write(ClientScriptEnd);
|
|
}
|
|
}
|
|
writer.WriteLine();
|
|
}
|
|
|
|
private interface IEventValidationProvider {
|
|
// Gets an object that - when serialized and encrypted - is the outbound __EVENTVALIDATION field value.
|
|
object GetEventValidationStoreObject();
|
|
|
|
// Returns a value denoting whether this (uniqueId, argument) tuple is valid for the current postback.
|
|
bool IsValid(string uniqueId, string argument);
|
|
|
|
// Registers the tuple (uniqueId, argument) as a valid event for the next postback.
|
|
void RegisterForEventValidation(string uniqueId, string argument);
|
|
|
|
// Given the deserialized form of an incoming __EVENTVALIDATION field, tries to load the valid
|
|
// event references for this postback. Returns true on success, false on failure.
|
|
bool TryLoadEventValidationField(object eventValidationField);
|
|
}
|
|
|
|
// provides a more secure implementation of event validation (fix for DevDiv #233564)
|
|
private sealed class DefaultEventValidationProvider : IEventValidationProvider {
|
|
private readonly ClientScriptManager _clientScriptManager;
|
|
private EventValidationStore _inboundEvents; // events which are valid for the current postback
|
|
private EventValidationStore _outboundEvents; // events which will be valid on the next postback
|
|
|
|
internal DefaultEventValidationProvider(ClientScriptManager clientScriptManager) {
|
|
_clientScriptManager = clientScriptManager;
|
|
}
|
|
|
|
public object GetEventValidationStoreObject() {
|
|
// We only produce the object to be serialized if there is data in the store
|
|
if (_outboundEvents != null && _outboundEvents.Count > 0) {
|
|
return _outboundEvents;
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public bool IsValid(string uniqueId, string argument) {
|
|
return _inboundEvents != null && _inboundEvents.Contains(uniqueId, argument);
|
|
}
|
|
|
|
public void RegisterForEventValidation(string uniqueId, string argument) {
|
|
if (_outboundEvents == null) {
|
|
if (_clientScriptManager._owner.IsCallback) {
|
|
_clientScriptManager.EnsureEventValidationFieldLoaded();
|
|
|
|
// _outboundEvents could have been initialized by the call to EnsureEventValidationFieldLoaded.
|
|
if (_outboundEvents == null) {
|
|
_outboundEvents = new EventValidationStore();
|
|
}
|
|
}
|
|
else {
|
|
// Make a new store object and tie it to the outbound __VIEWSTATE field.
|
|
// (This is the only field which can have a null/empty 'target'.)
|
|
_outboundEvents = new EventValidationStore();
|
|
_outboundEvents.Add(null, _clientScriptManager._owner.ClientState);
|
|
}
|
|
}
|
|
|
|
_outboundEvents.Add(uniqueId, argument);
|
|
}
|
|
|
|
public bool TryLoadEventValidationField(object eventValidationField) {
|
|
EventValidationStore validatedIncomingEvents = eventValidationField as EventValidationStore;
|
|
if (validatedIncomingEvents == null || validatedIncomingEvents.Count < 1) {
|
|
return true; // empty collection is not an error condition
|
|
}
|
|
|
|
Debug.Assert(_outboundEvents == null);
|
|
|
|
string viewStateString = _clientScriptManager._owner.RequestViewStateString;
|
|
if (!validatedIncomingEvents.Contains(null, viewStateString)) {
|
|
return false; // error: this event validation store isn't associated with the incoming __VIEWSTATE
|
|
}
|
|
_inboundEvents = validatedIncomingEvents;
|
|
|
|
if (_clientScriptManager._owner.IsCallback) {
|
|
// Seed the outbound provider with the valid inbound values; clone so that any outbound values
|
|
// added during page processing aren't accidentally treated as valid inbound values.
|
|
EventValidationStore clonedEventValidationStore = validatedIncomingEvents.Clone();
|
|
_outboundEvents = clonedEventValidationStore;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// provides the legacy implementation of event validation (before DevDiv #233564)
|
|
private sealed class LegacyEventValidationProvider : IEventValidationProvider {
|
|
private readonly ClientScriptManager _clientScriptManager;
|
|
private ArrayList _validEventReferences;
|
|
private HybridDictionary _clientPostBackValidatedEventTable;
|
|
|
|
internal LegacyEventValidationProvider(ClientScriptManager clientScriptManager) {
|
|
_clientScriptManager = clientScriptManager;
|
|
}
|
|
|
|
private static int ComputeHashKey(String uniqueId, String argument) {
|
|
if (String.IsNullOrEmpty(argument)) {
|
|
return StringUtil.GetStringHashCode(uniqueId);
|
|
}
|
|
|
|
return StringUtil.GetStringHashCode(uniqueId) ^ StringUtil.GetStringHashCode(argument);
|
|
}
|
|
|
|
public object GetEventValidationStoreObject() {
|
|
// We only produce the object to be serialized if there is data in the store
|
|
if (_validEventReferences != null && _validEventReferences.Count > 0) {
|
|
return _validEventReferences;
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public bool IsValid(string uniqueId, string argument) {
|
|
if (_clientPostBackValidatedEventTable == null) {
|
|
return false;
|
|
}
|
|
|
|
#if DEBUGEVENTVALIDATION
|
|
String hashCode = uniqueId + "@" + argument;
|
|
#else
|
|
int hashCode = ComputeHashKey(uniqueId, argument);
|
|
#endif //DEBUGEVENTVALIDATION
|
|
|
|
return _clientPostBackValidatedEventTable.Contains(hashCode);
|
|
}
|
|
|
|
public void RegisterForEventValidation(string uniqueId, string argument) {
|
|
#if DEBUGEVENTVALIDATION
|
|
string key = uniqueId + "@" + argument;
|
|
#else
|
|
int key = ComputeHashKey(uniqueId, argument);
|
|
#endif //DEBUGEVENTVALIDATION
|
|
|
|
string stateString = _clientScriptManager._owner.ClientState;
|
|
if (stateString == null) {
|
|
stateString = String.Empty;
|
|
}
|
|
|
|
if (_validEventReferences == null) {
|
|
if (_clientScriptManager._owner.IsCallback) {
|
|
_clientScriptManager.EnsureEventValidationFieldLoaded();
|
|
if (_validEventReferences == null) {
|
|
_validEventReferences = new ArrayList();
|
|
}
|
|
}
|
|
else {
|
|
_validEventReferences = new ArrayList();
|
|
_validEventReferences.Add(
|
|
StringUtil.GetStringHashCode(stateString));
|
|
}
|
|
}
|
|
|
|
#if DEBUGEVENTVALIDATION
|
|
Debug.Assert(!_validEventReferences.Contains(key));
|
|
#endif //DEBUGEVENTVALIDATION
|
|
|
|
_validEventReferences.Add(key);
|
|
}
|
|
|
|
public bool TryLoadEventValidationField(object eventValidationField) {
|
|
ArrayList validatedClientEvents = eventValidationField as ArrayList;
|
|
if (validatedClientEvents == null || validatedClientEvents.Count < 1) {
|
|
return true; // empty collection is not an error condition
|
|
}
|
|
|
|
Debug.Assert(_clientPostBackValidatedEventTable == null);
|
|
int viewStateHashCode = (int)validatedClientEvents[0];
|
|
|
|
string viewStateString = _clientScriptManager._owner.RequestViewStateString;
|
|
|
|
if (viewStateHashCode != StringUtil.GetStringHashCode(viewStateString)) {
|
|
return false; // hash mismatch is an error condition
|
|
}
|
|
|
|
_clientPostBackValidatedEventTable = new HybridDictionary(validatedClientEvents.Count - 1, true);
|
|
|
|
// Ignore the first item in the arrayList, which is the controlstate
|
|
for (int index = 1; index < validatedClientEvents.Count; index++) {
|
|
#if DEBUGEVENTVALIDATION
|
|
string hashKey = (string)validatedClientEvents[index];
|
|
#else
|
|
int hashKey = (int)validatedClientEvents[index];
|
|
#endif //DEBUGEVENTVALIDATION
|
|
_clientPostBackValidatedEventTable[hashKey] = null;
|
|
}
|
|
|
|
if (_clientScriptManager._owner.IsCallback) {
|
|
_validEventReferences = validatedClientEvents;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
[Serializable]
|
|
internal class ScriptKey {
|
|
[NonSerialized]
|
|
private Type _type;
|
|
private string _typeNameForSerialization;
|
|
private string _key;
|
|
private bool _isInclude;
|
|
private bool _isResource;
|
|
|
|
internal ScriptKey(Type type, string key) : this(type, key, false, false) {
|
|
}
|
|
|
|
internal ScriptKey(Type type, string key, bool isInclude, bool isResource) {
|
|
Debug.Assert(type != null);
|
|
_type = type;
|
|
|
|
// To treat nulls the same as empty strings, make them empty string.
|
|
if (key == null) {
|
|
key = String.Empty;
|
|
}
|
|
_key = key;
|
|
_isInclude = isInclude;
|
|
_isResource = isResource;
|
|
}
|
|
|
|
public Assembly Assembly {
|
|
get {
|
|
return _type == null ? null : AssemblyResourceLoader.GetAssemblyFromType(_type);
|
|
}
|
|
}
|
|
|
|
public bool IsResource {
|
|
get {
|
|
return _isResource;
|
|
}
|
|
}
|
|
|
|
public string Key {
|
|
get {
|
|
return _key;
|
|
}
|
|
}
|
|
|
|
public override int GetHashCode() {
|
|
return WebUtil.HashCodeCombiner.CombineHashCodes(_type.GetHashCode(), _key.GetHashCode(),
|
|
_isInclude.GetHashCode());
|
|
}
|
|
|
|
public override bool Equals(object o) {
|
|
ScriptKey key = (ScriptKey)o;
|
|
return (key._type == _type) && (key._key == _key) && (key._isInclude == _isInclude);
|
|
}
|
|
|
|
[OnSerializing()]
|
|
private void OnSerializingMethod(StreamingContext context) {
|
|
// create a string representation of _type
|
|
_typeNameForSerialization = System.Web.UI.Util.GetAssemblyQualifiedTypeName(_type);
|
|
}
|
|
|
|
[OnDeserialized()]
|
|
private void OnDeserializedMethod(StreamingContext context) {
|
|
// re-create _type from its string representation
|
|
_type = BuildManager.GetType(_typeNameForSerialization, true /*throwOnFail*/, false /*ignoreCase*/);
|
|
}
|
|
}
|
|
}
|