2 // System.Web.UI.ClientScriptManager.cs
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)
10 // (C) 2002,2003 Ximian, Inc. (http://www.ximian.com)
11 // (c) 2003-2010 Novell, Inc. (http://www.novell.com)
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:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
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.
36 using System.Collections;
37 using System.Collections.Generic;
39 using System.Collections.Specialized;
40 using System.Web.Util;
41 using System.Globalization;
43 namespace System.Web.UI
45 public sealed partial class ClientScriptManager
47 internal const string EventStateFieldName = "__EVENTVALIDATION";
49 Hashtable registeredArrayDeclares;
50 ScriptEntry clientScriptBlocks;
51 ScriptEntry startupScriptBlocks;
52 internal Hashtable hiddenFields;
53 ScriptEntry submitStatements;
55 int [] eventValidationValues;
56 int eventValidationPos = 0;
57 Hashtable expandoAttributes;
58 bool _hasRegisteredForEventValidationOnCallback;
60 bool _initCallBackRegistered;
61 bool _webFormClientScriptRendered;
62 bool _webFormClientScriptRequired;
64 internal bool ScriptsPresent {
66 return _webFormClientScriptRequired ||
67 _initCallBackRegistered ||
68 _hasRegisteredForEventValidationOnCallback ||
69 clientScriptBlocks != null ||
70 startupScriptBlocks != null ||
71 submitStatements != null ||
72 registeredArrayDeclares != null ||
73 expandoAttributes != null;
79 if (ownerPage == null)
80 throw new InvalidOperationException ("Associated Page instance is required to complete this operation.");
85 internal ClientScriptManager (Page page)
87 this.ownerPage = page;
90 public string GetPostBackClientHyperlink (Control control, string argument)
92 return "javascript:" + GetPostBackEventReference (control, argument);
95 public string GetPostBackClientHyperlink (Control control, string argument, bool registerForEventValidation)
97 if (registerForEventValidation)
98 RegisterForEventValidation (control.UniqueID, argument);
99 return "javascript:" + GetPostBackEventReference (control, argument);
102 public string GetPostBackEventReference (Control control, string argument)
105 throw new ArgumentNullException ("control");
107 Page page = OwnerPage;
108 page.RequiresPostBackScript ();
110 return page.theForm + ".__doPostBack('" + control.UniqueID + "','" + argument + "')";
112 return "__doPostBack('" + control.UniqueID + "','" + argument + "')";
115 public string GetPostBackEventReference (Control control, string argument, bool registerForEventValidation)
118 throw new ArgumentNullException ("control");
120 if (registerForEventValidation)
121 RegisterForEventValidation (control.UniqueID, argument);
122 return GetPostBackEventReference (control, argument);
125 public string GetPostBackEventReference (PostBackOptions options, bool registerForEventValidation)
128 throw new ArgumentNullException ("options");
129 if (registerForEventValidation)
130 RegisterForEventValidation (options);
131 return GetPostBackEventReference (options);
134 public string GetPostBackEventReference (PostBackOptions options)
137 throw new ArgumentNullException ("options");
139 string actionUrl = options.ActionUrl;
140 if (actionUrl == null && options.ValidationGroup == null && !options.TrackFocus &&
141 !options.AutoPostBack && !options.PerformValidation)
143 if (!options.ClientSubmit)
146 if (options.RequiresJavaScriptProtocol)
147 return GetPostBackClientHyperlink (options.TargetControl, options.Argument);
149 return GetPostBackEventReference (options.TargetControl, options.Argument);
152 RegisterWebFormClientScript ();
154 Page page = OwnerPage;
155 HttpRequest req = page.RequestInternal;
156 Uri pageUrl = req != null ? req.Url : null;
158 RegisterHiddenField (Page.PreviousPageID, pageUrl.AbsolutePath);
160 if(options.TrackFocus)
161 RegisterHiddenField (Page.LastFocusID, String.Empty);
163 string prefix = options.RequiresJavaScriptProtocol ? "javascript:" : String.Empty;
164 if (page.IsMultiForm)
165 prefix += page.theForm + ".";
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) + ")";
178 internal void RegisterWebFormClientScript ()
180 if (_webFormClientScriptRequired)
183 OwnerPage.RequiresPostBackScript ();
184 _webFormClientScriptRequired = true;
187 internal void WriteWebFormClientScript (HtmlTextWriter writer) {
188 if (!_webFormClientScriptRendered && _webFormClientScriptRequired) {
189 Page page = OwnerPage;
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;
199 public string GetCallbackEventReference (Control control, string argument, string clientCallback, string context)
201 return GetCallbackEventReference (control, argument, clientCallback, context, null, false);
204 public string GetCallbackEventReference (Control control, string argument, string clientCallback, string context, bool useAsync)
206 return GetCallbackEventReference (control, argument, clientCallback, context, null, useAsync);
209 public string GetCallbackEventReference (Control control, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)
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.");
216 return GetCallbackEventReference ("'" + control.UniqueID + "'", argument, clientCallback, context, clientErrorCallback, useAsync);
219 public string GetCallbackEventReference (string target, string argument, string clientCallback, string context, string clientErrorCallback, bool useAsync)
221 RegisterWebFormClientScript ();
223 Page page = OwnerPage;
224 if (!_initCallBackRegistered) {
225 _initCallBackRegistered = true;
226 RegisterStartupScript (typeof (Page), "WebForm_InitCallback", page.WebFormScriptReference + ".WebForm_InitCallback();", true);
228 return page.WebFormScriptReference + ".WebForm_DoCallback(" +
230 (argument ?? "null") + "," +
231 clientCallback + "," +
232 (context ?? "null") + "," +
233 (clientErrorCallback ?? "null") + "," +
234 (useAsync ? "true" : "false") + ")";
237 public string GetWebResourceUrl(Type type, string resourceName)
240 throw new ArgumentNullException ("type");
242 if (resourceName == null || resourceName.Length == 0)
243 throw new ArgumentNullException ("type");
245 return System.Web.Handlers.AssemblyResourceLoader.GetResourceUrl (type, resourceName);
249 public bool IsClientScriptBlockRegistered (string key)
251 return IsScriptRegistered (clientScriptBlocks, GetType(), key);
254 public bool IsClientScriptBlockRegistered (Type type, string key)
256 return IsScriptRegistered (clientScriptBlocks, type, key);
259 public bool IsStartupScriptRegistered (string key)
261 return IsScriptRegistered (startupScriptBlocks, GetType(), key);
264 public bool IsStartupScriptRegistered (Type type, string key)
266 return IsScriptRegistered (startupScriptBlocks, type, key);
269 public bool IsOnSubmitStatementRegistered (string key)
271 return IsScriptRegistered (submitStatements, GetType(), key);
274 public bool IsOnSubmitStatementRegistered (Type type, string key)
276 return IsScriptRegistered (submitStatements, type, key);
279 public bool IsClientScriptIncludeRegistered (string key)
281 return IsClientScriptIncludeRegistered (GetType (), key);
284 public bool IsClientScriptIncludeRegistered (Type type, string key)
286 return IsScriptRegistered (clientScriptBlocks, type, "include-" + key);
289 bool IsScriptRegistered (ScriptEntry scriptList, Type type, string key)
291 while (scriptList != null) {
292 if (scriptList.Type == type && scriptList.Key == key)
294 scriptList = scriptList.Next;
299 public void RegisterArrayDeclaration (string arrayName, string arrayValue)
301 if (registeredArrayDeclares == null)
302 registeredArrayDeclares = new Hashtable();
304 if (!registeredArrayDeclares.ContainsKey (arrayName))
305 registeredArrayDeclares.Add (arrayName, new ArrayList());
307 ((ArrayList) registeredArrayDeclares[arrayName]).Add(arrayValue);
308 OwnerPage.RequiresFormScriptDeclaration ();
311 void RegisterScript (ref ScriptEntry scriptList, Type type, string key, string script, bool addScriptTags)
313 RegisterScript (ref scriptList, type, key, script, addScriptTags ? ScriptEntryFormat.AddScriptTag : ScriptEntryFormat.None);
316 void RegisterScript (ref ScriptEntry scriptList, Type type, string key, string script, ScriptEntryFormat format)
318 ScriptEntry last = null;
319 ScriptEntry entry = scriptList;
321 while (entry != null) {
322 if (entry.Type == type && entry.Key == key)
328 entry = new ScriptEntry (type, key, script, format);
330 if (last != null) last.Next = entry;
331 else scriptList = entry;
334 internal void RegisterClientScriptBlock (string key, string script)
336 RegisterScript (ref clientScriptBlocks, GetType(), key, script, false);
339 public void RegisterClientScriptBlock (Type type, string key, string script)
341 RegisterClientScriptBlock (type, key, script, false);
344 public void RegisterClientScriptBlock (Type type, string key, string script, bool addScriptTags)
347 throw new ArgumentNullException ("type");
349 RegisterScript (ref clientScriptBlocks, type, key, script, addScriptTags);
352 public void RegisterHiddenField (string hiddenFieldName, string hiddenFieldInitialValue)
354 if (hiddenFields == null)
355 hiddenFields = new Hashtable ();
357 if (!hiddenFields.ContainsKey (hiddenFieldName))
358 hiddenFields.Add (hiddenFieldName, hiddenFieldInitialValue);
361 internal void RegisterOnSubmitStatement (string key, string script)
363 RegisterScript (ref submitStatements, GetType (), key, script, false);
366 public void RegisterOnSubmitStatement (Type type, string key, string script)
369 throw new ArgumentNullException ("type");
371 RegisterScript (ref submitStatements, type, key, script, false);
374 internal void RegisterStartupScript (string key, string script)
376 RegisterScript (ref startupScriptBlocks, GetType(), key, script, false);
379 public void RegisterStartupScript (Type type, string key, string script)
381 RegisterStartupScript (type, key, script, false);
384 public void RegisterStartupScript (Type type, string key, string script, bool addScriptTags)
387 throw new ArgumentNullException ("type");
389 RegisterScript (ref startupScriptBlocks, type, key, script, addScriptTags);
392 public void RegisterClientScriptInclude (string key, string url)
394 RegisterClientScriptInclude (GetType (), key, url);
397 public void RegisterClientScriptInclude (Type type, string key, string url)
400 throw new ArgumentNullException ("type");
401 if (url == null || url.Length == 0)
402 throw new ArgumentException ("url");
404 RegisterScript (ref clientScriptBlocks, type, "include-" + key, url, ScriptEntryFormat.Include);
407 public void RegisterClientScriptResource (Type type, string resourceName)
409 RegisterScript (ref clientScriptBlocks, type, "resource-" + resourceName, GetWebResourceUrl (type, resourceName), ScriptEntryFormat.Include);
412 public void RegisterExpandoAttribute (string controlId, string attributeName, string attributeValue)
414 RegisterExpandoAttribute (controlId, attributeName, attributeValue, true);
417 public void RegisterExpandoAttribute (string controlId, string attributeName, string attributeValue, bool encode)
419 if (controlId == null)
420 throw new ArgumentNullException ("controlId");
422 if (attributeName == null)
423 throw new ArgumentNullException ("attributeName");
425 if (expandoAttributes == null)
426 expandoAttributes = new Hashtable ();
428 ListDictionary list = (ListDictionary)expandoAttributes [controlId];
430 list = new ListDictionary ();
431 expandoAttributes [controlId] = list;
434 list.Add (attributeName, encode ? StrUtils.EscapeQuotesAndBackslashes (attributeValue) : attributeValue);
437 void EnsureEventValidationArray ()
439 if (eventValidationValues == null || eventValidationValues.Length == 0)
440 eventValidationValues = new int [64];
442 int len = eventValidationValues.Length;
444 if (eventValidationPos >= len) {
445 int [] tmp = new int [len * 2];
446 Array.Copy (eventValidationValues, tmp, len);
447 eventValidationValues = tmp;
451 internal void ResetEventValidationState ()
453 _pageInRender = true;
454 eventValidationPos = 0;
457 // Implemented following the description in http://odetocode.com/Blogs/scott/archive/2006/03/20/3145.aspx
458 int CalculateEventHash (string uniqueId, string argument)
460 int uniqueIdHash = uniqueId.GetHashCode ();
461 int argumentHash = String.IsNullOrEmpty (argument) ? 0 : argument.GetHashCode ();
462 return (uniqueIdHash ^ argumentHash);
465 public void RegisterForEventValidation (PostBackOptions options)
467 // MS.NET does not check for options == null, so we won't too...
468 RegisterForEventValidation (options.TargetControl.UniqueID, options.Argument);
471 public void RegisterForEventValidation (string uniqueId)
473 RegisterForEventValidation (uniqueId, null);
476 public void RegisterForEventValidation (string uniqueId, string argument)
478 Page page = OwnerPage;
479 if (!page.EnableEventValidation)
481 if (uniqueId == null || uniqueId.Length == 0)
484 _hasRegisteredForEventValidationOnCallback = true;
485 else if (!_pageInRender)
486 throw new InvalidOperationException ("RegisterForEventValidation may only be called from the Render method");
488 EnsureEventValidationArray ();
490 int hash = CalculateEventHash (uniqueId, argument);
491 for (int i = 0; i < eventValidationPos; i++)
492 if (eventValidationValues [i] == hash)
494 eventValidationValues [eventValidationPos++] = hash;
497 public void ValidateEvent (string uniqueId)
499 ValidateEvent (uniqueId, null);
502 ArgumentException InvalidPostBackException ()
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.");
507 public void ValidateEvent (string uniqueId, string argument)
509 if (uniqueId == null || uniqueId.Length == 0)
510 throw new ArgumentException ("must not be null or empty", "uniqueId");
511 if (!OwnerPage.EnableEventValidation)
513 if (eventValidationValues == null)
514 throw InvalidPostBackException ();
516 int hash = CalculateEventHash (uniqueId, argument);
517 for (int i = 0; i < eventValidationValues.Length; i++)
518 if (eventValidationValues [i] == hash)
521 throw InvalidPostBackException ();
524 void WriteScripts (HtmlTextWriter writer, ScriptEntry scriptList)
526 if (scriptList == null)
531 while (scriptList != null) {
532 switch (scriptList.Format) {
533 case ScriptEntryFormat.AddScriptTag:
534 EnsureBeginScriptBlock (writer);
535 writer.Write (scriptList.Script);
537 case ScriptEntryFormat.Include:
538 EnsureEndScriptBlock (writer);
539 WriteClientScriptInclude (writer, scriptList.Script, scriptList.Type, scriptList.Key);
542 EnsureEndScriptBlock (writer);
543 writer.WriteLine (scriptList.Script);
546 scriptList = scriptList.Next;
548 EnsureEndScriptBlock (writer);
551 bool _scriptTagOpened;
553 void EnsureBeginScriptBlock (HtmlTextWriter writer) {
554 if (!_scriptTagOpened) {
555 WriteBeginScriptBlock (writer);
556 _scriptTagOpened = true;
560 void EnsureEndScriptBlock (HtmlTextWriter writer) {
561 if (_scriptTagOpened) {
562 WriteEndScriptBlock (writer);
563 _scriptTagOpened = false;
567 internal void RestoreEventValidationState (string fieldValue)
569 Page page = OwnerPage;
570 if (!page.EnableEventValidation || fieldValue == null || fieldValue.Length == 0)
572 IStateFormatter fmt = page.GetFormatter ();
573 eventValidationValues = (int []) fmt.Deserialize (fieldValue);
574 eventValidationPos = eventValidationValues.Length;
577 internal void SaveEventValidationState ()
579 if (!OwnerPage.EnableEventValidation)
582 string eventValidation = GetEventValidationStateFormatted ();
583 if (eventValidation == null)
586 RegisterHiddenField (EventStateFieldName, eventValidation);
589 internal string GetEventValidationStateFormatted ()
591 if (eventValidationValues == null || eventValidationValues.Length == 0)
594 Page page = OwnerPage;
595 if(page.IsCallback && !_hasRegisteredForEventValidationOnCallback)
598 IStateFormatter fmt = page.GetFormatter ();
599 int [] array = new int [eventValidationPos];
600 Array.Copy (eventValidationValues, array, eventValidationPos);
601 return fmt.Serialize (array);
604 internal void WriteExpandoAttributes (HtmlTextWriter writer)
606 if (expandoAttributes == null)
610 WriteBeginScriptBlock (writer);
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]);
619 WriteEndScriptBlock (writer);
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>";
628 internal static void WriteBeginScriptBlock (HtmlTextWriter writer)
630 writer.WriteLine (SCRIPT_ELEMENT_START);
633 internal static void WriteEndScriptBlock (HtmlTextWriter writer)
635 writer.WriteLine (SCRIPT_ELEMENT_END);
638 internal void WriteHiddenFields (HtmlTextWriter writer)
640 if (hiddenFields == null)
645 writer.AddAttribute (HtmlTextWriterAttribute.Class, "aspNetHidden");
647 writer.RenderBeginTag (HtmlTextWriterTag.Div);
648 int oldIndent = writer.Indent;
651 var sb = new StringBuilder ();
653 foreach (string key in hiddenFields.Keys) {
654 string value = hiddenFields [key] as string;
659 sb.Append ("<input type=\"hidden\" name=\"");
661 sb.Append ("\" id=\"");
663 sb.Append ("\" value=\"");
664 sb.Append (HttpUtility.HtmlAttributeEncode (value));
667 writer.Write (sb.ToString ());
668 writer.Indent = oldIndent;
669 writer.RenderEndTag (); // DIV
674 internal void WriteClientScriptInclude (HtmlTextWriter writer, string path, Type type, string key) {
675 if (!OwnerPage.IsMultiForm)
676 writer.WriteLine ("<script src=\"{0}\" type=\"text/javascript\"></script>", path);
678 string scriptKey = "inc_" + (type.FullName + key).GetHashCode ().ToString ("X");
679 writer.WriteLine ("<script type=\"text/javascript\">");
680 writer.WriteLine (SCRIPT_BLOCK_START);
681 writer.WriteLine ("if (!window.{0}) {{", scriptKey);
682 writer.WriteLine ("\twindow.{0} = true", scriptKey);
683 writer.WriteLine ("\tdocument.write('<script src=\"{0}\" type=\"text/javascript\"><\\/script>'); }}", path);
684 writer.WriteLine (SCRIPT_BLOCK_END);
685 writer.WriteLine ("</script>");
689 internal void WriteClientScriptBlocks (HtmlTextWriter writer)
691 WriteScripts (writer, clientScriptBlocks);
694 internal void WriteStartupScriptBlocks (HtmlTextWriter writer)
696 WriteScripts (writer, startupScriptBlocks);
699 internal void WriteArrayDeclares (HtmlTextWriter writer)
701 if (registeredArrayDeclares != null) {
703 WriteBeginScriptBlock (writer);
704 IDictionaryEnumerator arrayEnum = registeredArrayDeclares.GetEnumerator();
705 Page page = OwnerPage;
706 while (arrayEnum.MoveNext()) {
707 if (page.IsMultiForm)
708 writer.Write ("\t" + page.theForm + ".");
710 writer.Write ("\tvar ");
711 writer.Write(arrayEnum.Key);
712 writer.Write(" = new Array(");
713 IEnumerator arrayListEnum = ((ArrayList) arrayEnum.Value).GetEnumerator();
715 while (arrayListEnum.MoveNext()) {
720 writer.Write(arrayListEnum.Current);
722 writer.WriteLine(");");
724 WriteEndScriptBlock (writer);
729 internal string GetClientValidationEvent (string validationGroup) {
730 Page page = OwnerPage;
731 if (page.IsMultiForm)
732 return "if (typeof(" + page.theForm + ".Page_ClientValidate) == 'function') " + page.theForm + ".Page_ClientValidate('" + validationGroup + "');";
733 return "if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate('" + validationGroup + "');";
736 internal string GetClientValidationEvent ()
738 Page page = OwnerPage;
739 if (page.IsMultiForm)
740 return "if (typeof(" + page.theForm + ".Page_ClientValidate) == 'function') " + page.theForm + ".Page_ClientValidate();";
741 return "if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate();";
745 internal string WriteSubmitStatements ()
747 if (submitStatements == null) return null;
749 StringBuilder sb = new StringBuilder ();
750 ScriptEntry entry = submitStatements;
751 while (entry != null) {
752 sb.Append (EnsureEndsWithSemicolon (entry.Script));
755 Page page = OwnerPage;
756 RegisterClientScriptBlock (GetType(), "HtmlForm-OnSubmitStatemen",
758 " + page.WebFormScriptReference + @".WebForm_OnSubmit = function () {
759 " + sb.ToString () + @"
763 return "javascript:return " + page.WebFormScriptReference + ".WebForm_OnSubmit();";
766 internal static string GetScriptLiteral (object ob)
770 else if (ob is string) {
771 string s = (string)ob;
775 for (int i = 0; i < len; i++)
776 if (s [i] == '\\' || s [i] == '\"') {
782 return string.Concat ("\"", s, "\"");
784 StringBuilder sb = new StringBuilder (len + 10);
787 for (int si = 0; si < len; si++) {
790 else if (s [si] == '\\')
797 return sb.ToString ();
798 } else if (ob is bool) {
799 return ob.ToString ().ToLower (Helpers.InvariantCulture);
801 return ob.ToString ();
805 sealed class ScriptEntry
807 public readonly Type Type;
808 public readonly string Key;
809 public readonly string Script;
810 public readonly ScriptEntryFormat Format;
811 public ScriptEntry Next;
813 public ScriptEntry (Type type, string key, string script, ScriptEntryFormat format) {
821 enum ScriptEntryFormat
829 internal static string EnsureEndsWithSemicolon (string value) {
830 if (value != null && value.Length > 0 && value [value.Length - 1] != ';')