2009-06-19 07:39:16 +00:00
using System ;
using System.Collections.Generic ;
using System.Text ;
using System.Web.UI ;
using System.Configuration.Provider ;
using System.Web ;
2009-07-13 14:51:26 +00:00
using System.Linq ;
2009-07-16 14:24:37 +00:00
using umbraco.presentation.ClientDependency.Controls ;
2009-06-19 07:39:16 +00:00
namespace umbraco.presentation.ClientDependency.Providers
{
public abstract class ClientDependencyProvider : ProviderBase
{
protected Control DependantControl { get ; private set ; }
protected ClientDependencyPathCollection FolderPaths { get ; private set ; }
2009-06-19 09:32:18 +00:00
protected List < IClientDependencyFile > AllDependencies { get ; private set ; }
/// <summary>
/// Set to true to disable composite scripts so all scripts/css comes through as individual files.
/// </summary>
public bool IsDebugMode { get ; set ; }
2009-06-19 07:39:16 +00:00
protected abstract void RegisterJsFiles ( List < IClientDependencyFile > jsDependencies ) ;
protected abstract void RegisterCssFiles ( List < IClientDependencyFile > cssDependencies ) ;
2009-07-13 14:51:26 +00:00
protected abstract void ProcessSingleJsFile ( string js ) ;
protected abstract void ProcessSingleCssFile ( string css ) ;
2009-06-19 07:39:16 +00:00
2009-06-19 09:32:18 +00:00
public override void Initialize ( string name , System . Collections . Specialized . NameValueCollection config )
{
IsDebugMode = false ;
if ( config ! = null & & config [ "isDebug" ] ! = null )
{
bool isDebug ;
if ( bool . TryParse ( config [ "isDebug" ] , out isDebug ) )
IsDebugMode = isDebug ;
}
base . Initialize ( name , config ) ;
}
2009-07-07 14:27:03 +00:00
public void RegisterDependencies ( Control dependantControl , ClientDependencyList dependencies , ClientDependencyPathCollection paths )
2009-06-19 07:39:16 +00:00
{
DependantControl = dependantControl ;
2009-07-07 14:27:03 +00:00
AllDependencies = new List < IClientDependencyFile > ( dependencies ) ;
2009-06-19 07:39:16 +00:00
FolderPaths = paths ;
UpdateFilePaths ( ) ;
//seperate the types into 2 lists for all dependencies without composite groups
2009-06-19 09:32:18 +00:00
List < IClientDependencyFile > jsDependencies = AllDependencies . FindAll (
delegate ( IClientDependencyFile a )
2009-06-19 07:39:16 +00:00
{
2009-07-07 14:27:03 +00:00
//if (!IsDebugMode)
// return a.DependencyType == ClientDependencyType.Javascript && string.IsNullOrEmpty(a.CompositeGroupName);
//else
2009-06-19 09:32:18 +00:00
return a . DependencyType = = ClientDependencyType . Javascript ;
2009-06-19 07:39:16 +00:00
}
) ;
2009-06-19 09:32:18 +00:00
List < IClientDependencyFile > cssDependencies = AllDependencies . FindAll (
delegate ( IClientDependencyFile a )
2009-06-19 07:39:16 +00:00
{
2009-07-07 14:27:03 +00:00
//if (!IsDebugMode)
// return a.DependencyType == ClientDependencyType.Css && string.IsNullOrEmpty(a.CompositeGroupName);
//else
2009-06-19 09:32:18 +00:00
return a . DependencyType = = ClientDependencyType . Css ;
2009-06-19 07:39:16 +00:00
}
) ;
// sort by priority
jsDependencies . Sort ( ( a , b ) = > a . Priority . CompareTo ( b . Priority ) ) ;
cssDependencies . Sort ( ( a , b ) = > a . Priority . CompareTo ( b . Priority ) ) ;
2009-07-07 14:27:03 +00:00
//if (!IsDebugMode) RegisterCssFiles(ProcessCompositeGroups(ClientDependencyType.Css));
2009-06-19 09:32:18 +00:00
RegisterCssFiles ( cssDependencies . ConvertAll < IClientDependencyFile > ( a = > { return ( IClientDependencyFile ) a ; } ) ) ;
2009-07-07 14:27:03 +00:00
//if (!IsDebugMode) RegisterJsFiles(ProcessCompositeGroups(ClientDependencyType.Javascript));
2009-06-19 07:39:16 +00:00
RegisterJsFiles ( jsDependencies . ConvertAll < IClientDependencyFile > ( a = > { return ( IClientDependencyFile ) a ; } ) ) ;
2009-06-19 09:32:18 +00:00
2009-06-19 07:39:16 +00:00
}
2009-07-07 14:27:03 +00:00
//private List<IClientDependencyFile> ProcessCompositeGroups(ClientDependencyType type)
//{
// List<IClientDependencyFile> dependencies = AllDependencies.FindAll(
// delegate(IClientDependencyFile a)
// {
// return a.DependencyType == type && !string.IsNullOrEmpty(a.CompositeGroupName);
// }
// );
2009-06-19 09:32:18 +00:00
2009-07-07 14:27:03 +00:00
// List<string> groups = new List<string>();
// List<IClientDependencyFile> files = new List<IClientDependencyFile>();
// foreach (IClientDependencyFile a in dependencies)
// {
// if (!groups.Contains(a.CompositeGroupName))
// {
// string url = ProcessCompositeGroup(dependencies, a.CompositeGroupName, type);
// groups.Add(a.CompositeGroupName);
// files.Add(new SimpleDependencyFile(url, type));
// DependantControl.Page.Trace.Write("ClientDependency", "Composite group " + a.CompositeGroupName + " URL: " + url);
// }
// }
// return files;
//}
2009-06-19 07:39:16 +00:00
/// <summary>
2009-07-13 14:51:26 +00:00
/// Returns a list of urls. The array will consist of only one entry if
/// none of the dependencies are tagged as DoNotOptimize, otherwise, if any of them are,
/// this will return the path to the file.
///
/// For the optimized files, the full url with the encoded query strings for the handler which will process the composite list
/// of dependencies. The handler will compbine, compress, minify (if JS), and output cache the results
/// based on a hash key of the base64 encoded string.
2009-06-19 07:39:16 +00:00
/// </summary>
/// <param name="dependencies"></param>
/// <param name="groupName"></param>
2009-07-13 14:51:26 +00:00
/// <remarks>
/// If the DoNotOptimize setting has been set for any of the dependencies in the list, then this will ignore them.
/// </remarks>
2009-06-19 07:39:16 +00:00
/// <returns></returns>
2009-07-13 14:51:26 +00:00
protected List < string > ProcessCompositeList ( List < IClientDependencyFile > dependencies , ClientDependencyType type )
{
List < string > rVal = new List < string > ( ) ;
//build the combined composite list url
string handler = "{0}?s={1}&t={2}" ;
StringBuilder files = new StringBuilder ( ) ;
foreach ( IClientDependencyFile a in dependencies . Where ( x = > ! x . DoNotOptimize ) )
{
files . Append ( a . FilePath + ";" ) ;
}
string combinedurl = string . Format ( handler , CompositeDependencyHandler . HandlerFileName , HttpContext . Current . Server . UrlEncode ( EncodeTo64 ( files . ToString ( ) ) ) , type . ToString ( ) ) ;
rVal . Add ( combinedurl ) ;
//add any urls that are not to be optimized
foreach ( IClientDependencyFile a in dependencies . Where ( x = > x . DoNotOptimize ) )
{
rVal . Add ( a . FilePath ) ;
}
//if (url.Length > CompositeDependencyHandler.MaxHandlerUrlLength)
// throw new ArgumentOutOfRangeException("The number of files in the composite group " + groupName + " creates a url handler address that exceeds the CompositeDependencyHandler MaxHandlerUrlLength. Reducing the amount of files in this composite group should fix the issue");
return rVal ;
}
2009-06-19 07:39:16 +00:00
private string EncodeTo64 ( string toEncode )
{
byte [ ] toEncodeAsBytes = System . Text . ASCIIEncoding . ASCII . GetBytes ( toEncode ) ;
string returnValue = System . Convert . ToBase64String ( toEncodeAsBytes ) ;
return returnValue ;
}
/// <summary>
/// Ensures the correctly resolved file path is set for each dependency (i.e. so that ~ are taken care of) and also
/// prefixes the file path with the correct base path specified for the PathNameAlias if specified.
/// </summary>
/// <param name="dependencies"></param>
/// <param name="paths"></param>
/// <param name="control"></param>
private void UpdateFilePaths ( )
{
2009-06-19 09:32:18 +00:00
foreach ( IClientDependencyFile dependency in AllDependencies )
2009-06-19 07:39:16 +00:00
{
if ( ! string . IsNullOrEmpty ( dependency . PathNameAlias ) )
{
ClientDependencyPath path = FolderPaths . Find (
delegate ( ClientDependencyPath p )
{
return p . Name = = dependency . PathNameAlias ;
}
) ;
if ( path = = null )
{
throw new NullReferenceException ( "The PathNameAlias specified for dependency " + dependency . FilePath + " does not exist in the ClientDependencyPathCollection" ) ;
}
string basePath = path . ResolvedPath . EndsWith ( "/" ) ? path . ResolvedPath : path . ResolvedPath + "/" ;
dependency . FilePath = basePath + dependency . FilePath ;
}
else
{
dependency . FilePath = DependantControl . ResolveUrl ( dependency . FilePath ) ;
}
}
}
2009-07-13 14:51:26 +00:00
//internal class SimpleDependencyFile : IClientDependencyFile
//{
// public SimpleDependencyFile(string filePath, ClientDependencyType type)
// {
// FilePath = filePath;
// DependencyType = type;
// }
2009-06-19 07:39:16 +00:00
2009-07-13 14:51:26 +00:00
// public string FilePath{get;set;}
// public ClientDependencyType DependencyType { get; set; }
// public string InvokeJavascriptMethodOnLoad { get; set; }
// public int Priority { get; set; }
// //public string CompositeGroupName { get; set; }
// public string PathNameAlias { get; set; }
//}
2009-06-19 07:39:16 +00:00
}
}