1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle
.MonoRail
.Framework
.Helpers
18 using System
.Collections
.Specialized
;
20 using System
.Collections
;
21 using Castle
.MonoRail
.Framework
.Internal
;
24 /// Optional base class for helpers.
25 /// Extend from this class only if your helpers needs
26 /// a reference to the controller which is using it or
27 /// if you need to use one of the protected utility methods.
29 public abstract class AbstractHelper
: IControllerAware
31 private const string MonoRailVersion
= "RC3_0006";
33 #region Controller Reference
36 /// Store's <see cref="Controller"/> for the current view.
38 private Controller controller
;
40 private UrlHelper urlHelper
;
42 private IServerUtility serverUtility
;
44 private IRailsEngineContext context
;
47 /// Sets the controller.
49 /// <param name="controller">Current view's <see cref="Controller"/>.</param>
50 public virtual void SetController(Controller controller
)
52 this.controller
= controller
;
54 if (controller
.Context
!= null) // It will be null when invoked from test cases
56 context
= controller
.Context
;
57 serverUtility
= controller
.Context
.Server
;
62 /// Gets the controller.
64 /// <value>The <see cref="Controller"/> used with the current view.</value>
65 public Controller Controller
67 get { return controller; }
73 /// Gets or sets the server utility.
75 /// <value>The server utility.</value>
76 public IServerUtility ServerUtility
78 get { return serverUtility; }
79 set { serverUtility = value; }
83 /// Gets the URL helper instance.
85 /// <value>The URL helper.</value>
86 public UrlHelper UrlHelper
88 get { return urlHelper ?? (UrlHelper) controller.Helpers["UrlHelper"]; }
89 set { urlHelper = value; }
93 /// Merges <paramref name="userOptions"/> with <paramref name="defaultOptions"/> placing results in
94 /// <paramref name="userOptions"/>.
96 /// <param name="userOptions">The user options.</param>
97 /// <param name="defaultOptions">The default options.</param>
99 /// All <see cref="IDictionary.Values"/> and <see cref="IDictionary.Keys"/> in <paramref name="defaultOptions"/>
100 /// are copied to <paramref name="userOptions"/>. Entries with the same <see cref="DictionaryEntry.Key"/> in
101 /// <paramref name="defaultOptions"/> and <paramref name="userOptions"/> are skipped.
103 protected void MergeOptions(IDictionary userOptions
, IDictionary defaultOptions
)
105 CommonUtils
.MergeOptions(userOptions
, defaultOptions
);
109 /// Gets the current context.
111 /// <value>The current context.</value>
112 public IRailsEngineContext CurrentContext
114 get { return context; }
115 set { context = value; }
118 #region Helper methods
121 /// Renders the a script block with a <c>src</c> attribute
122 /// pointing to the url. The url must not have an extension.
124 /// For example, suppose you invoke it like:
126 /// RenderScriptBlockToSource("/my/url/to/my/scripts");
132 /// <script type="text/javascript" src="/my/url/to/my/scripts.rails?VERSIONID"></script>
135 /// As you see the file extension will be inferred
138 /// <param name="url">The url for the scripts (should start with a '/')</param>
139 /// <returns>An script block pointing to the given url.</returns>
140 protected string RenderScriptBlockToSource(string url
)
142 return string.Format("<script type=\"text/javascript\" src=\"{0}.{1}?" + MonoRailVersion
+ "\"></script>",
143 context
.ApplicationPath
+ url
, context
.UrlInfo
.Extension
);
147 /// Renders the a script block with a <c>src</c> attribute
148 /// pointing to the url sending the querystring as parameter. The url must not have an extension.
150 /// For example, suppose you invoke it like:
152 /// RenderScriptBlockToSource("/my/url/to/my/scripts", "locale=pt-br");
158 /// <script type="text/javascript" src="/my/url/to/my/scripts.rails?VERSIONID&locale=pt-br"></script>
161 /// As you see the file extension will be inferred
164 /// <param name="url">The url for the scripts (should start with a '/')</param>
165 /// <param name="queryString">The query string.</param>
166 /// <returns>An script block pointing to the given url.</returns>
167 protected string RenderScriptBlockToSource(string url
, string queryString
)
169 if (queryString
!= null && queryString
!= string.Empty
)
171 queryString
= "&" + queryString
;
174 return string.Format("<script type=\"text/javascript\" src=\"{0}.{1}?" + MonoRailVersion
+ "{2}\"></script>",
175 context
.ApplicationPath
+ url
, context
.UrlInfo
.Extension
, queryString
);
179 /// Generates HTML element attributes string from <paramref name="attributes"/>.
180 /// <code>key1="value1" key2</code>
182 /// <param name="attributes">The attributes for the element.</param>
183 /// <returns><see cref="String"/> to use inside HTML element's tag.</returns>
185 /// <see cref="string.Empty"/> is returned if <paramref name="attributes"/> is <c>null</c> or empty.
187 /// If for some <see cref="DictionaryEntry.Key"/> <see cref="DictionaryEntry.Value"/> is <c>null</c> or
188 /// <see cref="string.Empty"/> only attribute name is appended to the string.
191 protected string GetAttributes(IDictionary attributes
)
193 if (attributes
== null || attributes
.Count
== 0) return string.Empty
;
195 StringBuilder contents
= new StringBuilder();
197 foreach(DictionaryEntry entry
in attributes
)
199 if (entry
.Value
== null || entry
.Value
.ToString() == string.Empty
)
201 contents
.Append(entry
.Key
);
205 contents
.AppendFormat("{0}=\"{1}\"", entry
.Key
, entry
.Value
);
207 contents
.Append(' ');
210 return contents
.ToString();
214 /// Builds a query string encoded.
217 /// Supports multi-value query strings, using any
218 /// <see cref="IEnumerable"/> as a value.
221 /// IDictionary dict = new Hashtable();
222 /// dict.Add("id", 5);
223 /// dict.Add("selectedItem", new int[] { 2, 4, 99 });
224 /// string querystring = BuildQueryString(dict);
225 /// // should result in: "id=5&selectedItem=2&selectedItem=4&selectedItem=99"
229 /// <param name="parameters">The parameters</param>
230 public string BuildQueryString(IDictionary parameters
)
232 return CommonUtils
.BuildQueryString(serverUtility
, parameters
, true);
236 /// Builds a query string encoded.
239 /// Supports multi-value query strings, using any
240 /// <see cref="IEnumerable"/> as a value.
242 /// <param name="parameters">The parameters</param>
243 public string BuildQueryString(NameValueCollection parameters
)
245 return CommonUtils
.BuildQueryString(serverUtility
, parameters
, true);
249 /// Concat two string in a query string format (<c>key=value&key2=value2</c>)
250 /// building a third string with the result
252 /// <param name="leftParams">key values</param>
253 /// <param name="rightParams">key values</param>
254 /// <returns>The concatenation result</returns>
255 protected string ConcatQueryString(string leftParams
, string rightParams
)
257 if (leftParams
== null || leftParams
.Length
== 0)
261 if (rightParams
== null || rightParams
.Length
== 0)
266 if (leftParams
.EndsWith("&") || leftParams
.EndsWith("&"))
268 leftParams
= leftParams
.Substring( 0, leftParams
.Length
- 1 );
271 return string.Format("{0}&{1}", leftParams
, rightParams
);
275 /// HTML encodes a string and returns the encoded string.
277 /// <param name="content">The text string to HTML encode.</param>
278 /// <returns>The HTML encoded text.</returns>
279 public virtual string HtmlEncode(string content
)
281 return serverUtility
.HtmlEncode(content
);
285 /// Escapes a content replacing line breaks with html break lines.
287 /// <param name="content">The text to escape.</param>
288 /// <returns>The URL encoded and JavaScript escaped text.</returns>
289 public String
LineBreaksToHtml(String content
)
291 if (content
== null) return string.Empty
;
293 // TODO: Replace by a regular expression, which should be much more efficient
295 return content
.Replace("\r", "").Replace("\n", "<br/>");
299 /// URL encodes a string and returns the encoded string.
301 /// <param name="content">The text to URL encode.</param>
302 /// <returns>The URL encoded text.</returns>
303 public virtual string UrlEncode(string content
)
305 return serverUtility
.UrlEncode(content
);
309 /// URL encodes the path portion of a URL string and returns the encoded string.
311 /// <param name="content">The text to URL encode.</param>
312 /// <returns>The URL encoded text.</returns>
313 public string UrlPathEncode(string content
)
315 return serverUtility
.UrlPathEncode(content
);
319 /// Escapes JavaScript with Url encoding and returns the encoded string.
322 /// Converts quotes, single quotes and CR/LFs to their representation as an escape character.
324 /// <param name="content">The text to URL encode and escape JavaScript within.</param>
325 /// <returns>The URL encoded and JavaScript escaped text.</returns>
326 public string JavaScriptEscape(string content
)
328 if (string.IsNullOrEmpty(content
)) return content
;
330 return serverUtility
.JavaScriptEscape(content
);
334 /// Builds a JS associative array based on the specified dictionary instance.
336 /// For example: <c>{name: value, other: 'another'}</c>
339 /// <param name="jsOptions">The js options.</param>
340 /// <returns>An associative array in javascript</returns>
341 public static string JavascriptOptions(IDictionary jsOptions
)
343 if (jsOptions
== null || jsOptions
.Count
== 0)
348 StringBuilder sb
= new StringBuilder(jsOptions
.Count
* 10);
352 foreach (DictionaryEntry entry
in jsOptions
)
354 if (!comma
) comma
= true; else sb
.Append(", ");
356 sb
.Append(string.Format("{0}:{1}", entry
.Key
, entry
.Value
));
360 return sb
.ToString();
364 /// Generates script block.
366 /// <script type=\"text/javascript\">
371 /// <param name="scriptContents">The script contents.</param>
372 /// <returns><paramref name="scriptContents"/> placed inside <b>script</b> tags.</returns>
373 public static string ScriptBlock(string scriptContents
)
375 return "\r\n<script type=\"text/javascript\">\r\n" + scriptContents
+ "</script>\r\n";
379 /// Quotes the specified string with double quotes
381 /// <param name="content">The content.</param>
382 /// <returns>A quoted string</returns>
383 public static string Quote(object content
)
385 return "\"" + content
+ "\"";
389 /// Quotes the specified string with singdoublele quotes
391 /// <param name="items">Items to quote</param>
392 /// <returns>A quoted string</returns>
393 public static string[] Quote(object[] items
)
395 string[] quotedItems
= new string[items
.Length
];
399 foreach(string item
in items
)
401 quotedItems
[index
++] = Quote(item
);
408 /// Quotes the specified string with double quotes
410 /// <param name="content">The content.</param>
411 /// <returns>A quoted string</returns>
412 public static string SQuote(object content
)
414 return "\'" + content
+ "\'";