1 // Copyright 2004-2008 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
19 using System
.Collections
;
20 using System
.Collections
.Specialized
;
22 using Castle
.MonoRail
.Framework
.Internal
;
23 using Castle
.MonoRail
.Framework
.Services
.AjaxProxyGenerator
;
26 /// XmlHttpRequest supported events.
28 public enum CallbackEnum
35 /// Called when the remote document is being
36 /// loaded with data by the browser.
40 /// Called when the browser has finished loading
41 /// the remote document.
45 /// Called when the user can interact with the
46 /// remote document, even though it has not
51 /// Called when the XMLHttpRequest has completed.
55 /// Called when the request was successfully (Status code < 500)
59 /// Called when the request was not successfully (Status code >= 500)
65 /// MonoRail Helper that delivers AJAX capabilities.
68 /// The following libraries are exposed:
69 /// <list type="table">
70 /// <item><term> Prototype </term>
71 /// <description> Simplify ajax programming, among other goodies
72 /// </description></item>
73 /// <item><term> Behaviour </term>
74 /// <description> Uses css selectors to bind javascript code to DOM elements
75 /// </description></item>
78 public class AjaxHelper
: AbstractHelper
, IServiceEnabledComponent
80 private IAjaxProxyGenerator ajaxProxyGenerator
;
84 /// Initializes a new instance of the <see cref="AjaxHelper"/> class.
86 public AjaxHelper() { }
88 /// Initializes a new instance of the <see cref="AjaxHelper"/> class.
89 /// setting the Controller, Context and ControllerContext.
91 /// <param name="engineContext">The engine context.</param>
92 public AjaxHelper(IEngineContext engineContext
) : base(engineContext
) { }
95 #region IServiceEnabledComponent implementation
98 /// Invoked by the framework in order to give a chance to
99 /// obtain other services
101 /// <param name="provider">The service proviver</param>
102 public void Service(IServiceProvider provider
)
104 ajaxProxyGenerator
= (IAjaxProxyGenerator
) provider
.GetService(typeof(IAjaxProxyGenerator
));
112 /// Renders a Javascript library inside a single script tag.
114 public String
InstallScripts()
116 return RenderScriptBlockToSource("/MonoRail/Files/AjaxScripts");
120 /// Renders a Javascript library inside a single script tag.
122 [Obsolete("Please use the preferred InstallScripts function.")]
123 public String
GetJavascriptFunctions()
125 return InstallScripts();
130 #region GenerateJSProxy overloads
133 /// Generates an AJAX JavaScript proxy for the current controller.
135 /// <param name="proxyName">Name of the javascript proxy object</param>
136 public String
GenerateJSProxy(string proxyName
)
138 return GenerateJSProxy(proxyName
, ControllerContext
.AreaName
, ControllerContext
.Name
);
142 /// Generates an AJAX JavaScript proxy for a given controller.
144 /// <param name="proxyName">Name of the javascript proxy object</param>
145 /// <param name="controller">Controller which will be target of the proxy</param>
146 public String
GenerateJSProxy(string proxyName
, string controller
)
148 return GenerateJSProxy(proxyName
, String
.Empty
, controller
);
152 /// Generates an AJAX JavaScript proxy for a given controller.
154 /// <param name="proxyName">Name of the javascript proxy object</param>
155 /// <param name="controller">Controller which will be target of the proxy</param>
156 /// <param name="area">area which the controller belongs to</param>
157 public String
GenerateJSProxy(string proxyName
, string area
, string controller
)
159 return ajaxProxyGenerator
.GenerateJSProxy(CurrentContext
, proxyName
, area
, controller
);
164 #region LinkToFunction
167 /// Returns a link that will trigger a javascript function using the
168 /// onclick handler and return false after the fact.
170 /// <a href="javascript:void(0);" onclick="functionCodeOrName; return false">innerContent</a>
173 /// <param name="innerContent">Link content</param>
174 /// <param name="functionCodeOrName">Function definition</param>
175 /// <param name="attributes">Attributes to be applied to the html element</param>
176 /// <returns></returns>
177 public String
LinkToFunction(String innerContent
, String functionCodeOrName
, IDictionary attributes
)
179 String htmlAtt
= GetAttributes(attributes
);
181 return String
.Format("<a href=\"javascript:void(0);\" {2} onclick=\"{0}; return false;\" >{1}</a>", functionCodeOrName
, innerContent
, htmlAtt
);
185 /// Returns a link that will trigger a javascript function using the
186 /// onclick handler and return false after the fact.
188 /// <a href="javascript:void(0);" onclick="confirm('question') { functionCodeOrName}; return false">innerContent</a>
191 /// <param name="innerContent">Link content</param>
192 /// <param name="functionCodeOrName">Function definition</param>
193 /// <param name="confirm">Confirm question</param>
194 /// <param name="attributes">Attributes to be applied to the html element</param>
195 /// <returns></returns>
196 public String
LinkToFunction(String innerContent
, String functionCodeOrName
, string confirm
, IDictionary attributes
)
198 String htmlAtt
= GetAttributes(attributes
);
200 return String
.Format("<a href=\"javascript:void(0);\" {2} onclick=\"if(confirm('" + confirm
+ "')){{{0}}};return false;\" >{1}</a>", functionCodeOrName
, innerContent
, htmlAtt
);
204 /// Returns a link that will trigger a javascript function using the
205 /// onclick handler and return false after the fact.
207 /// <param name="innerContent">Link content</param>
208 /// <param name="functionCodeOrName">Function definition</param>
209 /// <returns></returns>
210 public String
LinkToFunction(String innerContent
, String functionCodeOrName
)
212 return LinkToFunction(innerContent
, functionCodeOrName
, new Hashtable());
216 /// Returns a link that will trigger a javascript function using the
217 /// onclick handler and return false after the fact.
219 /// <param name="innerContent">Link content</param>
220 /// <param name="functionCodeOrName">Function definition</param>
221 /// <param name="confirm">Confirm question</param>
222 /// <returns></returns>
223 public String
LinkToFunction(String innerContent
, String functionCodeOrName
, String confirm
)
225 return LinkToFunction(innerContent
, functionCodeOrName
, confirm
, null);
230 #region ButtonToFunction
233 /// Returns a button that will trigger a javascript function using the
234 /// onclick handler and return false after the fact.
236 /// <param name="innerContent">Button legend</param>
237 /// <param name="functionCodeOrName">Function definition or name</param>
238 /// <param name="attributes">Attributes to be applied to the input html element</param>
239 /// <returns></returns>
240 public String
ButtonToFunction(String innerContent
, String functionCodeOrName
, IDictionary attributes
)
242 String htmlAtt
= GetAttributes(attributes
);
244 return String
.Format("<input type=\"button\" {2} onclick=\"{0}; return false;\" value=\"{1}\" />",
245 functionCodeOrName
, innerContent
, htmlAtt
);
249 /// Returns a button that will trigger a javascript function using the
250 /// onclick handler and return false after the fact.
252 /// <param name="innerContent">Button legend</param>
253 /// <param name="functionCodeOrName">Function definition or name</param>
254 /// <returns></returns>
255 public String
ButtonToFunction(String innerContent
, String functionCodeOrName
)
257 return ButtonToFunction(innerContent
, functionCodeOrName
, null);
262 #region ButtonToRemote
265 /// Creates a button that if clicked will fire an Ajax invocation.
267 /// <param name="innerContent">Button legend</param>
268 /// <param name="url">The URL of the Ajax action</param>
269 /// <param name="options">the options for the Ajax invocation</param>
270 /// <returns>The handcrafted input</returns>
271 public String
ButtonToRemote(String innerContent
, String url
, IDictionary options
)
273 return ButtonToFunction(innerContent
, BuildRemoteFunction(url
, options
));
277 /// Creates a button that if clicked will fire an Ajax invocation.
279 /// <param name="innerContent">Button legend</param>
280 /// <param name="url">the target url</param>
281 /// <param name="options">the options for the Ajax invocation</param>
282 /// <param name="htmloptions">Attributes to be applied to the html element</param>
283 /// <returns>The handcrafted input</returns>
284 public String
ButtonToRemote(String innerContent
, String url
, IDictionary options
, IDictionary htmloptions
)
286 return ButtonToFunction(innerContent
, BuildRemoteFunction(url
, options
), htmloptions
);
294 /// Returns a link to a remote action defined by <c>options["url"]</c>
295 /// that is called in the background using
296 /// XMLHttpRequest. The result of that request can then be inserted into a
297 /// DOM object whose id can be specified with <c>options["update"]</c>.
298 /// Usually, the result would be a partial prepared by the controller
300 /// <param name="innerContent">Link content</param>
301 /// <param name="url">Target url</param>
302 /// <param name="options">the options for the Ajax invocation</param>
303 /// <returns>The handcrafted element</returns>
304 public String
LinkToRemote(String innerContent
, String url
, IDictionary options
)
306 return LinkToFunction(innerContent
, BuildRemoteFunction(url
, options
));
310 /// Returns a link to a remote action defined by <c>options["url"]</c>
311 /// that is called in the background using
312 /// XMLHttpRequest. The result of that request can then be inserted into a
313 /// DOM object whose id can be specified with <c>options["update"]</c>.
314 /// Usually, the result would be a partial prepared by the controller
316 /// <param name="innerContent">Link content</param>
317 /// <param name="confirm">the confirm question</param>
318 /// <param name="url">Target url</param>
319 /// <param name="options">the options for the Ajax invocation</param>
320 /// <returns>The handcrafted element</returns>
321 public String
LinkToRemote(String innerContent
, String confirm
, String url
, IDictionary options
)
323 return LinkToFunction(innerContent
, BuildRemoteFunction(url
, options
), confirm
, null);
327 /// Returns a link to a remote action defined by <c>options["url"]</c>
328 /// that is called in the background using
329 /// XMLHttpRequest. The result of that request can then be inserted into a
330 /// DOM object whose id can be specified with <c>options["update"]</c>.
331 /// Usually, the result would be a partial prepared by the controller
333 /// <param name="innerContent">Link content</param>
334 /// <param name="url">Target url</param>
335 /// <param name="options">the options for the Ajax invocation</param>
336 /// <param name="htmloptions">Attributes to be applied to the html element</param>
337 /// <returns>The handcrafted element</returns>
338 public String
LinkToRemote(String innerContent
, String url
, IDictionary options
, IDictionary htmloptions
)
340 return LinkToFunction(innerContent
, BuildRemoteFunction(url
, options
), htmloptions
);
345 #region BuildFormRemoteTag
348 /// Returns a form tag that will submit using XMLHttpRequest
349 /// in the background instead of the regular
350 /// reloading POST arrangement. Even though it is
351 /// using Javascript to serialize the form elements, the form submission
352 /// will work just like a regular submission as viewed by the
353 /// receiving side (all elements available).
355 /// <param name="url">Target url</param>
356 /// <param name="options">the options for the Ajax invocation</param>
357 /// <returns>The handcrafted element</returns>
358 public String
BuildFormRemoteTag(String url
, IDictionary options
)
360 return BuildFormRemoteTag( GetOptions(url
, options
) );
364 /// Returns a form tag that will submit using XMLHttpRequest
365 /// in the background instead of the regular
366 /// reloading POST arrangement. Even though it is
367 /// using Javascript to serialize the form elements, the form submission
368 /// will work just like a regular submission as viewed by the
369 /// receiving side (all elements available).
371 /// <param name="options">the options for the Ajax invocation</param>
372 /// <returns>The handcrafted element</returns>
373 public String
BuildFormRemoteTag(IDictionary options
)
375 options
["form"] = true;
377 String remoteFunc
= RemoteFunction(options
);
379 String formId
= options
.Contains("formId") ? ("id=\"" + (String
) options
["formId"] + "\"") : String
.Empty
;
381 return String
.Format("<form {1} onsubmit=\"{0}; return false;\" enctype=\"multipart/form-data\" action=\"{2}\" method=\"post\" >", remoteFunc
, formId
, options
["url"]);
389 /// Observes the field with the DOM ID specified by <c>fieldId</c> and makes
390 /// an Ajax when its contents have changed.
392 /// <param name="fieldId">Form field to be observed</param>
393 /// <param name="frequency">The frequency (in seconds) at which changes to
394 /// this field will be detected. (required)</param>
395 /// <param name="url">url for the action to call
396 /// when the field has changed (required)</param>
397 /// <param name="idOfElementToBeUpdated"> Specifies the DOM ID of the element whose
398 /// innerHTML should be updated with the
399 /// XMLHttpRequest response text.</param>
400 /// <param name="with">A Javascript expression specifying the
401 /// parameters for the XMLHttpRequest. This defaults
402 /// to 'value', which in the evaluated context
403 /// refers to the new field value.</param>
404 /// <returns>javascript that activates the observer</returns>
405 public String
ObserveField(String fieldId
, int frequency
, String url
, String idOfElementToBeUpdated
, String with
)
407 IDictionary options
= new HybridDictionary();
408 options
["frequency"] = frequency
;
409 options
["url"] = url
;
411 if (idOfElementToBeUpdated
!= null) options
["update"] = idOfElementToBeUpdated
;
412 if (with
!= null) options
["with"] = with
;
414 return BuildObserver("Form.Element.Observer", fieldId
, options
);
418 /// Observes the field with the DOM ID specified by <c>fieldId</c> and makes
419 /// an Ajax when its contents have changed.
421 /// <param name="fieldId">Form field to be observed</param>
422 /// <param name="frequency">The frequency (in seconds) at which changes to
423 /// this field will be detected. (required)</param>
424 /// <param name="url">url for the action to call
425 /// when the field has changed (required)</param>
426 /// <param name="options">the options for the Ajax invocation</param>
427 /// <returns>javascript that activates the observer</returns>
428 public String
ObserveField(String fieldId
, int frequency
, String url
, IDictionary options
)
430 options
["url"] = url
;
431 options
["frequency"] = frequency
;
432 return BuildObserver("Form.Element.Observer", fieldId
, options
);
436 /// Observes the field with the DOM ID specified by <c>field</c> and makes
437 /// an Ajax call when its contents changes.
439 /// The following entries must exist in the dictionary:
441 /// <list type="bullet">
443 /// <term>field</term>
444 /// <description>The DOM field to be observed</description>
448 /// <description>url to to call when the field has changed</description>
451 /// <term>frequency</term>
452 /// <description>The frequency (in seconds) at which changes to this field will be detected</description>
456 /// The following are optional entries:
458 /// <list type="bullet">
460 /// <term>update</term>
461 /// <description>Specifies the DOM ID of the element whose
462 /// innerHTML should be updated with the
463 /// XMLHttpRequest response text</description>
466 /// <term>with</term>
467 /// <description>A Javascript expression specifying the parameters
468 /// for the XMLHttpRequest. This defaults to 'value', which in the
469 /// evaluated context refers to the new field value</description>
473 /// <param name="options">the options for the Ajax invocation</param>
474 /// <returns>javascript that activates the observer</returns>
475 public String
ObserveField(IDictionary options
)
477 return BuildObserver("Form.Element.Observer", (String
) options
["field"], options
);
485 /// Like <see cref="ObserveField(IDictionary)"/>, but operates on an entire form identified by the
486 /// DOM ID <c>formId</c>. options are the same as <see cref="ObserveField(IDictionary)"/>, except
487 /// the default value of the <tt>:with</tt> option evaluates to the
488 /// serialized (request String) value of the form.
489 /// Works like the <see cref="ObserveField(IDictionary)"/>, but operates on an entire form identified by the
490 /// DOM ID <c>formId</c>. Options are the same as <see cref="ObserveField(IDictionary)"/>, except
491 /// the default value of the <c>with</c> option evaluates to the
492 /// serialized (request String) value of the entire form.
494 /// <param name="formId">Form to be observed</param>
495 /// <param name="frequency">The frequency (in seconds) at which changes to
496 /// this field will be detected. (required)</param>
497 /// <param name="url">url for the action to call
498 /// when the field has changed (required)</param>
499 /// <param name="idOfElementToBeUpdated"> Specifies the DOM ID of the element whose
500 /// innerHTML should be updated with the
501 /// XMLHttpRequest response text.</param>
502 /// <param name="with">A Javascript expression specifying the
503 /// parameters for the XMLHttpRequest. This defaults
504 /// to 'value', which in the evaluated context
505 /// refers to the new field value.</param>
506 /// <returns>javascript that activates the observer</returns>
507 public String
ObserveForm(String formId
, int frequency
, String url
, String idOfElementToBeUpdated
, object with
)
509 IDictionary options
= new HybridDictionary();
510 options
["frequency"] = frequency
;
511 options
["url"] = url
;
513 if (idOfElementToBeUpdated
!= null && idOfElementToBeUpdated
.Length
> 0) options
["update"] = idOfElementToBeUpdated
;
514 if (with
!= null) options
["with"] = ProcessWith(with
);
516 return ObserveForm(formId
, options
);
520 /// Like <see cref="ObserveField(IDictionary)"/>, but operates on an entire form identified by the
521 /// DOM ID <c>formId</c>. options are the same as <see cref="ObserveField(IDictionary)"/>, except
522 /// the default value of the <c>with</c> option evaluates to the
523 /// serialized (request String) value of the entire form.
525 /// <param name="formId">Form to be observed</param>
526 /// <param name="options">the options for the Ajax invocation</param>
527 /// <returns>javascript that activates the observer</returns>
528 public String
ObserveForm(String formId
, IDictionary options
)
530 return BuildObserver("Form.Observer", formId
, options
);
534 /// Observes all elements within a form with the DOM
535 /// ID specified by <c>form</c> and makes
536 /// an Ajax call when its contents changes.
538 /// The following entries must exist in the dictionary:
540 /// <list type="bullet">
542 /// <term>form</term>
543 /// <description>The form element id</description>
547 /// <description>url to to call when the field has changed</description>
550 /// <term>frequency</term>
551 /// <description>The frequency (in seconds) at which changes to this field will be detected</description>
555 /// The following are optional entries:
557 /// <list type="bullet">
559 /// <term>update</term>
560 /// <description>Specifies the DOM ID of the element whose
561 /// innerHTML should be updated with the
562 /// XMLHttpRequest response text</description>
565 /// <term>with</term>
566 /// <description>A Javascript expression specifying the parameters
567 /// for the XMLHttpRequest. This defaults to 'value', which in the
568 /// evaluated context refers to the new field value</description>
572 /// <param name="options">the options for the Ajax invocation</param>
573 /// <returns>javascript that activates the observer</returns>
574 public String
ObserveForm(IDictionary options
)
576 String formId
= (String
) options
["form"];
578 if (!options
.Contains("with"))
580 options
["with"] = "Form.serialize(" + formId
+ ")";
583 return BuildObserver("Form.Observer", formId
, options
);
588 #region Periodically Call
591 /// Periodically invokes the specified <c>url</c>. You can use the options to
592 /// override the default <c>frequency</c> (defaults to 10 seconds).
594 /// <param name="options">the options for the Ajax invocation</param>
595 /// <returns>javascript that activates the timer</returns>
596 public String
PeriodicallyCallRemote(IDictionary options
)
598 String url
= (String
) options
["url"];
600 options
.Remove("url");
602 return PeriodicallyCallRemote(url
, options
);
606 /// Periodically invokes the specified <c>url</c>. You can use the options to
607 /// override the default <c>frequency</c> (defaults to 10 seconds).
609 /// <param name="options">the options for the Ajax invocation</param>
610 /// <param name="url">url to be invoked periodically</param>
611 /// <returns>javascript that activates the timer</returns>
612 public String
PeriodicallyCallRemote(String url
, IDictionary options
)
616 options
= new HybridDictionary();
619 if (!options
.Contains("frequency"))
621 options
["frequency"] = "10";
624 String code
= String
.Format("new PeriodicalExecuter(function() {{ {0} }}, {1} )",
625 BuildRemoteFunction(url
, options
), options
["frequency"]);
627 return String
.Format( "<script>{0}</script>", code
);
632 #region AutoCompletion
635 /// Rendes a input field with Google style autocomplete enabled.
636 /// The specified <c>url</c> is used to gather the contents
637 /// for the auto complete panel, so
638 /// and your action should return filtered and sorted results.
640 /// The following entries must exist in the options:
642 /// <list type="bullet">
644 /// <term>input</term>
645 /// <description>The text input element id</description>
649 /// <description>url to to call when the field has changed</description>
654 /// it is assumed that the url invoked returns an unordered list.
656 /// <param name="options">the options for the Ajax invocation</param>
657 /// <param name="tagAttributes">attributes for the input html element</param>
658 /// <returns>javascript that activates the timer</returns>
659 public String
InputTextWithAutoCompletion(IDictionary options
, IDictionary tagAttributes
)
661 String input
= (String
) options
["input"];
662 String url
= (String
) options
["url"];
664 options
.Remove("input");
665 options
.Remove("url");
667 return InputTextWithAutoCompletion(input
, url
, tagAttributes
, options
);
671 /// Rendes a input field with Google style autocomplete enabled.
672 /// The specified url is used to gather the contents for the auto complete panel, so
673 /// and your action should return filtered and sorted results.
674 /// <seealso cref="AutoCompleteInputText"/>
677 /// it is assumed that the url invoked returns an unordered list.
679 /// <param name="inputName">input element id</param>
680 /// <param name="url">url used to gather results</param>
681 /// <param name="tagAttributes">attributes for the input element</param>
682 /// <param name="completionOptions">options for the autocomplete</param>
683 /// <returns></returns>
684 public String
InputTextWithAutoCompletion(String inputName
, String url
, IDictionary tagAttributes
, IDictionary completionOptions
)
686 StringBuilder sb
= new StringBuilder();
688 sb
.AppendFormat( "<input type=\"text\" autocomplete=\"off\" name=\"{0}\" id=\"{0}\" {1}/>",
689 inputName
, GetAttributes(tagAttributes
) );
691 sb
.AppendFormat( "<div id=\"{0}\" class=\"auto_complete\"></div>", inputName
+ "autocomplete" );
693 sb
.Append( AutoCompleteInputText( inputName
, url
, completionOptions
) );
695 return sb
.ToString();
699 /// Generates an javascript block enabling
700 /// auto completion for the specified input text id (<c>elementId</c>).
701 /// You can specify the element to be updated using the options
702 /// dictionary (key <c>update</c>), if you don't we assume
703 /// <c>elementId+autocomplete</c>.
706 /// it is assumed that the url invoked returns an unordered list.
708 /// <param name="elementId">The element id (input type=text)</param>
709 /// <param name="url">The url to be invoked returning results</param>
710 /// <param name="options">the options for the Ajax invocation</param>
711 /// <returns></returns>
712 public String
AutoCompleteInputText(String elementId
, String url
, IDictionary options
)
716 options
= new HybridDictionary();
719 StringBuilder sb
= new StringBuilder();
721 String update
= (String
) options
["update"];
725 update
= elementId
+ "autocomplete";
728 sb
.Append("<script type=\"text/javascript\">");
730 sb
.AppendFormat( "new Ajax.Autocompleter('{0}', '{1}', '{2}'", elementId
, update
, url
);
732 if (options
.Contains("tokens"))
734 String
[] tokens
= options
["tokens"].ToString().Split('|');
736 if (tokens
.Length
== 0)
738 options
.Remove("tokens");
740 else if (tokens
.Length
== 1)
742 options
["tokens"] = tokens
[0];
746 StringBuilder content
= new StringBuilder("new Array(");
748 foreach(String tok
in tokens
)
750 content
.Append('\'').Append(tok
).Append("\',");
753 if(tokens
.Length
> 0)
754 content
.Remove( content
.Length
- 1, 1); // removing extra comma
758 options
["tokens"] = content
.ToString();
762 if (options
.Contains("indicator"))
764 options
["indicator"] = String
.Format( "'{0}'", options
["indicator"] );
769 sb
.Append( JavascriptOptions(options
) );
773 sb
.Append("</script>");
775 return sb
.ToString();
780 #region Supporting methods
783 /// Returns a function that makes a remote invocation,
784 /// using the supplied parameters
786 /// <param name="url">Target url</param>
787 /// <param name="options">the options for the Ajax invocation</param>
788 /// <returns>javascript code</returns>
789 public String
BuildRemoteFunction(String url
, IDictionary options
)
793 options
= new HybridDictionary();
796 options
["url"] = url
;
798 return RemoteFunction(options
);
802 /// Returns a function that makes a remote invocation,
803 /// using the supplied parameters
805 /// <param name="options">the options for the Ajax invocation</param>
806 /// <returns>javascript code</returns>
807 public String
RemoteFunction(IDictionary options
)
809 IDictionary jsOptions
= new HybridDictionary();
811 String javascriptOptionsString
= BuildAjaxOptions(jsOptions
, options
);
813 StringBuilder contents
= new StringBuilder();
815 bool isRequestOnly
= !options
.Contains("update") &&
816 !options
.Contains("success") && !options
.Contains("failure");
820 contents
.Append( "new Ajax.Request(" );
824 contents
.Append( "new Ajax.Updater(" );
826 if (options
.Contains("update"))
828 contents
.AppendFormat( "'{0}', ", options
["update"] );
829 options
.Remove("update");
833 contents
.Append("{");
835 bool commaFirst
= false;
837 if (options
.Contains("success"))
839 contents
.AppendFormat( "success:'{0}'", options
["success"] );
841 options
.Remove("success");
844 if (options
.Contains("failure"))
848 contents
.Append(",");
850 contents
.AppendFormat( "failure:'{0}'", options
["failure"] );
851 options
.Remove("failure");
854 contents
.Append("}, ");
858 if (!options
.Contains("url")) throw new ArgumentException("url is required");
860 contents
.Append( GetUrlOption(options
) );
861 contents
.Append( ", " + javascriptOptionsString
+ ")" );
863 if (options
.Contains("before"))
865 contents
= new StringBuilder( String
.Format("{0}; {1}", options
["before"], contents
) );
867 options
.Remove("before");
870 if (options
.Contains("after"))
872 contents
= new StringBuilder( String
.Format("{1}; {0}", options
["after"], contents
) );
874 options
.Remove("after");
877 if (options
.Contains("condition"))
879 String old
= contents
.ToString();
881 contents
= new StringBuilder(
882 String
.Format("if ( {0} ) {{ {1}; }}", options
["condition"], old
) );
884 options
.Remove("condition");
887 return contents
.ToString();
890 private String
GetUrlOption(IDictionary options
)
892 String url
= (String
) options
["url"];
894 if (url
.StartsWith("<") && url
.EndsWith(">"))
896 return url
.Substring(1, url
.Length
- 2);
899 return "'" + url
+ "'";
903 /// Populates the <paramref name="jsOptions"/> by analyzing the
904 /// options set on the helper <paramref name="options"/>
908 /// The following options are analyzed
910 /// <list type="bullet">
912 /// <term>type</term>
913 /// <description>boolean - sets the <c>asynchronous</c> </description>
916 /// <term>method</term>
917 /// <description>string - sets the <c>method</c>. Possible values are post/get </description>
920 /// <term>evalScripts</term>
921 /// <description>boolean</description>
924 /// <term>position</term>
925 /// <description>string - sets the place where content is inserted (Top, Bottom, After, Before)</description>
928 /// <term>form</term>
929 /// <description>if present, set the parameters request to send the current form serialized</description>
932 /// <term>with</term>
933 /// <description>if present, set its content as the parameters for the ajax request</description>
939 /// <param name="jsOptions">Options that will be used on the js side</param>
940 /// <param name="options">Options passed to the helper method</param>
941 /// <returns></returns>
942 protected String
BuildAjaxOptions(IDictionary jsOptions
, IDictionary options
)
944 BuildCallbacks(jsOptions
, options
);
946 jsOptions
["asynchronous"] = (!options
.Contains("type")).ToString().ToLower(System
.Globalization
.CultureInfo
.InvariantCulture
);
948 if (options
.Contains("method"))
950 jsOptions
["method"] = options
["method"];
953 if (options
.Contains("evalScripts"))
955 jsOptions
["evalScripts"] = options
["evalScripts"];
959 jsOptions
["evalScripts"] = "true";
962 if (options
.Contains("position"))
964 jsOptions
["insertion"] = String
.Format("Insertion.{0}", options
["position"]);
967 if (!options
.Contains("with") && options
.Contains("form"))
969 jsOptions
["parameters"] = "Form.serialize(this)";
971 else if (options
.Contains("with"))
973 jsOptions
["parameters"] = ProcessWith(options
["with"]);
976 return JavascriptOptions(jsOptions
);
979 private string ProcessWith(object with
)
981 if (with
== null) return null;
983 if (with
is IDictionary
)
985 return SQuote(CommonUtils
.BuildQueryString(ServerUtility
, with
as IDictionary
, false));
988 return with
.ToString();
991 private void BuildCallbacks(IDictionary jsOptions
, IDictionary options
)
993 String
[] names
= CallbackEnum
.GetNames( typeof(CallbackEnum
) );
995 foreach(String name
in names
)
997 if (!options
.Contains(name
)) continue;
999 String callbackFunctionName
;
1001 String function
= BuildCallbackFunction(
1002 (CallbackEnum
) Enum
.Parse( typeof(CallbackEnum
), name
, true),
1003 options
[name
].ToString(), out callbackFunctionName
);
1005 if (function
== String
.Empty
) return;
1007 jsOptions
[callbackFunctionName
] = function
;
1012 /// Builds the callback function.
1014 /// <param name="callback">The callback.</param>
1015 /// <param name="code">The code.</param>
1016 /// <param name="name">The name.</param>
1017 /// <returns></returns>
1018 protected String
BuildCallbackFunction(CallbackEnum callback
, String code
, out String name
)
1020 name
= String
.Empty
;
1022 if (callback
== CallbackEnum
.Uninitialized
) return String
.Empty
;
1024 if (callback
!= CallbackEnum
.OnFailure
&& callback
!= CallbackEnum
.OnSuccess
)
1026 name
= "on" + callback
;
1028 else if (callback
== CallbackEnum
.OnFailure
)
1032 else if (callback
== CallbackEnum
.OnSuccess
)
1037 return String
.Format("function(request) {{ {0} }} ", code
);
1041 /// Builds the observer.
1043 /// <param name="clazz">The clazz.</param>
1044 /// <param name="name">The name.</param>
1045 /// <param name="options">The options.</param>
1046 /// <returns></returns>
1047 protected String
BuildObserver(String clazz
, String name
, IDictionary options
)
1049 if (options
.Contains("update") && !options
.Contains("with"))
1051 options
["with"] = "'value=' + value";
1054 String call
= RemoteFunction(options
);
1056 StringBuilder js
= new StringBuilder();
1058 js
.Append( "<script type=\"text/javascript\">" );
1059 js
.Append( String
.Format("new {0}('{1}', {2}, function(element, value) {{ {3} }})",
1060 clazz
, name
, options
["frequency"], call
) );
1061 js
.Append( "</script>" );
1063 return js
.ToString();
1067 /// Gets the options.
1069 /// <param name="url">The URL.</param>
1070 /// <param name="options">The options.</param>
1071 /// <returns></returns>
1072 public IDictionary
GetOptions(String url
, IDictionary options
)
1074 if (options
== null)
1076 options
= new HybridDictionary();
1079 options
["form"] = true;
1080 options
["url"] = url
;
1086 /// Gets the options.
1088 /// <param name="url">The URL.</param>
1089 /// <param name="idOfElementToBeUpdated">The id of element to be updated.</param>
1090 /// <param name="with">The with.</param>
1091 /// <param name="loading">The loading.</param>
1092 /// <param name="loaded">The loaded.</param>
1093 /// <param name="complete">The complete.</param>
1094 /// <param name="interactive">The interactive.</param>
1095 /// <returns></returns>
1096 public IDictionary
GetOptions(String url
, String idOfElementToBeUpdated
,
1097 object with
, String loading
, String loaded
, String complete
, String interactive
)
1099 IDictionary options
= new HybridDictionary();
1101 options
["form"] = true;
1102 options
["url"] = url
;
1103 // options["method"] = method;
1105 if (with
!= null) options
["with"] = with
;
1106 if (idOfElementToBeUpdated
!= null && idOfElementToBeUpdated
.Length
> 0) options
["update"] = idOfElementToBeUpdated
;
1107 if (loading
!= null && loading
.Length
> 0) options
["Loading"] = loading
;
1108 if (loaded
!= null && loaded
.Length
> 0) options
["Loaded"] = loaded
;
1109 if (complete
!= null && complete
.Length
> 0) options
["Complete"] = complete
;
1110 if (interactive
!= null && interactive
.Length
> 0) options
["Interactive"] = interactive
;