/// Author: Kevin Zink of BrightMix.com
///
/// This class is derived from ActionResult. It is meant to be used in conjunction with an Ajax call, as it returns Prototype-based javascript.
/// The concept is modeled after Ruby on Rails' RJS framework (rendering javascript from the server) as well as Rails javascript/prototype
/// generator http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper/JavaScriptGenerator/GeneratorMethods.html
///
/// Example Usage in your Controller:
///
/// public ActionResult HideElement(string elementId)
/// {
/// RjsResult r = new RjsResult();
/// r.Effect(elementId, RjsResult.EffectTypes.Hide, null);
/// }
///
/// A more complicated but powerful example of returning the contents of two UserControls and inserting them into two different
's
///
/// public ActionResult InsertUserControl()
/// {
/// ObjectViewData viewData = new ObjectViewData { SomeString = "dude", SomeNumber = 1 };
///
/// var r = new RjsResult();
/// r.Insert("div_one", RjsResult.Positions.Top, "~/Views/Controls/UserControl1.ascx", ObjectViewData, ControllerContext);
/// r.Insert("div_two", RjsResult.Positions.Bottom, "~/Views/Controls/UserControl2.ascx", ObjectViewData, ControllerContext);
///
/// return r;
/// }
///
namespace System.Web.Mvc
{
using System;
using System.Text;
using System.Web;
using System.Collections.Generic;
using System.Security.Policy;
using System.Web.Script.Serialization;
using MvcContrib.UI;
using System.Web.Mvc.Html;
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
public class RjsResult : ActionResult
{
#region Constructors
public RjsResult(bool setContentType)
{
Actions = new List
();
this.SetContentType = setContentType;
}
public RjsResult() : this(false)
{
}
#endregion
#region Private Vars
private bool SetContentType { get; set; }
private List Actions
{
get;
set;
}
#endregion
#region Rjs Actions
public interface IRjsActionBase
{
string Render();
}
private class RjsUpdateAction : IRjsActionBase
{
public RjsUpdateAction(string element, string contents)
{
this.element = element;
this.contents = contents;
}
public string element { get; set; }
public string contents { get; set; }
#region IRjsActionBase Members
public string Render()
{
if (!contents.StartsWith("\""))
contents = "\"" + contents + "\"";
return string.Format("Element.update(\"{0}\", {1});", element, contents);
}
#endregion
}
private class RjsInsertAction : IRjsActionBase
{
public RjsInsertAction(string element, Positions p, string contents)
{
this.element = element;
this.contents = contents;
this.position = p;
}
public string element { get; set; }
public string contents { get; set; }
public Positions position { get; set; }
#region IRjsActionBase Members
public string Render()
{
if (!contents.StartsWith("\""))
contents = "\"" + contents + "\"";
return string.Format("Element.insert(\"{0}\", {{{1}: {2} }});", element, position, contents);
}
#endregion
}
private class RjsStringAction : IRjsActionBase
{
public string contents { get; set; }
public RjsStringAction(string contents)
{
this.contents = contents;
}
#region IRjsActionBase Members
public string Render()
{
return this.contents;
}
#endregion
}
private class RjsShowAction : IRjsActionBase
{
public RjsShowAction(string element)
{
this.element = element;
}
public string element { get; set; }
#region IRjsActionBase Members
public string Render()
{
return string.Format("$(\"{0}\").show();", element);
}
#endregion
}
private class RjsAlertAction : IRjsActionBase
{
public RjsAlertAction(string message)
{
this.message = message;
}
public string message { get; set; }
#region IRjsActionBase Members
public string Render()
{
return string.Format("alert('{0}');", message);
}
#endregion
}
private class RjsHideAction : IRjsActionBase
{
public RjsHideAction(string element)
{
this.element = element;
}
public string element { get; set; }
#region IRjsActionBase Members
public string Render()
{
return string.Format("$(\"{0}\").hide();", element);
}
#endregion
}
private class RjsRemoveAction : IRjsActionBase
{
public RjsRemoveAction(string element)
{
this.element = element;
}
public string element { get; set; }
#region IRjsActionBase Members
public string Render()
{
return string.Format("$(\"{0}\").remove();", element);
}
#endregion
}
private class RjsEffectAction : IRjsActionBase
{
public RjsEffectAction(string element, EffectTypes effect, KeyValuePair[] options)
{
this.options = new Dictionary();
if (options != null)
{
foreach (KeyValuePair pair in options)
this.options.Add(pair.Key, pair.Value);
}
this.element = element;
this.effect = effect;
}
public string element { get; set; }
public EffectTypes effect { get; set; }
public Dictionary options { get; set; }
#region IRjsActionBase Members
public string Render()
{
string ret = string.Format("new Effect.{0}(\"{1}\"", effect.ToString(), element);
ret += ", {";
foreach (string key in options.Keys)
{
ret += string.Format("{0}: {1}", key, options[key]);
}
ret += "});";
return ret;
}
#endregion
}
///
/// Call me from your controller and pass me your ControllerContext and I'll render a UserControl for you and return the contents as a string!
///
///
///
///
///
private string RenderPartialToString(string userControl, object viewData, ControllerContext controllerContext)
{
HtmlHelper h = new HtmlHelper(new ViewContext(controllerContext, new WebFormView("omg"), null, null), new ViewPage());
var blockRenderer = new BlockRenderer(controllerContext.HttpContext);
var r = new RjsResult();
JavaScriptSerializer serializer = new JavaScriptSerializer();
string s = blockRenderer.Capture(
() => RenderPartialExtensions.RenderPartial(h, userControl, viewData)
);
return serializer.Serialize(s);
}
#endregion
#region Fun Enums
public enum Positions
{
Before = 1,
After,
Top,
Bottom
}
public enum EffectTypes
{
Appear = 1,
Fade,
SlideDown,
SlideUp,
Shake,
Highlight
}
#endregion
#region Rjs Methods
///
/// Renders a user control and inserts the contents into specified element
///
///
///
///
///
///
public void Insert(string element, Positions p, string userControl, object viewData, ControllerContext controllerContext)
{
Insert(element, p, RenderPartialToString(userControl, viewData, controllerContext) );
}
///
/// Inserts content into specific element
///
///
///
///
public void Insert(string element, Positions p, string contents)
{
Actions.Add(new RjsInsertAction(element, p, contents));
}
///
/// Update a part of the page by rendering a user control
///
///
///
///
///
public void Update(string element, string userControl, object viewData, ControllerContext controllerContext)
{
Update(element, RenderPartialToString(userControl, viewData, controllerContext));
}
public void Update(string element, string contents)
{
Actions.Add(new RjsUpdateAction(element, contents));
}
///
/// Alert some text
///
///
public void Alert(string message)
{
Actions.Add(new RjsAlertAction(message));
}
///
/// Render some javascript code.. whatever you want
///
///
public void RenderString(string contents)
{
Actions.Add(new RjsStringAction(contents));
}
///
/// Shows an element
///
///
public void Show(string element)
{
Actions.Add(new RjsShowAction(element));
}
///
/// Hides an element
///
///
public void Hide(string element)
{
Actions.Add(new RjsHideAction(element));
}
///
/// Delets an element
///
///
public void Remove(string element)
{
Actions.Add(new RjsHideAction(element));
}
///
/// Calls an effect of type EffectTypes, also takes array of prototype options
///
///
///
///
public void Effect(string element, EffectTypes effect, KeyValuePair[] options)
{
Actions.Add(new RjsEffectAction(element, effect, options));
}
public void Effect(string element, EffectTypes effect)
{
Actions.Add(new RjsEffectAction(element, effect, null));
}
#endregion
#region ActionResult Override
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
if (this.SetContentType)
response.ContentType = "application/javascript";
string result = string.Empty;
foreach (IRjsActionBase action in Actions)
{
result += action.Render();
}
response.Write(result);
}
#endregion
}
}