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
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
;
82 #region IServiceEnabledComponent implementation
85 /// Invoked by the framework in order to give a chance to
86 /// obtain other services
88 /// <param name="provider">The service proviver</param>
89 public void Service(IServiceProvider provider
)
91 ajaxProxyGenerator
= (IAjaxProxyGenerator
) provider
.GetService(typeof(IAjaxProxyGenerator
));
99 /// Renders a Javascript library inside a single script tag.
101 public String
InstallScripts()
103 return RenderScriptBlockToSource("/MonoRail/Files/AjaxScripts");
107 /// Renders a Javascript library inside a single script tag.
109 [Obsolete("Please use the preferred InstallScripts function.")]
110 public String
GetJavascriptFunctions()
112 return InstallScripts();
117 #region GenerateJSProxy overloads
120 /// Generates an AJAX JavaScript proxy for the current controller.
122 /// <param name="proxyName">Name of the javascript proxy object</param>
123 public String
GenerateJSProxy(string proxyName
)
125 return GenerateJSProxy(proxyName
, Controller
.AreaName
, Controller
.Name
);
129 /// Generates an AJAX JavaScript proxy for a given controller.
131 /// <param name="proxyName">Name of the javascript proxy object</param>
132 /// <param name="controller">Controller which will be target of the proxy</param>
133 public String
GenerateJSProxy(string proxyName
, string controller
)
135 return GenerateJSProxy(proxyName
, String
.Empty
, controller
);
139 /// Generates an AJAX JavaScript proxy for a given controller.
141 /// <param name="proxyName">Name of the javascript proxy object</param>
142 /// <param name="controller">Controller which will be target of the proxy</param>
143 /// <param name="area">area which the controller belongs to</param>
144 public String
GenerateJSProxy(string proxyName
, string area
, string controller
)
146 return ajaxProxyGenerator
.GenerateJSProxy(CurrentContext
, proxyName
, area
, controller
);
151 #region LinkToFunction
154 /// Returns a link that will trigger a javascript function using the
155 /// onclick handler and return false after the fact.
157 /// <a href="javascript:void(0);" onclick="functionCodeOrName; return false">innerContent</a>
160 /// <param name="innerContent">Link content</param>
161 /// <param name="functionCodeOrName">Function definition</param>
162 /// <param name="attributes">Attributes to be applied to the html element</param>
163 /// <returns></returns>
164 public String
LinkToFunction(String innerContent
, String functionCodeOrName
, IDictionary attributes
)
166 String htmlAtt
= GetAttributes(attributes
);
168 return String
.Format("<a href=\"javascript:void(0);\" {2} onclick=\"{0}; return false;\" >{1}</a>", functionCodeOrName
, innerContent
, htmlAtt
);
172 /// Returns a link that will trigger a javascript function using the
173 /// onclick handler and return false after the fact.
175 /// <a href="javascript:void(0);" onclick="confirm('question') { functionCodeOrName}; return false">innerContent</a>
178 /// <param name="innerContent">Link content</param>
179 /// <param name="functionCodeOrName">Function definition</param>
180 /// <param name="confirm">Confirm question</param>
181 /// <param name="attributes">Attributes to be applied to the html element</param>
182 /// <returns></returns>
183 public String
LinkToFunction(String innerContent
, String functionCodeOrName
, string confirm
, IDictionary attributes
)
185 String htmlAtt
= GetAttributes(attributes
);
187 return String
.Format("<a href=\"javascript:void(0);\" {2} onclick=\"if(confirm('" + confirm
+ "')){{{0}}};return false;\" >{1}</a>", functionCodeOrName
, innerContent
, htmlAtt
);
191 /// Returns a link that will trigger a javascript function using the
192 /// onclick handler and return false after the fact.
194 /// <param name="innerContent">Link content</param>
195 /// <param name="functionCodeOrName">Function definition</param>
196 /// <returns></returns>
197 public String
LinkToFunction(String innerContent
, String functionCodeOrName
)
199 return LinkToFunction(innerContent
, functionCodeOrName
, new Hashtable());
203 /// Returns a link that will trigger a javascript function using the
204 /// onclick handler and return false after the fact.
206 /// <param name="innerContent">Link content</param>
207 /// <param name="functionCodeOrName">Function definition</param>
208 /// <param name="confirm">Confirm question</param>
209 /// <returns></returns>
210 public String
LinkToFunction(String innerContent
, String functionCodeOrName
, String confirm
)
212 return LinkToFunction(innerContent
, functionCodeOrName
, confirm
, null);
217 #region ButtonToFunction
220 /// Returns a button that will trigger a javascript function using the
221 /// onclick handler and return false after the fact.
223 /// <param name="innerContent">Button legend</param>
224 /// <param name="functionCodeOrName">Function definition or name</param>
225 /// <param name="attributes">Attributes to be applied to the input html element</param>
226 /// <returns></returns>
227 public String
ButtonToFunction(String innerContent
, String functionCodeOrName
, IDictionary attributes
)
229 String htmlAtt
= GetAttributes(attributes
);
231 return String
.Format("<input type=\"button\" {2} onclick=\"{0}; return false;\" value=\"{1}\" />",
232 functionCodeOrName
, innerContent
, htmlAtt
);
236 /// Returns a button that will trigger a javascript function using the
237 /// onclick handler and return false after the fact.
239 /// <param name="innerContent">Button legend</param>
240 /// <param name="functionCodeOrName">Function definition or name</param>
241 /// <returns></returns>
242 public String
ButtonToFunction(String innerContent
, String functionCodeOrName
)
244 return ButtonToFunction(innerContent
, functionCodeOrName
, null);
249 #region ButtonToRemote
252 /// Creates a button that if clicked will fire an Ajax invocation.
254 /// <param name="innerContent">Button legend</param>
255 /// <param name="url">The URL of the Ajax action</param>
256 /// <param name="options">the options for the Ajax invocation</param>
257 /// <returns>The handcrafted input</returns>
258 public String
ButtonToRemote(String innerContent
, String url
, IDictionary options
)
260 return ButtonToFunction(innerContent
, BuildRemoteFunction(url
, options
));
264 /// Creates a button that if clicked will fire an Ajax invocation.
266 /// <param name="innerContent">Button legend</param>
267 /// <param name="url">the target url</param>
268 /// <param name="options">the options for the Ajax invocation</param>
269 /// <param name="htmloptions">Attributes to be applied to the html element</param>
270 /// <returns>The handcrafted input</returns>
271 public String
ButtonToRemote(String innerContent
, String url
, IDictionary options
, IDictionary htmloptions
)
273 return ButtonToFunction(innerContent
, BuildRemoteFunction(url
, options
), htmloptions
);
281 /// Returns a link to a remote action defined by <c>options["url"]</c>
282 /// that is called in the background using
283 /// XMLHttpRequest. The result of that request can then be inserted into a
284 /// DOM object whose id can be specified with <c>options["update"]</c>.
285 /// Usually, the result would be a partial prepared by the controller
287 /// <param name="innerContent">Link content</param>
288 /// <param name="url">Target url</param>
289 /// <param name="options">the options for the Ajax invocation</param>
290 /// <returns>The handcrafted element</returns>
291 public String
LinkToRemote(String innerContent
, String url
, IDictionary options
)
293 return LinkToFunction(innerContent
, BuildRemoteFunction(url
, options
));
297 /// Returns a link to a remote action defined by <c>options["url"]</c>
298 /// that is called in the background using
299 /// XMLHttpRequest. The result of that request can then be inserted into a
300 /// DOM object whose id can be specified with <c>options["update"]</c>.
301 /// Usually, the result would be a partial prepared by the controller
303 /// <param name="innerContent">Link content</param>
304 /// <param name="confirm">the confirm question</param>
305 /// <param name="url">Target url</param>
306 /// <param name="options">the options for the Ajax invocation</param>
307 /// <returns>The handcrafted element</returns>
308 public String
LinkToRemote(String innerContent
, String confirm
, String url
, IDictionary options
)
310 return LinkToFunction(innerContent
, BuildRemoteFunction(url
, options
), confirm
, null);
314 /// Returns a link to a remote action defined by <c>options["url"]</c>
315 /// that is called in the background using
316 /// XMLHttpRequest. The result of that request can then be inserted into a
317 /// DOM object whose id can be specified with <c>options["update"]</c>.
318 /// Usually, the result would be a partial prepared by the controller
320 /// <param name="innerContent">Link content</param>
321 /// <param name="url">Target url</param>
322 /// <param name="options">the options for the Ajax invocation</param>
323 /// <param name="htmloptions">Attributes to be applied to the html element</param>
324 /// <returns>The handcrafted element</returns>
325 public String
LinkToRemote(String innerContent
, String url
, IDictionary options
, IDictionary htmloptions
)
327 return LinkToFunction(innerContent
, BuildRemoteFunction(url
, options
), htmloptions
);
332 #region BuildFormRemoteTag
335 /// Returns a form tag that will submit using XMLHttpRequest
336 /// in the background instead of the regular
337 /// reloading POST arrangement. Even though it is
338 /// using Javascript to serialize the form elements, the form submission
339 /// will work just like a regular submission as viewed by the
340 /// receiving side (all elements available).
342 /// <param name="url">Target url</param>
343 /// <param name="options">the options for the Ajax invocation</param>
344 /// <returns>The handcrafted element</returns>
345 public String
BuildFormRemoteTag(String url
, IDictionary options
)
347 return BuildFormRemoteTag( GetOptions(url
, options
) );
351 /// Returns a form tag that will submit using XMLHttpRequest
352 /// in the background instead of the regular
353 /// reloading POST arrangement. Even though it is
354 /// using Javascript to serialize the form elements, the form submission
355 /// will work just like a regular submission as viewed by the
356 /// receiving side (all elements available).
358 /// <param name="options">the options for the Ajax invocation</param>
359 /// <returns>The handcrafted element</returns>
360 public String
BuildFormRemoteTag(IDictionary options
)
362 options
["form"] = true;
364 String remoteFunc
= RemoteFunction(options
);
366 String formId
= options
.Contains("formId") ? ("id=\"" + (String
) options
["formId"] + "\"") : String
.Empty
;
368 return String
.Format("<form {1} onsubmit=\"{0}; return false;\" enctype=\"multipart/form-data\" action=\"{2}\" method=\"post\" >", remoteFunc
, formId
, options
["url"]);
376 /// Observes the field with the DOM ID specified by <c>fieldId</c> and makes
377 /// an Ajax when its contents have changed.
379 /// <param name="fieldId">Form field to be observed</param>
380 /// <param name="frequency">The frequency (in seconds) at which changes to
381 /// this field will be detected. (required)</param>
382 /// <param name="url">url for the action to call
383 /// when the field has changed (required)</param>
384 /// <param name="idOfElementToBeUpdated"> Specifies the DOM ID of the element whose
385 /// innerHTML should be updated with the
386 /// XMLHttpRequest response text.</param>
387 /// <param name="with">A Javascript expression specifying the
388 /// parameters for the XMLHttpRequest. This defaults
389 /// to 'value', which in the evaluated context
390 /// refers to the new field value.</param>
391 /// <returns>javascript that activates the observer</returns>
392 public String
ObserveField(String fieldId
, int frequency
, String url
, String idOfElementToBeUpdated
, String with
)
394 IDictionary options
= new HybridDictionary();
395 options
["frequency"] = frequency
;
396 options
["url"] = url
;
398 if (idOfElementToBeUpdated
!= null) options
["update"] = idOfElementToBeUpdated
;
399 if (with
!= null) options
["with"] = with
;
401 return BuildObserver("Form.Element.Observer", fieldId
, options
);
405 /// Observes the field with the DOM ID specified by <c>fieldId</c> and makes
406 /// an Ajax when its contents have changed.
408 /// <param name="fieldId">Form field to be observed</param>
409 /// <param name="frequency">The frequency (in seconds) at which changes to
410 /// this field will be detected. (required)</param>
411 /// <param name="url">url for the action to call
412 /// when the field has changed (required)</param>
413 /// <param name="options">the options for the Ajax invocation</param>
414 /// <returns>javascript that activates the observer</returns>
415 public String
ObserveField(String fieldId
, int frequency
, String url
, IDictionary options
)
417 options
["url"] = url
;
418 options
["frequency"] = frequency
;
419 return BuildObserver("Form.Element.Observer", fieldId
, options
);
423 /// Observes the field with the DOM ID specified by <c>field</c> and makes
424 /// an Ajax call when its contents changes.
426 /// The following entries must exist in the dictionary:
428 /// <list type="bullet">
430 /// <term>field</term>
431 /// <description>The DOM field to be observed</description>
435 /// <description>url to to call when the field has changed</description>
438 /// <term>frequency</term>
439 /// <description>The frequency (in seconds) at which changes to this field will be detected</description>
443 /// The following are optional entries:
445 /// <list type="bullet">
447 /// <term>update</term>
448 /// <description>Specifies the DOM ID of the element whose
449 /// innerHTML should be updated with the
450 /// XMLHttpRequest response text</description>
453 /// <term>with</term>
454 /// <description>A Javascript expression specifying the parameters
455 /// for the XMLHttpRequest. This defaults to 'value', which in the
456 /// evaluated context refers to the new field value</description>
460 /// <param name="options">the options for the Ajax invocation</param>
461 /// <returns>javascript that activates the observer</returns>
462 public String
ObserveField(IDictionary options
)
464 return BuildObserver("Form.Element.Observer", (String
) options
["field"], options
);
472 /// Like <see cref="ObserveField(IDictionary)"/>, but operates on an entire form identified by the
473 /// DOM ID <c>formId</c>. options are the same as <see cref="ObserveField(IDictionary)"/>, except
474 /// the default value of the <tt>:with</tt> option evaluates to the
475 /// serialized (request String) value of the form.
476 /// Works like the <see cref="ObserveField(IDictionary)"/>, but operates on an entire form identified by the
477 /// DOM ID <c>formId</c>. Options are the same as <see cref="ObserveField(IDictionary)"/>, except
478 /// the default value of the <c>with</c> option evaluates to the
479 /// serialized (request String) value of the entire form.
481 /// <param name="formId">Form to be observed</param>
482 /// <param name="frequency">The frequency (in seconds) at which changes to
483 /// this field will be detected. (required)</param>
484 /// <param name="url">url for the action to call
485 /// when the field has changed (required)</param>
486 /// <param name="idOfElementToBeUpdated"> Specifies the DOM ID of the element whose
487 /// innerHTML should be updated with the
488 /// XMLHttpRequest response text.</param>
489 /// <param name="with">A Javascript expression specifying the
490 /// parameters for the XMLHttpRequest. This defaults
491 /// to 'value', which in the evaluated context
492 /// refers to the new field value.</param>
493 /// <returns>javascript that activates the observer</returns>
494 public String
ObserveForm(String formId
, int frequency
, String url
, String idOfElementToBeUpdated
, object with
)
496 IDictionary options
= new HybridDictionary();
497 options
["frequency"] = frequency
;
498 options
["url"] = url
;
500 if (idOfElementToBeUpdated
!= null && idOfElementToBeUpdated
.Length
> 0) options
["update"] = idOfElementToBeUpdated
;
501 if (with
!= null) options
["with"] = ProcessWith(with
);
503 return ObserveForm(formId
, options
);
507 /// Like <see cref="ObserveField(IDictionary)"/>, but operates on an entire form identified by the
508 /// DOM ID <c>formId</c>. options are the same as <see cref="ObserveField(IDictionary)"/>, except
509 /// the default value of the <c>with</c> option evaluates to the
510 /// serialized (request String) value of the entire form.
512 /// <param name="formId">Form to be observed</param>
513 /// <param name="options">the options for the Ajax invocation</param>
514 /// <returns>javascript that activates the observer</returns>
515 public String
ObserveForm(String formId
, IDictionary options
)
517 return BuildObserver("Form.Observer", formId
, options
);
521 /// Observes all elements within a form with the DOM
522 /// ID specified by <c>form</c> and makes
523 /// an Ajax call when its contents changes.
525 /// The following entries must exist in the dictionary:
527 /// <list type="bullet">
529 /// <term>form</term>
530 /// <description>The form element id</description>
534 /// <description>url to to call when the field has changed</description>
537 /// <term>frequency</term>
538 /// <description>The frequency (in seconds) at which changes to this field will be detected</description>
542 /// The following are optional entries:
544 /// <list type="bullet">
546 /// <term>update</term>
547 /// <description>Specifies the DOM ID of the element whose
548 /// innerHTML should be updated with the
549 /// XMLHttpRequest response text</description>
552 /// <term>with</term>
553 /// <description>A Javascript expression specifying the parameters
554 /// for the XMLHttpRequest. This defaults to 'value', which in the
555 /// evaluated context refers to the new field value</description>
559 /// <param name="options">the options for the Ajax invocation</param>
560 /// <returns>javascript that activates the observer</returns>
561 public String
ObserveForm(IDictionary options
)
563 String formId
= (String
) options
["form"];
565 if (!options
.Contains("with"))
567 options
["with"] = "Form.serialize(" + formId
+ ")";
570 return BuildObserver("Form.Observer", formId
, options
);
575 #region Periodically Call
578 /// Periodically invokes the specified <c>url</c>. You can use the options to
579 /// override the default <c>frequency</c> (defaults to 10 seconds).
581 /// <param name="options">the options for the Ajax invocation</param>
582 /// <returns>javascript that activates the timer</returns>
583 public String
PeriodicallyCallRemote(IDictionary options
)
585 String url
= (String
) options
["url"];
587 options
.Remove("url");
589 return PeriodicallyCallRemote(url
, options
);
593 /// Periodically invokes the specified <c>url</c>. You can use the options to
594 /// override the default <c>frequency</c> (defaults to 10 seconds).
596 /// <param name="options">the options for the Ajax invocation</param>
597 /// <param name="url">url to be invoked periodically</param>
598 /// <returns>javascript that activates the timer</returns>
599 public String
PeriodicallyCallRemote(String url
, IDictionary options
)
603 options
= new HybridDictionary();
606 if (!options
.Contains("frequency"))
608 options
["frequency"] = "10";
611 String code
= String
.Format("new PeriodicalExecuter(function() {{ {0} }}, {1} )",
612 BuildRemoteFunction(url
, options
), options
["frequency"]);
614 return String
.Format( "<script>{0}</script>", code
);
619 #region AutoCompletion
622 /// Rendes a input field with Google style autocomplete enabled.
623 /// The specified <c>url</c> is used to gather the contents
624 /// for the auto complete panel, so
625 /// and your action should return filtered and sorted results.
627 /// The following entries must exist in the options:
629 /// <list type="bullet">
631 /// <term>input</term>
632 /// <description>The text input element id</description>
636 /// <description>url to to call when the field has changed</description>
641 /// it is assumed that the url invoked returns an unordered list.
643 /// <param name="options">the options for the Ajax invocation</param>
644 /// <param name="tagAttributes">attributes for the input html element</param>
645 /// <returns>javascript that activates the timer</returns>
646 public String
InputTextWithAutoCompletion(IDictionary options
, IDictionary tagAttributes
)
648 String input
= (String
) options
["input"];
649 String url
= (String
) options
["url"];
651 options
.Remove("input");
652 options
.Remove("url");
654 return InputTextWithAutoCompletion(input
, url
, tagAttributes
, options
);
658 /// Rendes a input field with Google style autocomplete enabled.
659 /// The specified url is used to gather the contents for the auto complete panel, so
660 /// and your action should return filtered and sorted results.
661 /// <seealso cref="AutoCompleteInputText"/>
664 /// it is assumed that the url invoked returns an unordered list.
666 /// <param name="inputName">input element id</param>
667 /// <param name="url">url used to gather results</param>
668 /// <param name="tagAttributes">attributes for the input element</param>
669 /// <param name="completionOptions">options for the autocomplete</param>
670 /// <returns></returns>
671 public String
InputTextWithAutoCompletion(String inputName
, String url
, IDictionary tagAttributes
, IDictionary completionOptions
)
673 StringBuilder sb
= new StringBuilder();
675 sb
.AppendFormat( "<input type=\"text\" autocomplete=\"off\" name=\"{0}\" id=\"{0}\" {1}/>",
676 inputName
, GetAttributes(tagAttributes
) );
678 sb
.AppendFormat( "<div id=\"{0}\" class=\"auto_complete\"></div>", inputName
+ "autocomplete" );
680 sb
.Append( AutoCompleteInputText( inputName
, url
, completionOptions
) );
682 return sb
.ToString();
686 /// Generates an javascript block enabling
687 /// auto completion for the specified input text id (<c>elementId</c>).
688 /// You can specify the element to be updated using the options
689 /// dictionary (key <c>update</c>), if you don't we assume
690 /// <c>elementId+autocomplete</c>.
693 /// it is assumed that the url invoked returns an unordered list.
695 /// <param name="elementId">The element id (input type=text)</param>
696 /// <param name="url">The url to be invoked returning results</param>
697 /// <param name="options">the options for the Ajax invocation</param>
698 /// <returns></returns>
699 public String
AutoCompleteInputText(String elementId
, String url
, IDictionary options
)
703 options
= new HybridDictionary();
706 StringBuilder sb
= new StringBuilder();
708 String update
= (String
) options
["update"];
712 update
= elementId
+ "autocomplete";
715 sb
.Append("<script type=\"text/javascript\">");
717 sb
.AppendFormat( "new Ajax.Autocompleter('{0}', '{1}', '{2}'", elementId
, update
, url
);
719 if (options
.Contains("tokens"))
721 String
[] tokens
= options
["tokens"].ToString().Split('|');
723 if (tokens
.Length
== 0)
725 options
.Remove("tokens");
727 else if (tokens
.Length
== 1)
729 options
["tokens"] = tokens
[0];
733 StringBuilder content
= new StringBuilder("new Array(");
735 foreach(String tok
in tokens
)
737 content
.Append('\'').Append(tok
).Append("\',");
740 if(tokens
.Length
> 0)
741 content
.Remove( content
.Length
- 1, 1); // removing extra comma
745 options
["tokens"] = content
.ToString();
749 if (options
.Contains("indicator"))
751 options
["indicator"] = String
.Format( "'{0}'", options
["indicator"] );
756 sb
.Append( JavascriptOptions(options
) );
760 sb
.Append("</script>");
762 return sb
.ToString();
767 #region Supporting methods
770 /// Returns a function that makes a remote invocation,
771 /// using the supplied parameters
773 /// <param name="url">Target url</param>
774 /// <param name="options">the options for the Ajax invocation</param>
775 /// <returns>javascript code</returns>
776 public String
BuildRemoteFunction(String url
, IDictionary options
)
780 options
= new HybridDictionary();
783 options
["url"] = url
;
785 return RemoteFunction(options
);
789 /// Returns a function that makes a remote invocation,
790 /// using the supplied parameters
792 /// <param name="options">the options for the Ajax invocation</param>
793 /// <returns>javascript code</returns>
794 public String
RemoteFunction(IDictionary options
)
796 IDictionary jsOptions
= new HybridDictionary();
798 String javascriptOptionsString
= BuildAjaxOptions(jsOptions
, options
);
800 StringBuilder contents
= new StringBuilder();
802 bool isRequestOnly
= !options
.Contains("update") &&
803 !options
.Contains("success") && !options
.Contains("failure");
807 contents
.Append( "new Ajax.Request(" );
811 contents
.Append( "new Ajax.Updater(" );
813 if (options
.Contains("update"))
815 contents
.AppendFormat( "'{0}', ", options
["update"] );
816 options
.Remove("update");
820 contents
.Append("{");
822 bool commaFirst
= false;
824 if (options
.Contains("success"))
826 contents
.AppendFormat( "success:'{0}'", options
["success"] );
828 options
.Remove("success");
831 if (options
.Contains("failure"))
835 contents
.Append(",");
837 contents
.AppendFormat( "failure:'{0}'", options
["failure"] );
838 options
.Remove("failure");
841 contents
.Append("}, ");
845 if (!options
.Contains("url")) throw new ArgumentException("url is required");
847 contents
.Append( GetUrlOption(options
) );
848 contents
.Append( ", " + javascriptOptionsString
+ ")" );
850 if (options
.Contains("before"))
852 contents
= new StringBuilder( String
.Format("{0}; {1}", options
["before"], contents
) );
854 options
.Remove("before");
857 if (options
.Contains("after"))
859 contents
= new StringBuilder( String
.Format("{1}; {0}", options
["after"], contents
) );
861 options
.Remove("after");
864 if (options
.Contains("condition"))
866 String old
= contents
.ToString();
868 contents
= new StringBuilder(
869 String
.Format("if ( {0} ) {{ {1}; }}", options
["condition"], old
) );
871 options
.Remove("condition");
874 return contents
.ToString();
877 private String
GetUrlOption(IDictionary options
)
879 String url
= (String
) options
["url"];
881 if (url
.StartsWith("<") && url
.EndsWith(">"))
883 return url
.Substring(1, url
.Length
- 2);
886 return "'" + url
+ "'";
890 /// Populates the <paramref name="jsOptions"/> by analyzing the
891 /// options set on the helper <paramref name="options"/>
895 /// The following options are analyzed
897 /// <list type="bullet">
899 /// <term>type</term>
900 /// <description>boolean - sets the <c>asynchronous</c> </description>
903 /// <term>method</term>
904 /// <description>string - sets the <c>method</c>. Possible values are post/get </description>
907 /// <term>evalScripts</term>
908 /// <description>boolean</description>
911 /// <term>position</term>
912 /// <description>string - sets the place where content is inserted (Top, Bottom, After, Before)</description>
915 /// <term>form</term>
916 /// <description>if present, set the parameters request to send the current form serialized</description>
919 /// <term>with</term>
920 /// <description>if present, set its content as the parameters for the ajax request</description>
926 /// <param name="jsOptions">Options that will be used on the js side</param>
927 /// <param name="options">Options passed to the helper method</param>
928 /// <returns></returns>
929 protected String
BuildAjaxOptions(IDictionary jsOptions
, IDictionary options
)
931 BuildCallbacks(jsOptions
, options
);
933 jsOptions
["asynchronous"] = (!options
.Contains("type")).ToString().ToLower(System
.Globalization
.CultureInfo
.InvariantCulture
);
935 if (options
.Contains("method"))
937 jsOptions
["method"] = options
["method"];
940 if (options
.Contains("evalScripts"))
942 jsOptions
["evalScripts"] = options
["evalScripts"];
946 jsOptions
["evalScripts"] = "true";
949 if (options
.Contains("position"))
951 jsOptions
["insertion"] = String
.Format("Insertion.{0}", options
["position"]);
954 if (!options
.Contains("with") && options
.Contains("form"))
956 jsOptions
["parameters"] = "Form.serialize(this)";
958 else if (options
.Contains("with"))
960 jsOptions
["parameters"] = ProcessWith(options
["with"]);
963 return JavascriptOptions(jsOptions
);
966 private string ProcessWith(object with
)
968 if (with
== null) return null;
970 if (with
is IDictionary
)
972 return SQuote(CommonUtils
.BuildQueryString(ServerUtility
, with
as IDictionary
, false));
975 return with
.ToString();
978 private void BuildCallbacks(IDictionary jsOptions
, IDictionary options
)
980 String
[] names
= CallbackEnum
.GetNames( typeof(CallbackEnum
) );
982 foreach(String name
in names
)
984 if (!options
.Contains(name
)) continue;
986 String callbackFunctionName
;
988 String function
= BuildCallbackFunction(
989 (CallbackEnum
) Enum
.Parse( typeof(CallbackEnum
), name
, true),
990 options
[name
].ToString(), out callbackFunctionName
);
992 if (function
== String
.Empty
) return;
994 jsOptions
[callbackFunctionName
] = function
;
999 /// Builds the callback function.
1001 /// <param name="callback">The callback.</param>
1002 /// <param name="code">The code.</param>
1003 /// <param name="name">The name.</param>
1004 /// <returns></returns>
1005 protected String
BuildCallbackFunction(CallbackEnum callback
, String code
, out String name
)
1007 name
= String
.Empty
;
1009 if (callback
== CallbackEnum
.Uninitialized
) return String
.Empty
;
1011 if (callback
!= CallbackEnum
.OnFailure
&& callback
!= CallbackEnum
.OnSuccess
)
1013 name
= "on" + callback
;
1015 else if (callback
== CallbackEnum
.OnFailure
)
1019 else if (callback
== CallbackEnum
.OnSuccess
)
1024 return String
.Format("function(request) {{ {0} }} ", code
);
1028 /// Builds the observer.
1030 /// <param name="clazz">The clazz.</param>
1031 /// <param name="name">The name.</param>
1032 /// <param name="options">The options.</param>
1033 /// <returns></returns>
1034 protected String
BuildObserver(String clazz
, String name
, IDictionary options
)
1036 if (options
.Contains("update") && !options
.Contains("with"))
1038 options
["with"] = "'value=' + value";
1041 String call
= RemoteFunction(options
);
1043 StringBuilder js
= new StringBuilder();
1045 js
.Append( "<script type=\"text/javascript\">" );
1046 js
.Append( String
.Format("new {0}('{1}', {2}, function(element, value) {{ {3} }})",
1047 clazz
, name
, options
["frequency"], call
) );
1048 js
.Append( "</script>" );
1050 return js
.ToString();
1054 /// Gets the options.
1056 /// <param name="url">The URL.</param>
1057 /// <param name="options">The options.</param>
1058 /// <returns></returns>
1059 public IDictionary
GetOptions(String url
, IDictionary options
)
1061 if (options
== null)
1063 options
= new HybridDictionary();
1066 options
["form"] = true;
1067 options
["url"] = url
;
1073 /// Gets the options.
1075 /// <param name="url">The URL.</param>
1076 /// <param name="idOfElementToBeUpdated">The id of element to be updated.</param>
1077 /// <param name="with">The with.</param>
1078 /// <param name="loading">The loading.</param>
1079 /// <param name="loaded">The loaded.</param>
1080 /// <param name="complete">The complete.</param>
1081 /// <param name="interactive">The interactive.</param>
1082 /// <returns></returns>
1083 public IDictionary
GetOptions(String url
, String idOfElementToBeUpdated
,
1084 object with
, String loading
, String loaded
, String complete
, String interactive
)
1086 IDictionary options
= new HybridDictionary();
1088 options
["form"] = true;
1089 options
["url"] = url
;
1090 // options["method"] = method;
1092 if (with
!= null) options
["with"] = with
;
1093 if (idOfElementToBeUpdated
!= null && idOfElementToBeUpdated
.Length
> 0) options
["update"] = idOfElementToBeUpdated
;
1094 if (loading
!= null && loading
.Length
> 0) options
["Loading"] = loading
;
1095 if (loaded
!= null && loaded
.Length
> 0) options
["Loaded"] = loaded
;
1096 if (complete
!= null && complete
.Length
> 0) options
["Complete"] = complete
;
1097 if (interactive
!= null && interactive
.Length
> 0) options
["Interactive"] = interactive
;