/// 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 } }