Created
February 18, 2011 03:02
-
-
Save johnkchow/833179 to your computer and use it in GitHub Desktop.
MvcScriptController - Compresses all script in a global js directory into one file
HtmlHelperExtension - automatically generate <link> elements for css files depending on controller/action
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Web.Mvc; | |
using System.Web; | |
using System.IO; | |
using Core.Service; | |
namespace NestleGFGL.Extensions.Helpers | |
{ | |
public static class HtmlHelperExtension | |
{ | |
private const string _scriptHtmlFormat = "<script type=\"text/javascript\" src=\"{0}\"></script>"; | |
public static IHtmlString GetGlobalScriptsTag(this HtmlHelper html) | |
{ | |
UrlHelper urlHelper = new UrlHelper(html.ViewContext.RequestContext); | |
string baseUrl = urlHelper.RouteUrl(new { controller = "MvcScript", action = "GetGlobalScripts" }); | |
string url = string.Format("{0}/{1}/{2}", baseUrl, html.ViewData["controller"], html.ViewData["action"]); | |
return new HtmlString(string.Format(_scriptHtmlFormat, url)); | |
} | |
public static IHtmlString GetCssLinks(this HtmlHelper html) | |
{ | |
CssManager cssManager = new CssManager(); | |
return cssManager.GetCssLinks(html); | |
} | |
} | |
// Helper classes below | |
internal class CssManager | |
{ | |
private const string _defaultCssRootDir = "~/content"; | |
private const string _globalDir = "global"; | |
private const string _cssExt = "css"; | |
private const string _cssLinksCacheKey = "cache_key_css_links_{0}_{1}"; | |
private const string _linkFormat = "<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\">"; | |
public CssManager() : this(new ServerPathMapper()) | |
{ | |
} | |
public CssManager(IPathMapper mapper) | |
{ | |
PathMapper = mapper; | |
} | |
public IHtmlString GetCssLinks(HtmlHelper html) | |
{ | |
object returnedValue; | |
string controllerName = html.ViewData.TryGetValue("controller", out returnedValue) ? returnedValue as string : string.Empty; | |
string actionName = html.ViewData.TryGetValue("action", out returnedValue) ? returnedValue as string : string.Empty; | |
string cacheKey = GetCacheKey(controllerName, actionName); | |
IHtmlString htmlString = CoreManager.Cache.Get<IHtmlString>(cacheKey); | |
if (htmlString != null) | |
return htmlString; | |
StringBuilder linksBuilder = new StringBuilder(); | |
List<FileInfo> cssFiles = new List<FileInfo>(); | |
AddFiles(ref cssFiles, BuildUrl(_defaultCssRootDir, _globalDir), _cssExt); | |
AddFiles(ref cssFiles, BuildUrl(_defaultCssRootDir, controllerName), _cssExt); | |
AddFiles(ref cssFiles, BuildUrl(_defaultCssRootDir, controllerName, actionName), _cssExt); | |
if (cssFiles != null) | |
{ | |
foreach (FileInfo file in cssFiles) | |
{ | |
linksBuilder.AppendFormat(_linkFormat, BuildUrl(_defaultCssRootDir, _globalDir, file.Name)); | |
} | |
} | |
htmlString = new HtmlString(string.Format(linksBuilder.ToString())); | |
CoreManager.Cache.Set(cacheKey, htmlString); | |
return htmlString; | |
} | |
protected string GetCacheKey(string controllerName, string actionName) | |
{ | |
return string.Format(_cssLinksCacheKey, controllerName, actionName); | |
} | |
protected string BuildUrl(params object[] urlSections) | |
{ | |
if (urlSections == null || urlSections.Length <= 0) | |
{ | |
return string.Empty; | |
} | |
StringBuilder sb = new StringBuilder(); | |
foreach (object section in urlSections) | |
{ | |
sb.AppendFormat("{0}/", section); | |
} | |
// remove trailing slash | |
sb.Remove(sb.Length - 1, 1); | |
return sb.ToString(); | |
} | |
protected void AddFiles(ref List<FileInfo> fileList, string relativeDirPath, string extension) | |
{ | |
if (fileList == null) | |
fileList = new List<FileInfo>(); | |
List<FileInfo> files = GetFiles(relativeDirPath, extension); | |
if (files != null) | |
fileList.AddRange(files); | |
} | |
protected List<FileInfo> GetFiles(string relativeDirPath, string extension) | |
{ | |
string path = PathMapper.MapPath(relativeDirPath); | |
if (!Directory.Exists(path)) | |
return null; | |
List<FileInfo> files = new List<FileInfo>(); | |
string[] fileNames = Directory.GetFiles(path, "*." + extension, SearchOption.TopDirectoryOnly); | |
foreach (string name in fileNames) | |
{ | |
files.Add(new FileInfo(name)); | |
} | |
return files; | |
} | |
private IPathMapper PathMapper { get; set; } | |
} | |
public interface IPathMapper | |
{ | |
string MapPath(string relativePath); | |
string MapPath(); | |
} | |
public class ServerPathMapper : IPathMapper | |
{ | |
private readonly string _relativePath; | |
public ServerPathMapper() | |
{ | |
} | |
public ServerPathMapper(string relativePath) | |
{ | |
_relativePath = relativePath; | |
} | |
#region Implementation of IPathMapper | |
public string MapPath(string relativePath) | |
{ | |
return HttpContext.Current.Server.MapPath(relativePath); | |
} | |
public string MapPath() | |
{ | |
if (_relativePath != null) | |
if (HttpContext.Current != null) return HttpContext.Current.Server.MapPath(_relativePath); | |
return null; | |
} | |
#endregion | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Web; | |
using System.Web.Mvc; | |
using System.IO; | |
using System.Text; | |
using System.Configuration; | |
using System.Web.UI; | |
using NestleGFGL.Site.Code.Base; | |
using NestleGFGL.Extensions.Helpers; | |
namespace NestleGFGL.Site.Controllers | |
{ | |
public class MvcScriptController : BaseController | |
{ | |
private const string _jsExt = "js"; | |
private const string _cssExt = "css"; | |
private const string DefaultJsDir1 = "~/js/global"; | |
private const string DefaultJsDir2 = "~/scripts/global"; | |
private const string DefaultCssDir = "~/content"; | |
private const string DefaultGlobalDirectoryName = "global"; | |
private const string GlobalJsDirectoryAppKey = "GlobalJSDirectory"; | |
private const string GlobalCssDirectoryAppKey = "GlobalCssDirectory"; | |
public MvcScriptController() | |
{ | |
ServerPathMapper = new ServerPathMapper(); | |
} | |
[OutputCache(Duration = 900, Location = OutputCacheLocation.ServerAndClient)] | |
public FileResult GetGlobalScripts() | |
{ | |
StringBuilder sb = LoadGlobalJavascriptScripts(); | |
return StreamText(sb.ToString(), JsExt); | |
} | |
[OutputCache(Duration = 900, Location = OutputCacheLocation.ServerAndClient)] | |
public FileResult GetStyleSheets(string controllerName) | |
{ | |
StringBuilder sb = LoadStyleSheets(controllerName); | |
return StreamText(sb.ToString(), CssExt); | |
} | |
[OutputCache(Duration = 900, Location = OutputCacheLocation.ServerAndClient)] | |
public FileResult GetGlobalStyleSheets() | |
{ | |
StringBuilder sb = LoadStyleSheets(DefaultGlobalDirectoryName); | |
return StreamText(sb.ToString(), CssExt); | |
} | |
private StringBuilder LoadGlobalJavascriptScripts() | |
{ | |
StringBuilder sb = new StringBuilder(); | |
string jsDirectory; | |
if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings.Get(GlobalJsDirectoryAppKey))) | |
{ | |
jsDirectory = ConfigurationManager.AppSettings.Get(GlobalJsDirectoryAppKey); | |
} | |
else | |
{ | |
jsDirectory = GetDefaultGlobalJavascriptDirectory(); | |
} | |
// Filter any vsdoc files | |
IEnumerable<FileInfo> jsFiles = GetFiles(jsDirectory, JsExt).Where(f => !f.Name.ToLower().EndsWith("-vsdoc.js")); | |
// Filter minimized js files in Debug Mode | |
if (IsDebugMode) | |
{ | |
jsFiles = jsFiles.Where(f => !f.Name.ToLower().EndsWith("min.js")); | |
} | |
if (jsFiles != null) | |
{ | |
foreach (FileInfo file in jsFiles) | |
{ | |
using (StreamReader reader = new StreamReader(file.OpenRead())) | |
{ | |
sb.Append(reader.ReadToEnd()); | |
} | |
} | |
} | |
return sb; | |
} | |
/// <summary> | |
/// Gets stylesheet from path relative to the css root directory | |
/// </summary> | |
/// <param name="relativePath"></param> | |
/// <returns></returns> | |
private StringBuilder LoadStyleSheets(string relativePath) | |
{ | |
if(relativePath.StartsWith("/") || relativePath.StartsWith("~")) | |
throw new ArgumentException("The relative path cannot start with '/' or '~'."); | |
// get css root dir | |
string rootDir = !string.IsNullOrEmpty(ConfigurationManager.AppSettings.Get(GlobalCssDirectoryAppKey)) ? | |
ConfigurationManager.AppSettings.Get(GlobalCssDirectoryAppKey) : GetDefaultRootStyleSheetDirectory(); | |
if (!rootDir.EndsWith("/")) | |
rootDir = string.Concat(rootDir, "/"); | |
string cssDir = string.Concat(rootDir, relativePath); | |
List<FileInfo> files = GetFiles(cssDir, CssExt) ?? new List<FileInfo>(); | |
StringBuilder sb = new StringBuilder(); | |
foreach (FileInfo file in files) | |
{ | |
using (StreamReader reader = new StreamReader(file.OpenRead())) | |
{ | |
sb.Append(reader.ReadToEnd()); | |
} | |
} | |
return sb; | |
} | |
private List<FileInfo> GetFiles(string dirPath, string extension) | |
{ | |
string path = ServerPathMapper.MapPath(dirPath); | |
if (!Directory.Exists(path)) | |
return null; | |
List<FileInfo> files = new List<FileInfo>(); | |
string[] fileNames = Directory.GetFiles(path, "*." + extension, SearchOption.TopDirectoryOnly); | |
foreach (string name in fileNames) | |
{ | |
files.Add(new FileInfo(name)); | |
} | |
return files; | |
} | |
private string GetDefaultGlobalJavascriptDirectory() | |
{ | |
if (Directory.Exists(ServerPathMapper.MapPath(DefaultJsDir1))) | |
return DefaultJsDir1; | |
else if (Directory.Exists(ServerPathMapper.MapPath(DefaultJsDir2))) | |
return DefaultJsDir2; | |
else | |
return string.Empty; | |
} | |
private string GetDefaultRootStyleSheetDirectory() | |
{ | |
if (Directory.Exists(ServerPathMapper.MapPath(DefaultCssDir))) | |
return DefaultCssDir; | |
return string.Empty; | |
} | |
private FileStreamResult StreamText(string inputText, string extension) | |
{ | |
MemoryStream m = new MemoryStream(Encoding.Default.GetBytes(inputText)); | |
return File(m, extension.Equals(CssExt) ? "text/css" : "text/javascript"); | |
} | |
public static IPathMapper ServerPathMapper { get; set; } | |
public bool IsDebugMode | |
{ | |
get | |
{ | |
return ControllerContext.HttpContext.IsDebuggingEnabled; | |
} | |
} | |
public string JsExt | |
{ | |
get | |
{ | |
if (!IsDebugMode) | |
return string.Concat("min.", _jsExt); | |
else | |
return _jsExt; | |
} | |
} | |
public string CssExt | |
{ | |
get | |
{ | |
if (IsDebugMode) | |
return string.Concat("min.", _cssExt); | |
else | |
return _cssExt; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment