1 //------------------------------------------------------------------------------
2 // <copyright file="ScriptReferenceBase.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6 
7 namespace System.Web.UI {
8     using System;
9     using System.ComponentModel;
10     using System.Diagnostics.CodeAnalysis;
11     using System.Globalization;
12     using System.Web;
13     using System.Web.Resources;
14     using System.Web.UI.WebControls;
15     using Debug = System.Diagnostics.Debug;
16 
17     [
18     DefaultProperty("Path"),
19     ]
20     public abstract class ScriptReferenceBase {
21         private bool _alwaysLoadBeforeUI;
22         private IClientUrlResolver _clientUrlResolver;
23         private Control _containingControl;
24         private bool _isStaticReference;
25         private bool _notifyScriptLoaded = true;
26         private string _path;
27         private string[] _resourceUICultures;
28         private ScriptMode _scriptMode;
29 
ScriptReferenceBase()30         protected ScriptReferenceBase() {}
31 
32         internal bool AlwaysLoadBeforeUI {
33             get {
34                 return _alwaysLoadBeforeUI;
35             }
36             set {
37                 _alwaysLoadBeforeUI = value;
38             }
39         }
40 
41         // Used by ScriptManager to associate a ScriptReference with its url resolver
42         // (i.e. ScriptManager or ScriptManagerProxy)
43         internal IClientUrlResolver ClientUrlResolver {
44             get {
45                 return _clientUrlResolver;
46             }
47             set {
48                 _clientUrlResolver = value;
49             }
50         }
51 
52         internal Control ContainingControl {
53             get {
54                 return _containingControl;
55             }
56             set {
57                 _containingControl = value;
58             }
59         }
60 
61         // isStaticReference is true if the reference came from a ScriptManager or ScriptManagerProxy scripts collection,
62         // false if it came from an IScriptControl or ExtenderControl.
63         internal bool IsStaticReference {
64             get {
65                 return _isStaticReference;
66             }
67             set {
68                 _isStaticReference = value;
69             }
70         }
71 
72         // True if this is a reference to a bundle
73         internal bool IsBundleReference {
74             get;
75             set;
76         }
77 
78         [
79         Category("Behavior"),
80         DefaultValue(true),
81         NotifyParentProperty(true),
82         ResourceDescription("ScriptReference_NotifyScriptLoaded"),
83         Obsolete("NotifyScriptLoaded is no longer required in script references.")
84         ]
85         public bool NotifyScriptLoaded {
86             get {
87                 return _notifyScriptLoaded;
88             }
89             set {
90                 _notifyScriptLoaded = value;
91             }
92         }
93 
94         [
95         Category("Behavior"),
96         DefaultValue(""),
97         NotifyParentProperty(true),
98         ResourceDescription("ScriptReference_Path"),
99         UrlProperty("*.js")
100         ]
101         public string Path {
102             get {
103                 return (_path == null) ? String.Empty : _path;
104             }
105             set {
106                 _path = value;
107             }
108         }
109 
110         [
111         ResourceDescription("ScriptReference_ResourceUICultures"),
112         DefaultValue(null),
113         Category("Behavior"),
114         MergableProperty(false),
115         NotifyParentProperty(true),
116         TypeConverter(typeof(StringArrayConverter)),
117         SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays",
118             Justification = "String[] has existing TypeConverter support, which we don't want to add for List<string> to the assembly just for this property and at this point in the product cycle.")
119         ]
120         public string[] ResourceUICultures {
121             get {
122                 return _resourceUICultures;
123             }
124             set {
125                 _resourceUICultures = value;
126             }
127         }
128 
129         [
130         Category("Behavior"),
131         DefaultValue(ScriptMode.Auto),
132         NotifyParentProperty(true),
133         ResourceDescription("ScriptReference_ScriptMode")
134         ]
135         public ScriptMode ScriptMode {
136             get {
137                 return _scriptMode;
138             }
139             set {
140                 if (value < ScriptMode.Auto || value > ScriptMode.Release) {
141                     throw new ArgumentOutOfRangeException("value");
142                 }
143                 _scriptMode = value;
144             }
145         }
146 
147         [Obsolete("Use IsAjaxFrameworkScript(ScriptManager)")]
IsFromSystemWebExtensions()148         protected internal abstract bool IsFromSystemWebExtensions();
149 
IsAjaxFrameworkScript(ScriptManager scriptManager)150         protected internal virtual bool IsAjaxFrameworkScript(ScriptManager scriptManager) {
151             return false;
152         }
153 
154         internal virtual bool IsDefiningSys {
155             get;
156             set;
157         }
158 
159         // Script path may contain a query string, while script name may not
160         // Release: foo.js?key=value
161         // Debug:   foo.debug.js?key=value
GetDebugPath(string releasePath)162         internal static string GetDebugPath(string releasePath) {
163             // Per RFC 3986, the '?' delimits the query, regardless of the protocol.  This overrides
164             // an earlier RFC, which stated that FTP protocol allows '?' as path characters.
165             string pathWithoutQuery;
166             string query;
167             if (releasePath.IndexOf('?') >= 0) {
168                 int indexOfQuery = releasePath.IndexOf('?');
169                 pathWithoutQuery = releasePath.Substring(0, indexOfQuery);
170                 query = releasePath.Substring(indexOfQuery);
171             }
172             else {
173                 pathWithoutQuery = releasePath;
174                 query = null;
175             }
176 
177             if (!pathWithoutQuery.EndsWith(".js", StringComparison.Ordinal)) {
178                 throw new InvalidOperationException(
179                     String.Format(CultureInfo.CurrentUICulture, AtlasWeb.ScriptReference_InvalidReleaseScriptPath, pathWithoutQuery));
180             }
181 
182             return ReplaceExtension(pathWithoutQuery) + query;
183         }
184 
185         [SuppressMessage("Microsoft.Design", "CA1055", Justification = "Consistent with other URL properties in ASP.NET.")]
GetUrl(ScriptManager scriptManager, bool zip)186         protected internal abstract string GetUrl(ScriptManager scriptManager, bool zip);
187 
188         // Assumes the input ends with ".js".  Replaces the ".js" at the end of the input
189         // with ".debug.js".
ReplaceExtension(string pathOrName)190         protected static string ReplaceExtension(string pathOrName) {
191             Debug.Assert(pathOrName.EndsWith(".js", StringComparison.Ordinal));
192             return (pathOrName.Substring(0, pathOrName.Length - 2) + "debug.js");
193         }
194     }
195 }
196