I remember that some months ago I’ve found a beauty video of a beauty component that allows to manage .js and .css files from an MVC application.
Unfortunately I’ve lost the link and I don’t remember the name of the component.
I’ve searched the seven seas of the internet but… nothing. Things went worst today when I realized I need a script manager.
I’ve searched, browsed and digged the internet again but the best I’ve found is the “Simple script manager” on codeplex, that is well far from being “beauty”
So, I’ve started my own simple script manager. for now it is very basic. it does almost nothing but at least it is in full “MVC” style, by using and respecting the existing design of MVC3, differently from the other things I’ve found.
so: here is the code
namespace Web.Helpers
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Web.Mvc;
using System.Web.WebPages;
/// <summary>
/// Provides a way to declare in any place of cshtml pages the required .css and .js, they will be generated later in the _layout page
/// </summary>
public static class FileHelper
{
/// <summary>
/// Requires a file to be referenced
/// </summary>
/// <param name="helper">the Html helper this method extends</param>
/// <param name="resource">the path to the resource</param>
/// <returns>null</returns>
/// <remarks>the extension of the file .css or .js allows the method to decide wich tag should be generated
/// this method may affect the AdditionalScripts and the AdditionalStyles property in the ViewBag</remarks>
public static object Require(this HtmlHelper helper, string resource)
{
if (!Path.HasExtension(resource)) throw new ArgumentException("Impossible to determine the file type as it doesn't have extension");
if (Path.GetExtension(resource).Equals(".css", StringComparison.InvariantCultureIgnoreCase))
{
return RequireCss(helper, resource);
}
if (Path.GetExtension(resource).Equals(".js", StringComparison.InvariantCultureIgnoreCase))
{
return RequireJs(helper, resource);
}
throw new ArgumentException("Only .js and .css are supported");
}
/// <summary>
/// Requires a javascript script file to be referenced
/// </summary>
/// <param name="helper">the Html helper this method extends</param>
/// <param name="resource">the path to the script</param>
/// <returns>null</returns>
/// <remarks>this method affects the AdditionalScripts property in the ViewBag</remarks>
public static object RequireJs(this HtmlHelper helper, string script)
{
HashSet<string> requiredScript = GetScriptTable(helper);
if (!requiredScript.Contains(script))
{
requiredScript.Add(script);
}
return null;
}
/// <summary>
/// Requires a css script file to be referenced
/// </summary>
/// <param name="helper">the Html helper this method extends</param>
/// <param name="resource">the path to the script</param>
/// <returns>null</returns>
/// <remarks>this method affects the AdditionalScripts property in the ViewBag</remarks>
public static object RequireCss(this HtmlHelper helper, string style)
{
HashSet<string> requiredStyle = GetStyleTable(helper);
if (!requiredStyle.Contains(style))
{
requiredStyle.Add(style);
}
return null;
}
private static HashSet<string> GetScriptTable(HtmlHelper helper)
{
HashSet<string> requiredScripts;
if (helper.ViewContext.Controller.ViewBag.AdditionalScripts == null)
{
requiredScripts = new HashSet<string>();
helper.ViewContext.Controller.ViewBag.AdditionalScripts = requiredScripts;
}
else
{
requiredScripts = helper.ViewContext.Controller.ViewBag.AdditionalScripts;
}
return requiredScripts;
}
private static HashSet<string> GetStyleTable(HtmlHelper helper)
{
HashSet<string> requiredStyles;
if (helper.ViewContext.Controller.ViewBag.AdditionalStyles == null)
{
requiredStyles = new HashSet<string>();
helper.ViewContext.Controller.ViewBag.AdditionalStyles = requiredStyles;
}
else
{
requiredStyles = helper.ViewContext.Controller.ViewBag.AdditionalStyles;
}
return requiredStyles;
}
/// <summary>
/// renders the tag to reference the required javascripts
/// </summary>
/// <param name="helper">the HtmlHelper this method extends</param>
/// <returns>a set of tags that represents the required javascripts</returns>
public static HelperResult RenderRequiredJs(this HtmlHelper helper)
{
return new HelperResult(writer => GenerateAllScriptsTags(writer, GetScriptTable(helper)));
}
private static void GenerateAllScriptsTags(TextWriter writer, HashSet<string> requests)
{
if (requests == null) return;
foreach (var script in requests)
{
var builder = new TagBuilder("script");
builder.Attributes.Add("src", script);
builder.Attributes.Add("type", "text/javascript");
writer.WriteLine(builder.ToString(TagRenderMode.Normal));
}
}
/// <summary>
/// renders the tag to reference the required css
/// </summary>
/// <param name="helper">the HtmlHelper this method extends</param>
/// <returns>a set of tags that represents the required styles sheets</returns>
public static HelperResult RenderRequiredCss(this HtmlHelper helper)
{
return new HelperResult(writer => GenerateAllStylesTags(writer, GetStyleTable(helper)));
}
private static void GenerateAllStylesTags(TextWriter writer, HashSet<string> requests)
{
if (requests == null) return;
foreach (var style in requests)
{
var builder = new TagBuilder("link");
builder.Attributes.Add("href", style);
builder.Attributes.Add("rel", "stylesheet");
builder.Attributes.Add("type", "text/css");
writer.WriteLine(builder.ToString(TagRenderMode.SelfClosing));
}
}
/// <summary>
/// renders the tags to reference the required javascripts and css
/// </summary>
/// <param name="helper">the HtmlHelper this method extends</param>
/// <returns>a set of tags that represents the required javascripts and css</returns>
public static HelperResult RenderRequiredFiles(this HtmlHelper helper)
{
return new HelperResult(writer =>
{
GenerateAllStylesTags(writer, GetStyleTable(helper));
GenerateAllScriptsTags(writer, GetStyleTable(helper));
});
}
}
}
and with this I can write in my pages things like
@Html.Require(Url.Content("~/Content/tinymce/tinymce.css"))
@Html.Require(Url.Content("~/Scripts/jquery.validate.min.js"))
@Html.Require(Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js"))
and finally render the required tag in the _Layout.cshtml by writing
@Html.RenderRequiredFiles()
And forgetting about the rest.
I like MVC because it is very easy to extend!
Tags: asp.net, mvc3, scriptmanager