Skip to content

Instantly share code, notes, and snippets.

@joelpurra
Created April 16, 2012 13:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joelpurra/2398969 to your computer and use it in GitHub Desktop.
Save joelpurra/2398969 to your computer and use it in GitHub Desktop.
MvcScriptHelper: Helps render multiple script blocks from multiple pages/layouts/partial views, in the expected order
//-----------------------------------------------------------------------
// <copyright file="MvcScriptHelper.cs" company="The Swedish Post and Telecom Authority (PTS)">
// Copyright (c) 2011, 2012 The Swedish Post and Telecom Authority (PTS)
// Developed for PTS by Joel Purra <http://joelpurra.se/>
// Released under the BSD license.
// </copyright>
//-----------------------------------------------------------------------
// https://gist.github.com/2398969
namespace JoelPurra.Web.Helpers
{
using System;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.WebPages;
/// <summary>
/// Helps renders multiple script blocks from multiple pages, layouts, partial views in the expected order.
/// </summary>
public static class MvcScriptHelper
{
#region Constants and Fields
private static int counter;
#endregion
#region Public Methods
/// <summary>
/// Renders multiple script blocks from multiple partial views
/// </summary>
/// <remarks>
/// Inspiration from http://stackoverflow.com/questions/5433531/using-sections-in-editor-display-templates/5433722#5433722
/// </remarks>
/// <param name="htmlHelper"> </param>
/// <returns> </returns>
public static IHtmlString RenderScripts(this HtmlHelper htmlHelper)
{
Contract.Requires(htmlHelper != null);
// Order the collection by the key in order to output scripts in the order they were added on each "execution level".
// This is a hack due to the execution order of Razor pages
// See http://mvcdev.com/differences-between-asp-net-razor-and-web-forms-view-engines/
IOrderedEnumerable<object> scriptKeys =
htmlHelper.ViewContext.HttpContext.Items.Keys.Cast<object>().Where(
key => key.GetType() == typeof(int[])).OrderBy(key => string.Join(", ", (int[])key));
foreach (object key in scriptKeys)
{
Func<object, HelperResult> template =
htmlHelper.ViewContext.HttpContext.Items[key] as Func<object, HelperResult>;
if (template != null)
{
htmlHelper.ViewContext.Writer.Write(template(null));
}
}
return MvcHtmlString.Empty;
}
/// <summary>
/// Adds script blocks to be executed in order called.
/// </summary>
/// <example>
/// <![CDATA[@Html.Script(
/// @&lt;script&gt;
/// //&lt;![CDATA[
/// alert("This is a script block!");
/// //]]&gt;
/// &lt;/script&gt;)
/// ]]>
/// </example>
/// <remarks>
/// Inspiration from http://stackoverflow.com/questions/5433531/using-sections-in-editor-display-templates/5433722#5433722
/// </remarks>
/// <param name="htmlHelper"> </param>
/// <param name="razorExecutionLevel"> </param>
/// <param name="template"> One or more script blocks. Surround multiple blocks with the &lt;text&gt; tag. </param>
/// <returns> </returns>
public static MvcHtmlString Script(
this HtmlHelper htmlHelper, RazorExecutionLevel razorExecutionLevel, Func<object, HelperResult> template)
{
Contract.Requires(htmlHelper != null);
Contract.Requires(template != null);
int razorExecutionLevelInt = (int)razorExecutionLevel;
// TODO: Make a new ScriptKey class that is sortable
int[] key = new[]
{
razorExecutionLevelInt, counter
};
htmlHelper.ViewContext.HttpContext.Items.Add(key, template);
counter++;
return MvcHtmlString.Empty;
}
public static MvcHtmlString ScriptInLayout(this HtmlHelper htmlHelper, Func<object, HelperResult> template)
{
Contract.Requires(htmlHelper != null);
Contract.Requires(template != null);
return htmlHelper.Script(RazorExecutionLevel.Layout, template);
}
public static MvcHtmlString ScriptInPage(this HtmlHelper htmlHelper, Func<object, HelperResult> template)
{
Contract.Requires(htmlHelper != null);
Contract.Requires(template != null);
return htmlHelper.Script(RazorExecutionLevel.Page, template);
}
public static MvcHtmlString ScriptInPartialView(this HtmlHelper htmlHelper, Func<object, HelperResult> template)
{
Contract.Requires(htmlHelper != null);
Contract.Requires(template != null);
return htmlHelper.Script(RazorExecutionLevel.PartialView, template);
}
#endregion
}
}
//-----------------------------------------------------------------------
// <copyright file="RazorExecutionLevel.cs" company="The Swedish Post and Telecom Authority (PTS)">
// Copyright (c) 2011, 2012 The Swedish Post and Telecom Authority (PTS)
// Developed for PTS by Joel Purra <http://joelpurra.se/>
// Released under the BSD license.
// </copyright>
//-----------------------------------------------------------------------
// https://gist.github.com/2398969
namespace JoelPurra.Web.Helpers
{
public enum RazorExecutionLevel
{
Layout = 1,
Page = 2,
PartialView = 3
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment