1 //
2 // System.Web.UI.ClientScriptManager.cs
3 //
4 // Authors:
5 //   Duncan Mak  (duncan@ximian.com)
6 //   Gonzalo Paniagua (gonzalo@ximian.com)
7 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
8 //   Lluis Sanchez (lluis@novell.com)
9 //
10 // (C) 2002,2003 Ximian, Inc. (http://www.ximian.com)
11 // (c) 2003-2010 Novell, Inc. (http://www.novell.com)
12 //
13 
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 //
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 //
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34 
35 using System;
36 using System.Collections;
37 using System.Collections.Generic;
38 using System.Text;
39 using System.Collections.Specialized;
40 using System.Web.Util;
41 using System.Globalization;
42 
43 namespace System.Web.UI
44 {
45 	public sealed partial class ClientScriptManager
46 	{
47 		internal const string EventStateFieldName = "__EVENTVALIDATION";
48 
49 		Hashtable registeredArrayDeclares;
50 		ScriptEntry clientScriptBlocks;
51 		ScriptEntry startupScriptBlocks;
52 		internal Hashtable hiddenFields;
53 		ScriptEntry submitStatements;
54 		Page ownerPage;
55 		int [] eventValidationValues;
56 		int eventValidationPos = 0;
57 		Hashtable expandoAttributes;
58 		bool _hasRegisteredForEventValidationOnCallback;
59 		bool _pageInRender;
60 		bool _initCallBackRegistered;
61 		bool _webFormClientScriptRendered;
62 		bool _webFormClientScriptRequired;
63 
64 		internal bool ScriptsPresent {
65 			get {
66 				return _webFormClientScriptRequired ||
67 					_initCallBackRegistered ||
68 					_hasRegisteredForEventValidationOnCallback ||
69 					clientScriptBlocks != null ||
70 					startupScriptBlocks != null ||
71 					submitStatements != null ||
72 					registeredArrayDeclares != null ||
73 					expandoAttributes != null;
74 			}
75 		}
76 
77 		Page OwnerPage {
78 			get {
79 				if (ownerPage == null)
80 					throw new InvalidOperationException ("Associated Page instance is required to complete this operation.");
81 				return ownerPage;
82 			}
83 		}
84 
ClientScriptManager(Page page)85 		internal ClientScriptManager (Page page)
86 		{
87 			this.ownerPage = page;
88 		}
89 
GetPostBackClientHyperlink(Control control, string argument)90 		public string GetPostBackClientHyperlink (Control control, string argument)
91 		{
92 			return "javascript:" + GetPostBackEventReference (control, argument);
93 		}
94 
GetPostBackClientHyperlink(Control control, string argument, bool registerForEventValidation)95 		public string GetPostBackClientHyperlink (Control control, string argument, bool registerForEventValidation)
96 		{
97 			if (registerForEventValidation)
98 				RegisterForEventValidation (control.UniqueID, argument);
99 			return "javascript:" + GetPostBackEventReference (control, argument);
100 		}
101 
GetPostBackEventReference(Control control, string argument)102 		public string GetPostBackEventReference (Control control, string argument)
103 		{
104 			if (control == null)
105 				throw new ArgumentNullException ("control");
106 
107 			Page page = OwnerPage;
108 			page.RequiresPostBackScript ();
109 			if(page.IsMultiForm)
110 				return page.theForm + ".__doPostBack('" + control.UniqueID + "','" + argument + "')";
111 			else
112 				return "__doPostBack('" + control.UniqueID + "','" + argument + "')";
113 		}
114 
GetPostBackEventReference(Control control, string argument, bool registerForEventValidation)115 		public string GetPostBackEventReference (Control control, string argument, bool registerForEventValidation)
116 		{
117 			if (control == null)
118 				throw new ArgumentNullException ("control");
119 
120 			if (registerForEventValidation)
121 				RegisterForEventValidation (control.UniqueID, argument);
122 			return GetPostBackEventReference (control, argument);
123 		}
124 
GetPostBackEventReference(PostBackOptions options, bool registerForEventValidation)125 		public string GetPostBackEventReference (PostBackOptions options, bool registerForEventValidation)
126 		{
127 			if (options == null)
128 				throw new ArgumentNullException ("options");
129 			if (registerForEventValidation)
130 				RegisterForEventValidation (options);
131 			return GetPostBackEventReference (options);
132 		}
133 
GetPostBackEventReference(PostBackOptions options)134 		public string GetPostBackEventReference (PostBackOptions options)
135 		{
136 			if (options == null)
137 				throw new ArgumentNullException ("options");
138 
139 			string actionUrl = options.ActionUrl;
140 			if (actionUrl == null && options.ValidationGroup == null && !options.TrackFocus &&
141 				!options.AutoPostBack && !options.PerformValidation)
142 			{
143 				if (!options.ClientSubmit)
144 					return null;
145 
146 				if (options.RequiresJavaScriptProtocol)
147 					return GetPostBackClientHyperlink (options.TargetControl, options.Argument);
148 				else
149 					return GetPostBackEventReference (options.TargetControl, options.Argument);
150 			}
151 
152 			RegisterWebFormClientScript ();
153 
154 			Page page = OwnerPage;
155 			HttpRequest req = page.RequestInternal;
156 			Uri pageUrl = req != null ? req.Url : null;
157 			if (pageUrl != null)
158 				RegisterHiddenField (Page.PreviousPageID, pageUrl.AbsolutePath);
159 
160 			if(options.TrackFocus)
161 				RegisterHiddenField (Page.LastFocusID, String.Empty);
162 
163 			string prefix = options.RequiresJavaScriptProtocol ? "javascript:" : String.Empty;
164 			if (page.IsMultiForm)
165 				prefix += page.theForm + ".";
166 
167 			return prefix + "WebForm_DoPostback(" +
168 				ClientScriptManager.GetScriptLiteral (options.TargetControl.UniqueID) + "," +
169 				ClientScriptManager.GetScriptLiteral (options.Argument) + "," +
170 				ClientScriptManager.GetScriptLiteral (actionUrl) + "," +
171 				ClientScriptManager.GetScriptLiteral (options.AutoPostBack) + "," +
172 				ClientScriptManager.GetScriptLiteral (options.PerformValidation) + "," +
173 				ClientScriptManager.GetScriptLiteral (options.TrackFocus) + "," +
174 				ClientScriptManager.GetScriptLiteral (options.ClientSubmit) + "," +
175 				ClientScriptManager.GetScriptLiteral (options.ValidationGroup) + ")";
176 		}
177 
RegisterWebFormClientScript()178 		internal void RegisterWebFormClientScript ()
179 		{
180 			if (_webFormClientScriptRequired)
181 				return;
182 
183 			OwnerPage.RequiresPostBackScript ();
184 			_webFormClientScriptRequired = true;
185 		}
186 
WriteWebFormClientScript(HtmlTextWriter writer)187 		internal void WriteWebFormClientScript (HtmlTextWriter writer) {
188 			if (!_webFormClientScriptRendered && _webFormClientScriptRequired) {
189 				Page page = OwnerPage;
190 				writer.WriteLine ();
191 				WriteClientScriptInclude (writer, GetWebResourceUrl (typeof (Page), "webform.js"), typeof (Page), "webform.js");
192 				WriteBeginScriptBlock (writer);
193 				writer.WriteLine ("WebForm_Initialize({0});", page.IsMultiForm ? page.theForm : "window");
194 				WriteEndScriptBlock (writer);
195 				_webFormClientScriptRendered = true;
196 			}
197 		}
198 
GetCallbackEventReference(Control control, string argument, string clientCallback, string context)199 		public string GetCallbackEventReference (Control control, string argument, string clientCallback, string context)
200 		{
201 			return GetCallbackEventReference (control, argument, clientCallback, context, null, false);
202 		}
203 
GetCallbackEventReference(Control control, string argument, string clientCallback, string context, bool useAsync)204 		public string GetCallbackEventReference (Control control, string argument, string clientCallback, string context, bool useAsync)
205 		{
206 			return GetCallbackEventReference (control, argument, clientCallback, context, null, useAsync);
207 		}
208 
GetCallbackEventReference(Control control, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)209 		public string GetCallbackEventReference (Control control, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)
210 		{
211 			if (control == null)
212 				throw new ArgumentNullException ("control");
213 			if(!(control is ICallbackEventHandler))
214 				throw new InvalidOperationException ("The control must implement the ICallbackEventHandler interface and provide a RaiseCallbackEvent method.");
215 
216 			return GetCallbackEventReference ("'" + control.UniqueID + "'", argument, clientCallback, context, clientErrorCallback, useAsync);
217 		}
218 
GetCallbackEventReference(string target, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)219 		public string GetCallbackEventReference (string target, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)
220 		{
221 			RegisterWebFormClientScript ();
222 
223 			Page page = OwnerPage;
224 			if (!_initCallBackRegistered) {
225 				_initCallBackRegistered = true;
226 				RegisterStartupScript (typeof (Page), "WebForm_InitCallback", page.WebFormScriptReference + ".WebForm_InitCallback();", true);
227 			}
228 			return page.WebFormScriptReference + ".WebForm_DoCallback(" +
229 				target + "," +
230 				(argument ?? "null") + "," +
231 				clientCallback + "," +
232 				(context ?? "null") + "," +
233 				(clientErrorCallback ?? "null") + "," +
234 				(useAsync ? "true" : "false") + ")";
235 		}
236 
GetWebResourceUrl(Type type, string resourceName)237 		public string GetWebResourceUrl(Type type, string resourceName)
238 		{
239 			if (type == null)
240 				throw new ArgumentNullException ("type");
241 
242 			if (resourceName == null || resourceName.Length == 0)
243 				throw new ArgumentNullException ("type");
244 
245 			return System.Web.Handlers.AssemblyResourceLoader.GetResourceUrl (type, resourceName);
246 		}
247 
248 
IsClientScriptBlockRegistered(string key)249 		public bool IsClientScriptBlockRegistered (string key)
250 		{
251 			return IsScriptRegistered (clientScriptBlocks, GetType(), key);
252 		}
253 
IsClientScriptBlockRegistered(Type type, string key)254 		public bool IsClientScriptBlockRegistered (Type type, string key)
255 		{
256 			return IsScriptRegistered (clientScriptBlocks, type, key);
257 		}
258 
IsStartupScriptRegistered(string key)259 		public bool IsStartupScriptRegistered (string key)
260 		{
261 			return IsScriptRegistered (startupScriptBlocks, GetType(), key);
262 		}
263 
IsStartupScriptRegistered(Type type, string key)264 		public bool IsStartupScriptRegistered (Type type, string key)
265 		{
266 			return IsScriptRegistered (startupScriptBlocks, type, key);
267 		}
268 
IsOnSubmitStatementRegistered(string key)269 		public bool IsOnSubmitStatementRegistered (string key)
270 		{
271 			return IsScriptRegistered (submitStatements, GetType(), key);
272 		}
273 
IsOnSubmitStatementRegistered(Type type, string key)274 		public bool IsOnSubmitStatementRegistered (Type type, string key)
275 		{
276 			return IsScriptRegistered (submitStatements, type, key);
277 		}
278 
IsClientScriptIncludeRegistered(string key)279 		public bool IsClientScriptIncludeRegistered (string key)
280 		{
281 			return IsClientScriptIncludeRegistered (GetType (), key);
282 		}
283 
IsClientScriptIncludeRegistered(Type type, string key)284 		public bool IsClientScriptIncludeRegistered (Type type, string key)
285 		{
286 			return IsScriptRegistered (clientScriptBlocks, type, "include-" + key);
287 		}
288 
IsScriptRegistered(ScriptEntry scriptList, Type type, string key)289 		bool IsScriptRegistered (ScriptEntry scriptList, Type type, string key)
290 		{
291 			while (scriptList != null) {
292 				if (scriptList.Type == type && scriptList.Key == key)
293 					return true;
294 				scriptList = scriptList.Next;
295 			}
296 			return false;
297 		}
298 
RegisterArrayDeclaration(string arrayName, string arrayValue)299 		public void RegisterArrayDeclaration (string arrayName, string arrayValue)
300 		{
301 			if (registeredArrayDeclares == null)
302 				registeredArrayDeclares = new Hashtable();
303 
304 			if (!registeredArrayDeclares.ContainsKey (arrayName))
305 				registeredArrayDeclares.Add (arrayName, new ArrayList());
306 
307 			((ArrayList) registeredArrayDeclares[arrayName]).Add(arrayValue);
308 			OwnerPage.RequiresFormScriptDeclaration ();
309 		}
310 
RegisterScript(ref ScriptEntry scriptList, Type type, string key, string script, bool addScriptTags)311 		void RegisterScript (ref ScriptEntry scriptList, Type type, string key, string script, bool addScriptTags)
312 		{
313 			RegisterScript (ref scriptList, type, key, script, addScriptTags ? ScriptEntryFormat.AddScriptTag : ScriptEntryFormat.None);
314 		}
315 
RegisterScript(ref ScriptEntry scriptList, Type type, string key, string script, ScriptEntryFormat format)316 		void RegisterScript (ref ScriptEntry scriptList, Type type, string key, string script, ScriptEntryFormat format)
317 		{
318 			ScriptEntry last = null;
319 			ScriptEntry entry = scriptList;
320 
321 			while (entry != null) {
322 				if (entry.Type == type && entry.Key == key)
323 					return;
324 				last = entry;
325 				entry = entry.Next;
326 			}
327 
328 			entry = new ScriptEntry (type, key, script, format);
329 
330 			if (last != null) last.Next = entry;
331 			else scriptList = entry;
332 		}
333 
RegisterClientScriptBlock(string key, string script)334 		internal void RegisterClientScriptBlock (string key, string script)
335 		{
336 			RegisterScript (ref clientScriptBlocks, GetType(), key, script, false);
337 		}
338 
RegisterClientScriptBlock(Type type, string key, string script)339 		public void RegisterClientScriptBlock (Type type, string key, string script)
340 		{
341 			RegisterClientScriptBlock (type, key, script, false);
342 		}
343 
RegisterClientScriptBlock(Type type, string key, string script, bool addScriptTags)344 		public void RegisterClientScriptBlock (Type type, string key, string script, bool addScriptTags)
345 		{
346 			if (type == null)
347 				throw new ArgumentNullException ("type");
348 
349 			RegisterScript (ref clientScriptBlocks, type, key, script, addScriptTags);
350 		}
351 
RegisterHiddenField(string hiddenFieldName, string hiddenFieldInitialValue)352 		public void RegisterHiddenField (string hiddenFieldName, string hiddenFieldInitialValue)
353 		{
354 			if (hiddenFields == null)
355 				hiddenFields = new Hashtable ();
356 
357 			if (!hiddenFields.ContainsKey (hiddenFieldName))
358 				hiddenFields.Add (hiddenFieldName, hiddenFieldInitialValue);
359 		}
360 
RegisterOnSubmitStatement(string key, string script)361 		internal void RegisterOnSubmitStatement (string key, string script)
362 		{
363 			RegisterScript (ref submitStatements, GetType (), key, script, false);
364 		}
365 
RegisterOnSubmitStatement(Type type, string key, string script)366 		public void RegisterOnSubmitStatement (Type type, string key, string script)
367 		{
368 			if (type == null)
369 				throw new ArgumentNullException ("type");
370 
371 			RegisterScript (ref submitStatements, type, key, script, false);
372 		}
373 
RegisterStartupScript(string key, string script)374 		internal void RegisterStartupScript (string key, string script)
375 		{
376 			RegisterScript (ref startupScriptBlocks, GetType(), key, script, false);
377 		}
378 
RegisterStartupScript(Type type, string key, string script)379 		public void RegisterStartupScript (Type type, string key, string script)
380 		{
381 			RegisterStartupScript (type, key, script, false);
382 		}
383 
RegisterStartupScript(Type type, string key, string script, bool addScriptTags)384 		public void RegisterStartupScript (Type type, string key, string script, bool addScriptTags)
385 		{
386 			if (type == null)
387 				throw new ArgumentNullException ("type");
388 
389 			RegisterScript (ref startupScriptBlocks, type, key, script, addScriptTags);
390 		}
391 
RegisterClientScriptInclude(string key, string url)392 		public void RegisterClientScriptInclude (string key, string url)
393 		{
394 			RegisterClientScriptInclude (GetType (), key, url);
395 		}
396 
RegisterClientScriptInclude(Type type, string key, string url)397 		public void RegisterClientScriptInclude (Type type, string key, string url)
398 		{
399 			if (type == null)
400 				throw new ArgumentNullException ("type");
401 			if (url == null || url.Length == 0)
402 				throw new ArgumentException ("url");
403 
404 			RegisterScript (ref clientScriptBlocks, type, "include-" + key, url, ScriptEntryFormat.Include);
405 		}
406 
RegisterClientScriptResource(Type type, string resourceName)407 		public void RegisterClientScriptResource (Type type, string resourceName)
408 		{
409 			RegisterScript (ref clientScriptBlocks, type, "resource-" + resourceName, GetWebResourceUrl (type, resourceName), ScriptEntryFormat.Include);
410 		}
411 
RegisterExpandoAttribute(string controlId, string attributeName, string attributeValue)412 		public void RegisterExpandoAttribute (string controlId, string attributeName, string attributeValue)
413 		{
414 			RegisterExpandoAttribute (controlId, attributeName, attributeValue, true);
415 		}
416 
RegisterExpandoAttribute(string controlId, string attributeName, string attributeValue, bool encode)417 		public void RegisterExpandoAttribute (string controlId, string attributeName, string attributeValue, bool encode)
418 		{
419 			if (controlId == null)
420 				throw new ArgumentNullException ("controlId");
421 
422 			if (attributeName == null)
423 				throw new ArgumentNullException ("attributeName");
424 
425 			if (expandoAttributes == null)
426 				expandoAttributes = new Hashtable ();
427 
428 			ListDictionary list = (ListDictionary)expandoAttributes [controlId];
429 			if (list == null) {
430 				list = new ListDictionary ();
431 				expandoAttributes [controlId] = list;
432 			}
433 
434 			list.Add (attributeName, encode ? StrUtils.EscapeQuotesAndBackslashes (attributeValue) : attributeValue);
435 		}
436 
EnsureEventValidationArray()437 		void EnsureEventValidationArray ()
438 		{
439 			if (eventValidationValues == null || eventValidationValues.Length == 0)
440 				eventValidationValues = new int [64];
441 
442 			int len = eventValidationValues.Length;
443 
444 			if (eventValidationPos >= len) {
445 				int [] tmp = new int [len * 2];
446 				Array.Copy (eventValidationValues, tmp, len);
447 				eventValidationValues = tmp;
448 			}
449 		}
450 
ResetEventValidationState()451 		internal void ResetEventValidationState ()
452 		{
453 			_pageInRender = true;
454 			eventValidationPos = 0;
455 		}
456 
457 		// Implemented following the description in http://odetocode.com/Blogs/scott/archive/2006/03/20/3145.aspx
CalculateEventHash(string uniqueId, string argument)458 		int CalculateEventHash (string uniqueId, string argument)
459 		{
460 			int uniqueIdHash = uniqueId.GetHashCode ();
461 			int argumentHash = String.IsNullOrEmpty (argument) ? 0 : argument.GetHashCode ();
462 			return (uniqueIdHash ^ argumentHash);
463 		}
464 
RegisterForEventValidation(PostBackOptions options)465 		public void RegisterForEventValidation (PostBackOptions options)
466 		{
467 			// MS.NET does not check for options == null, so we won't too...
468 			RegisterForEventValidation (options.TargetControl.UniqueID, options.Argument);
469 		}
470 
RegisterForEventValidation(string uniqueId)471 		public void RegisterForEventValidation (string uniqueId)
472 		{
473 			RegisterForEventValidation (uniqueId, null);
474 		}
475 
RegisterForEventValidation(string uniqueId, string argument)476 		public void RegisterForEventValidation (string uniqueId, string argument)
477 		{
478 			Page page = OwnerPage;
479 			if (!page.EnableEventValidation)
480 				return;
481 			if (uniqueId == null || uniqueId.Length == 0)
482 				return;
483 			if (page.IsCallback)
484 				_hasRegisteredForEventValidationOnCallback = true;
485 			else if (!_pageInRender)
486 				throw new InvalidOperationException ("RegisterForEventValidation may only be called from the Render method");
487 
488 			EnsureEventValidationArray ();
489 
490 			int hash = CalculateEventHash (uniqueId, argument);
491 			for (int i = 0; i < eventValidationPos; i++)
492 				if (eventValidationValues [i] == hash)
493 					return;
494 			eventValidationValues [eventValidationPos++] = hash;
495 		}
496 
ValidateEvent(string uniqueId)497 		public void ValidateEvent (string uniqueId)
498 		{
499 			ValidateEvent (uniqueId, null);
500 		}
501 
InvalidPostBackException()502 		ArgumentException InvalidPostBackException ()
503 		{
504 			return new ArgumentException ("Invalid postback or callback argument. Event validation is enabled using <pages enableEventValidation=\"true\"/> in configuration or <%@ Page EnableEventValidation=\"true\" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.");
505 		}
506 
ValidateEvent(string uniqueId, string argument)507 		public void ValidateEvent (string uniqueId, string argument)
508 		{
509 			if (uniqueId == null || uniqueId.Length == 0)
510 				throw new ArgumentException ("must not be null or empty", "uniqueId");
511 			if (!OwnerPage.EnableEventValidation)
512 				return;
513 			if (eventValidationValues == null)
514 				throw InvalidPostBackException ();
515 
516 			int hash = CalculateEventHash (uniqueId, argument);
517 			for (int i = 0; i < eventValidationValues.Length; i++)
518 				if (eventValidationValues [i] == hash)
519 					return;
520 
521 			throw InvalidPostBackException ();
522 		}
523 
WriteScripts(HtmlTextWriter writer, ScriptEntry scriptList)524 		void WriteScripts (HtmlTextWriter writer, ScriptEntry scriptList)
525 		{
526 			if (scriptList == null)
527 				return;
528 
529 			writer.WriteLine ();
530 
531 			while (scriptList != null) {
532 				switch (scriptList.Format) {
533 				case ScriptEntryFormat.AddScriptTag:
534 					EnsureBeginScriptBlock (writer);
535 					writer.Write (scriptList.Script);
536 					break;
537 				case ScriptEntryFormat.Include:
538 					EnsureEndScriptBlock (writer);
539 					WriteClientScriptInclude (writer, scriptList.Script, scriptList.Type, scriptList.Key);
540 					break;
541 				default:
542 					EnsureEndScriptBlock (writer);
543 					writer.WriteLine (scriptList.Script);
544 					break;
545 				}
546 				scriptList = scriptList.Next;
547 			}
548 			EnsureEndScriptBlock (writer);
549 		}
550 
551 		bool _scriptTagOpened;
552 
EnsureBeginScriptBlock(HtmlTextWriter writer)553 		void EnsureBeginScriptBlock (HtmlTextWriter writer) {
554 			if (!_scriptTagOpened) {
555 				WriteBeginScriptBlock (writer);
556 				_scriptTagOpened = true;
557 			}
558 		}
559 
EnsureEndScriptBlock(HtmlTextWriter writer)560 		void EnsureEndScriptBlock (HtmlTextWriter writer) {
561 			if (_scriptTagOpened) {
562 				WriteEndScriptBlock (writer);
563 				_scriptTagOpened = false;
564 			}
565 		}
566 
RestoreEventValidationState(string fieldValue)567 		internal void RestoreEventValidationState (string fieldValue)
568 		{
569 			Page page = OwnerPage;
570 			if (!page.EnableEventValidation || fieldValue == null || fieldValue.Length == 0)
571 				return;
572 			IStateFormatter fmt = page.GetFormatter ();
573 			eventValidationValues = (int []) fmt.Deserialize (fieldValue);
574 			eventValidationPos = eventValidationValues.Length;
575 		}
576 
SaveEventValidationState()577 		internal void SaveEventValidationState ()
578 		{
579 			if (!OwnerPage.EnableEventValidation)
580 				return;
581 
582 			string eventValidation = GetEventValidationStateFormatted ();
583 			if (eventValidation == null)
584 				return;
585 
586 			RegisterHiddenField (EventStateFieldName, eventValidation);
587 		}
588 
GetEventValidationStateFormatted()589 		internal string GetEventValidationStateFormatted ()
590 		{
591 			if (eventValidationValues == null || eventValidationValues.Length == 0)
592 				return null;
593 
594 			Page page = OwnerPage;
595 			if(page.IsCallback && !_hasRegisteredForEventValidationOnCallback)
596 				return null;
597 
598 			IStateFormatter fmt = page.GetFormatter ();
599 			int [] array = new int [eventValidationPos];
600 			Array.Copy (eventValidationValues, array, eventValidationPos);
601 			return fmt.Serialize (array);
602 		}
603 
WriteExpandoAttributes(HtmlTextWriter writer)604 		internal void WriteExpandoAttributes (HtmlTextWriter writer)
605 		{
606 			if (expandoAttributes == null)
607 				return;
608 
609 			writer.WriteLine ();
610 			WriteBeginScriptBlock (writer);
611 
612 			foreach (string controlId in expandoAttributes.Keys) {
613 				writer.WriteLine ("var {0} = document.all ? document.all [\"{0}\"] : document.getElementById (\"{0}\");", controlId);
614 				ListDictionary attrs = (ListDictionary) expandoAttributes [controlId];
615 				foreach (string attributeName in attrs.Keys) {
616 					writer.WriteLine ("{0}.{1} = \"{2}\";", controlId, attributeName, attrs [attributeName]);
617 				}
618 			}
619 			WriteEndScriptBlock (writer);
620 			writer.WriteLine ();
621 		}
622 
623 		internal const string SCRIPT_BLOCK_START = "//<![CDATA[";
624 		internal const string SCRIPT_BLOCK_END = "//]]>";
625 		internal const string SCRIPT_ELEMENT_START = @"<script type=""text/javascript"">" + SCRIPT_BLOCK_START;
626 		internal const string SCRIPT_ELEMENT_END = SCRIPT_BLOCK_END + "</script>";
627 
WriteBeginScriptBlock(HtmlTextWriter writer)628 		internal static void WriteBeginScriptBlock (HtmlTextWriter writer)
629 		{
630 			writer.WriteLine (SCRIPT_ELEMENT_START);
631 		}
632 
WriteEndScriptBlock(HtmlTextWriter writer)633 		internal static void WriteEndScriptBlock (HtmlTextWriter writer)
634 		{
635 			writer.WriteLine (SCRIPT_ELEMENT_END);
636 		}
637 
WriteHiddenFields(HtmlTextWriter writer)638 		internal void WriteHiddenFields (HtmlTextWriter writer)
639 		{
640 			if (hiddenFields == null)
641 				return;
642 
643 			writer.WriteLine ();
644 			writer.AddAttribute (HtmlTextWriterAttribute.Class, "aspNetHidden");
645 			writer.RenderBeginTag (HtmlTextWriterTag.Div);
646 			int oldIndent = writer.Indent;
647 			writer.Indent = 0;
648 			bool first = true;
649 			var sb = new StringBuilder ();
650 
651 			foreach (string key in hiddenFields.Keys) {
652 				string value = hiddenFields [key] as string;
653 				if (first)
654 					first = false;
655 				else
656 					writer.WriteLine ();
657 				sb.Append ("<input type=\"hidden\" name=\"");
658 				sb.Append (key);
659 				sb.Append ("\" id=\"");
660 				sb.Append (key);
661 				sb.Append ("\" value=\"");
662 				sb.Append (HttpUtility.HtmlAttributeEncode (value));
663 				sb.Append ("\" />");
664 			}
665 			writer.Write (sb.ToString ());
666 			writer.Indent = oldIndent;
667 			writer.RenderEndTag (); // DIV
668 			writer.WriteLine ();
669 			hiddenFields = null;
670 		}
671 
WriteClientScriptInclude(HtmlTextWriter writer, string path, Type type, string key)672 		internal void WriteClientScriptInclude (HtmlTextWriter writer, string path, Type type, string key) {
673 					if (!OwnerPage.IsMultiForm)
674 						writer.WriteLine ("<script src=\"{0}\" type=\"text/javascript\"></script>", path);
675 					else {
676 						string scriptKey = "inc_" + (type.FullName + key).GetHashCode ().ToString ("X");
677 						writer.WriteLine ("<script type=\"text/javascript\">");
678 						writer.WriteLine (SCRIPT_BLOCK_START);
679 						writer.WriteLine ("if (!window.{0}) {{", scriptKey);
680 						writer.WriteLine ("\twindow.{0} = true", scriptKey);
681 						writer.WriteLine ("\tdocument.write('<script src=\"{0}\" type=\"text/javascript\"><\\/script>'); }}", path);
682 						writer.WriteLine (SCRIPT_BLOCK_END);
683 						writer.WriteLine ("</script>");
684 					}
685 		}
686 
WriteClientScriptBlocks(HtmlTextWriter writer)687 		internal void WriteClientScriptBlocks (HtmlTextWriter writer)
688 		{
689 			WriteScripts (writer, clientScriptBlocks);
690 		}
691 
WriteStartupScriptBlocks(HtmlTextWriter writer)692 		internal void WriteStartupScriptBlocks (HtmlTextWriter writer)
693 		{
694 			WriteScripts (writer, startupScriptBlocks);
695 		}
696 
WriteArrayDeclares(HtmlTextWriter writer)697 		internal void WriteArrayDeclares (HtmlTextWriter writer)
698 		{
699 			if (registeredArrayDeclares != null) {
700 				writer.WriteLine();
701 				WriteBeginScriptBlock (writer);
702 				IDictionaryEnumerator arrayEnum = registeredArrayDeclares.GetEnumerator();
703 				Page page = OwnerPage;
704 				while (arrayEnum.MoveNext()) {
705 					if (page.IsMultiForm)
706 						writer.Write ("\t" + page.theForm + ".");
707 					else
708 						writer.Write ("\tvar ");
709 					writer.Write(arrayEnum.Key);
710 					writer.Write(" =  new Array(");
711 					IEnumerator arrayListEnum = ((ArrayList) arrayEnum.Value).GetEnumerator();
712 					bool isFirst = true;
713 					while (arrayListEnum.MoveNext()) {
714 						if (isFirst)
715 							isFirst = false;
716 						else
717 							writer.Write(", ");
718 						writer.Write(arrayListEnum.Current);
719 					}
720 					writer.WriteLine(");");
721 				}
722 				WriteEndScriptBlock (writer);
723 				writer.WriteLine ();
724 			}
725 		}
726 
GetClientValidationEvent(string validationGroup)727 		internal string GetClientValidationEvent (string validationGroup) {
728 			Page page = OwnerPage;
729 			if (page.IsMultiForm)
730 				return "if (typeof(" + page.theForm + ".Page_ClientValidate) == 'function') " + page.theForm + ".Page_ClientValidate('" + validationGroup + "');";
731 			return "if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate('" + validationGroup + "');";
732 		}
733 
GetClientValidationEvent()734 		internal string GetClientValidationEvent ()
735 		{
736 			Page page = OwnerPage;
737 			if (page.IsMultiForm)
738 				return "if (typeof(" + page.theForm + ".Page_ClientValidate) == 'function') " + page.theForm + ".Page_ClientValidate();";
739 			return "if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate();";
740 		}
741 
742 
WriteSubmitStatements()743 		internal string WriteSubmitStatements ()
744 		{
745 			if (submitStatements == null) return null;
746 
747 			StringBuilder sb = new StringBuilder ();
748 			ScriptEntry entry = submitStatements;
749 			while (entry != null) {
750 				sb.Append (EnsureEndsWithSemicolon (entry.Script));
751 				entry = entry.Next;
752 			}
753 			Page page = OwnerPage;
754 			RegisterClientScriptBlock (GetType(), "HtmlForm-OnSubmitStatemen",
755 @"
756 " + page.WebFormScriptReference + @".WebForm_OnSubmit = function () {
757 " + sb.ToString () + @"
758 return true;
759 }
760 ", true);
761 			return "javascript:return " + page.WebFormScriptReference + ".WebForm_OnSubmit();";
762 		}
763 
GetScriptLiteral(object ob)764 		internal static string GetScriptLiteral (object ob)
765 		{
766 			if (ob == null)
767 				return "null";
768 			else if (ob is string) {
769 				string s = (string)ob;
770 				bool escape = false;
771 				int len = s.Length;
772 
773 				for (int i = 0; i < len; i++)
774 					if (s [i] == '\\' || s [i] == '\"') {
775 						escape = true;
776 						break;
777 					}
778 
779 				if (!escape)
780 					return string.Concat ("\"", s, "\"");
781 
782 				StringBuilder sb = new StringBuilder (len + 10);
783 
784 				sb.Append ('\"');
785 				for (int si = 0; si < len; si++) {
786 					if (s [si] == '\"')
787 						sb.Append ("\\\"");
788 					else if (s [si] == '\\')
789 						sb.Append ("\\\\");
790 					else
791 						sb.Append (s [si]);
792 				}
793 				sb.Append ('\"');
794 
795 				return sb.ToString ();
796 			} else if (ob is bool) {
797 				return ob.ToString ().ToLower (Helpers.InvariantCulture);
798 			} else {
799 				return ob.ToString ();
800 			}
801 		}
802 
803 		sealed class ScriptEntry
804 		{
805 			public readonly Type Type;
806 			public readonly string Key;
807 			public readonly string Script;
808 			public readonly ScriptEntryFormat Format;
809 			public ScriptEntry Next;
810 
ScriptEntry(Type type, string key, string script, ScriptEntryFormat format)811 			public ScriptEntry (Type type, string key, string script, ScriptEntryFormat format) {
812 				Key = key;
813 				Type = type;
814 				Script = script;
815 				Format = format;
816 			}
817 		}
818 
819 		enum ScriptEntryFormat
820 		{
821 			None,
822 			AddScriptTag,
823 			Include,
824 		}
825 
826 		// helper method
EnsureEndsWithSemicolon(string value)827 		internal static string EnsureEndsWithSemicolon (string value) {
828 			if (value != null && value.Length > 0 && value [value.Length - 1] != ';')
829 				return value += ";";
830 			return value;
831 		}
832 	}
833 }
834