WORK IN PROGRESS, DO NOT DOWNLOAD
ClientDependency work. Resolved old 20914 bug. Initial fix to remove Umbraco.aspx page popup. [TFS Changeset #56361]
This commit is contained in:
@@ -15,6 +15,7 @@ namespace umbraco.presentation.ClientDependency
|
||||
public ClientDependencyAttribute()
|
||||
{
|
||||
Priority = DefaultPriority;
|
||||
DoNotOptimize = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -26,6 +27,16 @@ namespace umbraco.presentation.ClientDependency
|
||||
/// </remarks>
|
||||
protected const int DefaultPriority = 100;
|
||||
|
||||
/// <summary>
|
||||
/// If set to true, this file will not be compressed, combined, etc...
|
||||
/// it will be rendered out as is.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Useful for debugging dodgy scripts.
|
||||
/// Default is false.
|
||||
/// </remarks>
|
||||
public bool DoNotOptimize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If dependencies have a composite group name specified, the system will combine all dependency
|
||||
/// file contents under the one group name and GZIP the output to output cache.
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace umbraco.presentation.ClientDependency
|
||||
|
||||
private static ClientDependencyProvider m_Provider = null;
|
||||
private static ClientDependencyProviderCollection m_Providers = null;
|
||||
private static List<string> m_Extensions;
|
||||
private static object m_Lock = new object();
|
||||
|
||||
public static ClientDependencyProvider DefaultProvider
|
||||
@@ -34,6 +35,26 @@ namespace umbraco.presentation.ClientDependency
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The file extensions of Client Dependencies that are file based as opposed to request based.
|
||||
/// Any file that doesn't have the extensions listed here will be request based, request based is
|
||||
/// more overhead for the server to process.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// A request based JavaScript file may be a .ashx that dynamically creates JavaScript server side.
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// If this is not explicitly set, then the extensions 'js' and 'css' are the defaults.
|
||||
/// </remarks>
|
||||
public static List<string> FileBasedDependencyExtensionList
|
||||
{
|
||||
get
|
||||
{
|
||||
LoadProviders();
|
||||
return m_Extensions;
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadProviders()
|
||||
{
|
||||
if (m_Provider == null)
|
||||
@@ -43,7 +64,7 @@ namespace umbraco.presentation.ClientDependency
|
||||
// Do this again to make sure _provider is still null
|
||||
if (m_Provider == null)
|
||||
{
|
||||
ClientDependencySection section = (ClientDependencySection)WebConfigurationManager.GetSection("system.web/imageService");
|
||||
ClientDependencySection section = (ClientDependencySection)WebConfigurationManager.GetSection("system.web/clientDependency");
|
||||
|
||||
m_Providers = new ClientDependencyProviderCollection();
|
||||
|
||||
@@ -55,17 +76,23 @@ namespace umbraco.presentation.ClientDependency
|
||||
ProvidersHelper.InstantiateProviders(section.Providers, m_Providers, typeof(ClientDependencyProvider));
|
||||
m_Provider = m_Providers[section.DefaultProvider];
|
||||
if (m_Provider == null)
|
||||
throw new ProviderException("Unable to load default ImageProvider");
|
||||
throw new ProviderException("Unable to load default ClientDependency provider");
|
||||
}
|
||||
else
|
||||
{
|
||||
//get the default settings
|
||||
section = new ClientDependencySection();
|
||||
m_Extensions = section.FileBasedDependencyExtensionList;
|
||||
|
||||
PageHeaderProvider php = new PageHeaderProvider();
|
||||
php.Initialize(PageHeaderProvider.DefaultName, null);
|
||||
m_Providers.Add(php);
|
||||
ClientSideRegistrationProvider csrp = new ClientSideRegistrationProvider();
|
||||
csrp.Initialize(ClientSideRegistrationProvider.DefaultName, null);
|
||||
m_Providers.Add(csrp);
|
||||
m_Provider = m_Providers[PageHeaderProvider.DefaultName];
|
||||
|
||||
//set the default
|
||||
m_Provider = m_Providers[section.DefaultProvider];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace umbraco.presentation.ClientDependency
|
||||
{
|
||||
DependencyType = ClientDependencyType.Javascript;
|
||||
Priority = DefaultPriority;
|
||||
DoNotOptimize = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -23,6 +24,16 @@ namespace umbraco.presentation.ClientDependency
|
||||
/// </remarks>
|
||||
protected const int DefaultPriority = 100;
|
||||
|
||||
/// <summary>
|
||||
/// If set to true, this file will not be compressed, combined, etc...
|
||||
/// it will be rendered out as is.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Useful for debugging dodgy scripts.
|
||||
/// Default is false.
|
||||
/// </remarks>
|
||||
public bool DoNotOptimize { get; set; }
|
||||
|
||||
public ClientDependencyType DependencyType { get; set; }
|
||||
public string FilePath { get; set; }
|
||||
public string PathNameAlias { get; set; }
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Web;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Net;
|
||||
|
||||
namespace umbraco.presentation.ClientDependency
|
||||
{
|
||||
@@ -63,7 +64,7 @@ namespace umbraco.presentation.ClientDependency
|
||||
if (string.IsNullOrEmpty(fileset))
|
||||
throw new ArgumentException("Must specify a fileset in the request");
|
||||
|
||||
byte[] fileBytes = CombineFiles(fileset, context);
|
||||
byte[] fileBytes = CombineFiles(fileset, context, type);
|
||||
byte[] outputBytes = CompressBytes(context, fileBytes);
|
||||
SetCaching(context);
|
||||
|
||||
@@ -77,22 +78,61 @@ namespace umbraco.presentation.ClientDependency
|
||||
/// <param name="fileList"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
private byte[] CombineFiles(string fileList, HttpContext context)
|
||||
private byte[] CombineFiles(string fileList, HttpContext context, ClientDependencyType type)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream(5000);
|
||||
//get the file list, and write the contents of each file to the output stream.
|
||||
string[] strFiles = DecodeFrom64(fileList).Split(';');
|
||||
StreamWriter sw = new StreamWriter(ms);
|
||||
StreamWriter sw = new StreamWriter(ms);
|
||||
foreach (string s in strFiles)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(s))
|
||||
{
|
||||
FileInfo fi = new FileInfo(context.Server.MapPath(s));
|
||||
if (!fi.Exists)
|
||||
throw new NullReferenceException("File could not be found: " + fi.FullName);
|
||||
string fileContents = File.ReadAllText(fi.FullName);
|
||||
sw.WriteLine(fileContents);
|
||||
try
|
||||
{
|
||||
FileInfo fi = new FileInfo(context.Server.MapPath(s));
|
||||
if (ClientDependencyHelper.FileBasedDependencyExtensionList.Contains(fi.Extension.ToLower().Replace(".", "")))
|
||||
{
|
||||
//if the file doesn't exist, then we'll assume it is a URI external request
|
||||
if (!fi.Exists)
|
||||
{
|
||||
WriteRequestToStream(ref sw, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if it is a file based dependency then read it
|
||||
string fileContents = File.ReadAllText(fi.FullName);
|
||||
sw.WriteLine(fileContents);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//if it's not a file based dependency, try to get the request output.
|
||||
WriteRequestToStream(ref sw, s);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Type exType = ex.GetType();
|
||||
if (exType.Equals(typeof(NotSupportedException)) || exType.Equals(typeof(ArgumentException)))
|
||||
{
|
||||
//could not parse the string into a fileinfo, so we assume it is a URI
|
||||
WriteRequestToStream(ref sw, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if this fails, log the exception in trace, but continue
|
||||
HttpContext.Current.Trace.Warn("ClientDependency", "Could not load file contents from " + s, ex);
|
||||
System.Diagnostics.Debug.Assert(false, "Could not load file contents from " + s, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ClientDependencyType.Javascript)
|
||||
{
|
||||
sw.Write(";;;"); //write semicolons in case the js isn't formatted correctly. This also helps for debugging.
|
||||
}
|
||||
|
||||
}
|
||||
sw.Flush();
|
||||
byte[] outputBytes = ms.ToArray();
|
||||
@@ -101,6 +141,74 @@ namespace umbraco.presentation.ClientDependency
|
||||
return outputBytes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the output of an external request to the stream. Returns true/false if succesful or not.
|
||||
/// </summary>
|
||||
/// <param name="sw"></param>
|
||||
/// <param name="url"></param>
|
||||
/// <returns></returns>
|
||||
private bool WriteRequestToStream(ref StreamWriter sw, string url)
|
||||
{
|
||||
string requestOutput;
|
||||
bool rVal = false;
|
||||
rVal = TryReadUri(url, out requestOutput);
|
||||
if (rVal)
|
||||
{
|
||||
//write the contents of the external request.
|
||||
sw.WriteLine(requestOutput);
|
||||
}
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to convert the url to a uri, then read the request into a string and return it.
|
||||
/// This takes into account relative vs absolute URI's
|
||||
/// </summary>
|
||||
/// <param name="url"></param>
|
||||
/// <param name="requestContents"></param>
|
||||
/// <returns></returns>
|
||||
private bool TryReadUri(string url, out string requestContents)
|
||||
{
|
||||
Uri uri;
|
||||
if (Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out uri))
|
||||
{
|
||||
if (uri.IsAbsoluteUri)
|
||||
{
|
||||
WebClient client = new WebClient();
|
||||
try
|
||||
{
|
||||
requestContents = client.DownloadString(uri.AbsoluteUri);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HttpContext.Current.Trace.Warn("ClientDependency", "Could not load file contents from " + url, ex);
|
||||
System.Diagnostics.Debug.Assert(false, "Could not load file contents from " + url, ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//its a relative path so use the execute method
|
||||
StringWriter sw = new StringWriter();
|
||||
try
|
||||
{
|
||||
HttpContext.Current.Server.Execute(url, sw);
|
||||
requestContents = sw.ToString();
|
||||
sw.Close();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
HttpContext.Current.Trace.Warn("ClientDependency", "Could not load file contents from " + url, ex);
|
||||
System.Diagnostics.Debug.Assert(false, "Could not load file contents from " + url, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
requestContents = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the output cache parameters and also the client side caching parameters
|
||||
/// </summary>
|
||||
@@ -112,7 +220,7 @@ namespace umbraco.presentation.ClientDependency
|
||||
TimeSpan duration = TimeSpan.FromDays(10);
|
||||
HttpCachePolicy cache = context.Response.Cache;
|
||||
cache.SetCacheability(HttpCacheability.Public);
|
||||
cache.SetExpires(DateTime.Now.Add(duration));
|
||||
cache.SetExpires(DateTime.Now.Add(duration));
|
||||
cache.SetMaxAge(duration);
|
||||
cache.SetValidUntilExpires(true);
|
||||
cache.SetLastModified(DateTime.Now);
|
||||
@@ -133,7 +241,7 @@ namespace umbraco.presentation.ClientDependency
|
||||
/// Compresses the bytes if the browser supports it
|
||||
/// </summary>
|
||||
private byte[] CompressBytes(HttpContext context, byte[] fileBytes)
|
||||
{
|
||||
{
|
||||
string acceptEncoding = context.Request.Headers["Accept-Encoding"];
|
||||
if (!string.IsNullOrEmpty(acceptEncoding))
|
||||
{
|
||||
@@ -141,18 +249,21 @@ namespace umbraco.presentation.ClientDependency
|
||||
Stream compressedStream = null;
|
||||
acceptEncoding = acceptEncoding.ToLowerInvariant();
|
||||
bool isCompressed = false;
|
||||
if (acceptEncoding.Contains("gzip"))
|
||||
{
|
||||
context.Response.AddHeader("Content-encoding", "gzip");
|
||||
compressedStream = new GZipStream(ms, CompressionMode.Compress, true);
|
||||
isCompressed = true;
|
||||
}
|
||||
else if (acceptEncoding.Contains("deflate"))
|
||||
|
||||
//deflate is faster in .Net according to Mads Kristensen (blogengine.net)
|
||||
if (acceptEncoding.Contains("deflate"))
|
||||
{
|
||||
context.Response.AddHeader("Content-encoding", "deflate");
|
||||
compressedStream = new DeflateStream(ms, CompressionMode.Compress, true);
|
||||
isCompressed = true;
|
||||
}
|
||||
else if (acceptEncoding.Contains("gzip"))
|
||||
{
|
||||
context.Response.AddHeader("Content-encoding", "gzip");
|
||||
compressedStream = new GZipStream(ms, CompressionMode.Compress, true);
|
||||
isCompressed = true;
|
||||
}
|
||||
|
||||
if (isCompressed)
|
||||
{
|
||||
//write the bytes to the compressed stream
|
||||
|
||||
@@ -12,5 +12,6 @@ namespace umbraco.presentation.ClientDependency
|
||||
int Priority { get; set; }
|
||||
//string CompositeGroupName { get; set; }
|
||||
string PathNameAlias { get; set; }
|
||||
bool DoNotOptimize { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Text;
|
||||
using System.Web.UI;
|
||||
using System.Configuration.Provider;
|
||||
using System.Web;
|
||||
using System.Linq;
|
||||
|
||||
namespace umbraco.presentation.ClientDependency.Providers
|
||||
{
|
||||
@@ -20,6 +21,8 @@ namespace umbraco.presentation.ClientDependency.Providers
|
||||
|
||||
protected abstract void RegisterJsFiles(List<IClientDependencyFile> jsDependencies);
|
||||
protected abstract void RegisterCssFiles(List<IClientDependencyFile> cssDependencies);
|
||||
protected abstract void ProcessSingleJsFile(string js);
|
||||
protected abstract void ProcessSingleCssFile(string css);
|
||||
|
||||
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
|
||||
{
|
||||
@@ -98,31 +101,44 @@ namespace umbraco.presentation.ClientDependency.Providers
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a full url with the encoded query strings for the handler which will process the composite group.
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="dependencies"></param>
|
||||
/// <param name="groupName"></param>
|
||||
/// <remarks>
|
||||
/// If the DoNotOptimize setting has been set for any of the dependencies in the list, then this will ignore them.
|
||||
/// </remarks>
|
||||
/// <returns></returns>
|
||||
//private string ProcessCompositeGroup(List<IClientDependencyFile> dependencies, string groupName, ClientDependencyType type)
|
||||
//{
|
||||
// string handler = "{0}?s={1}&t={2}";
|
||||
// StringBuilder files = new StringBuilder();
|
||||
// List<IClientDependencyFile> byGroup = dependencies.FindAll(
|
||||
// delegate(IClientDependencyFile a)
|
||||
// {
|
||||
// return a.CompositeGroupName == groupName;
|
||||
// }
|
||||
// );
|
||||
// byGroup.Sort((a, b) => a.Priority.CompareTo(b.Priority));
|
||||
// foreach (IClientDependencyFile a in byGroup)
|
||||
// {
|
||||
// files.Append(a.FilePath + ";");
|
||||
// }
|
||||
// string url = string.Format(handler, CompositeDependencyHandler.HandlerFileName, HttpContext.Current.Server.UrlEncode(EncodeTo64(files.ToString())), type.ToString());
|
||||
// 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 url;
|
||||
//}
|
||||
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;
|
||||
}
|
||||
|
||||
private string EncodeTo64(string toEncode)
|
||||
{
|
||||
@@ -164,21 +180,21 @@ namespace umbraco.presentation.ClientDependency.Providers
|
||||
}
|
||||
}
|
||||
|
||||
internal class SimpleDependencyFile : IClientDependencyFile
|
||||
{
|
||||
public SimpleDependencyFile(string filePath, ClientDependencyType type)
|
||||
{
|
||||
FilePath = filePath;
|
||||
DependencyType = type;
|
||||
}
|
||||
//internal class SimpleDependencyFile : IClientDependencyFile
|
||||
//{
|
||||
// public SimpleDependencyFile(string filePath, ClientDependencyType type)
|
||||
// {
|
||||
// FilePath = filePath;
|
||||
// DependencyType = type;
|
||||
// }
|
||||
|
||||
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; }
|
||||
}
|
||||
// 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; }
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
|
||||
namespace umbraco.presentation.ClientDependency.Providers
|
||||
{
|
||||
@@ -20,6 +21,41 @@ namespace umbraco.presentation.ClientDependency.Providers
|
||||
get { return (string)base["defaultProvider"]; }
|
||||
set { base["defaultProvider"] = value; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The configuration section to set the FileBasedDependencyExtensionList. This is a comma separated list.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If this is not explicitly set, then the extensions 'js' and 'css' are the defaults.
|
||||
/// </remarks>
|
||||
[ConfigurationProperty("fileDependencyExtensions", DefaultValue = "js,css")]
|
||||
protected string FileBasedDepdendenyExtensions
|
||||
{
|
||||
get { return (string)base["fileDependencyExtensions"]; }
|
||||
set { base["fileDependencyExtensions"] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The file extensions of Client Dependencies that are file based as opposed to request based.
|
||||
/// Any file that doesn't have the extensions listed here will be request based, request based is
|
||||
/// more overhead for the server to process.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// A request based JavaScript file may be a .ashx that dynamically creates JavaScript server side.
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// If this is not explicitly set, then the extensions 'js' and 'css' are the defaults.
|
||||
/// </remarks>
|
||||
public List<string> FileBasedDependencyExtensionList
|
||||
{
|
||||
get
|
||||
{
|
||||
return FileBasedDepdendenyExtensions.Split(',')
|
||||
.Select(x => x.Trim().ToLower())
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,6 +43,11 @@ namespace umbraco.presentation.ClientDependency.Providers
|
||||
dependencyCalls.ToString(), true);
|
||||
}
|
||||
|
||||
protected override void ProcessSingleJsFile(string js)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void RegisterCssFiles(List<IClientDependencyFile> cssDependencies)
|
||||
{
|
||||
if (cssDependencies.Count == 0)
|
||||
@@ -62,6 +67,11 @@ namespace umbraco.presentation.ClientDependency.Providers
|
||||
dependencyCalls.ToString(), true);
|
||||
}
|
||||
|
||||
protected override void ProcessSingleCssFile(string css)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private void RegisterDependencyLoader()
|
||||
{
|
||||
// register loader script
|
||||
|
||||
@@ -9,6 +9,8 @@ namespace umbraco.presentation.ClientDependency.Providers
|
||||
{
|
||||
|
||||
public const string DefaultName = "PageHeaderProvider";
|
||||
public const string ScriptEmbed = "<script type=\"text/javascript\" src=\"{0}\"></script>";
|
||||
public const string CssEmbed = "<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\" />";
|
||||
|
||||
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
|
||||
{
|
||||
@@ -21,22 +23,55 @@ namespace umbraco.presentation.ClientDependency.Providers
|
||||
|
||||
protected override void RegisterJsFiles(List<IClientDependencyFile> jsDependencies)
|
||||
{
|
||||
string js = "<script type=\"text/javascript\" src=\"{0}\"></script>";
|
||||
foreach (IClientDependencyFile dependency in jsDependencies)
|
||||
|
||||
if (IsDebugMode)
|
||||
{
|
||||
DependantControl.Page.Trace.Write("ClientDependency", string.Format("Registering: {0}", dependency.FilePath));
|
||||
DependantControl.Page.Header.Controls.Add(new LiteralControl(string.Format(js, dependency.FilePath)));
|
||||
foreach (IClientDependencyFile dependency in jsDependencies)
|
||||
{
|
||||
ProcessSingleJsFile(dependency.FilePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
List<string> jsList = ProcessCompositeList(jsDependencies, ClientDependencyType.Javascript);
|
||||
DependantControl.Page.Trace.Write("ClientDependency", string.Format("Processed composite list: {0}", jsList[0]));
|
||||
foreach (string js in jsList)
|
||||
{
|
||||
ProcessSingleJsFile(js);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ProcessSingleJsFile(string js)
|
||||
{
|
||||
DependantControl.Page.Trace.Write("ClientDependency", string.Format("Registering: {0}", js));
|
||||
DependantControl.Page.Header.Controls.Add(new LiteralControl(string.Format(ScriptEmbed, js)));
|
||||
}
|
||||
|
||||
protected override void RegisterCssFiles(List<IClientDependencyFile> cssDependencies)
|
||||
{
|
||||
string css = "<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\" />";
|
||||
foreach (IClientDependencyFile dependency in cssDependencies)
|
||||
if (IsDebugMode)
|
||||
{
|
||||
DependantControl.Page.Trace.Write("ClientDependency", string.Format("Registering: {0}", dependency.FilePath));
|
||||
DependantControl.Page.Header.Controls.Add(new LiteralControl(string.Format(css, dependency.FilePath)));
|
||||
foreach (IClientDependencyFile dependency in cssDependencies)
|
||||
{
|
||||
ProcessSingleCssFile(dependency.FilePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
List<string> cssList = ProcessCompositeList(cssDependencies, ClientDependencyType.Css);
|
||||
DependantControl.Page.Trace.Write("ClientDependency", string.Format("Processed composite list: {0}", cssList[0]));
|
||||
foreach (string css in cssList)
|
||||
{
|
||||
ProcessSingleCssFile(css);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ProcessSingleCssFile(string css)
|
||||
{
|
||||
DependantControl.Page.Trace.Write("ClientDependency", string.Format("Registering: {0}", css));
|
||||
DependantControl.Page.Header.Controls.Add(new LiteralControl(string.Format(CssEmbed, css)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1806,6 +1806,7 @@
|
||||
<Content Include="umbraco_client\tinymce3\themes\umbraco\langs\no_dlg.js" />
|
||||
<Content Include="umbraco_client\tinymce3\themes\umbraco\langs\sv.js" />
|
||||
<Content Include="umbraco_client\tinymce3\themes\umbraco\langs\sv_dlg.js" />
|
||||
<Content Include="umbraco_client\Tree\UmbracoTree.min.js" />
|
||||
<Content Include="umbraco_client\ui\jQueryWresize.js" />
|
||||
<Content Include="umbraco\js\quickEdit.js" />
|
||||
<Content Include="umbraco\members\search.aspx" />
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace umbraco
|
||||
{
|
||||
protected void Page_Load(object sender, System.EventArgs e)
|
||||
{
|
||||
|
||||
Server.Transfer("umbraco.aspx");
|
||||
// Put user code to initialize the page here
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<umb:ClientDependencyInclude runat="server" ID="ClientDependencyInclude2" DependencyType="Javascript" FilePath="Tree/css.js" PathNameAlias="UmbracoClient" Priority="10" />
|
||||
<umb:ClientDependencyInclude runat="server" ID="ClientDependencyInclude5" DependencyType="Javascript" FilePath="Tree/tree_component.min.js" PathNameAlias="UmbracoClient" Priority="11" />
|
||||
<umb:ClientDependencyInclude runat="server" ID="ClientDependencyInclude3" DependencyType="Javascript" FilePath="Tree/NodeDefinition.js" PathNameAlias="UmbracoClient" Priority="12" />
|
||||
<umb:ClientDependencyInclude runat="server" ID="ClientDependencyInclude4" DependencyType="Javascript" FilePath="Tree/UmbracoTree.js" PathNameAlias="UmbracoClient" Priority="13" />
|
||||
<umb:ClientDependencyInclude runat="server" ID="ClientDependencyInclude4" DependencyType="Javascript" FilePath="Tree/UmbracoTree.min.js" PathNameAlias="UmbracoClient" Priority="13" />
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
app: "",
|
||||
showContext: true,
|
||||
isDialog: false,
|
||||
treeType: "standard"
|
||||
treeType: "standard",
|
||||
umb_clientFolderRoot: "/umbraco_client"
|
||||
}, opts);
|
||||
new Umbraco.Controls.UmbracoTree().init($(this), conf);
|
||||
});
|
||||
@@ -42,6 +43,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
_actionNode: new Umbraco.Controls.NodeDefinition(), //the most recent node right clicked for context menu
|
||||
_activeTreeType: "content", //tracks which is the active tree type, this is used in searching and syncing.
|
||||
_recycleBinId: -20,
|
||||
_umb_clientFolderRoot: "/umbraco_client", //this should be set externally!!!
|
||||
_fullMenu: null,
|
||||
_initNode: null,
|
||||
_menuActions: null,
|
||||
@@ -71,7 +73,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
|
||||
init: function(jItem, opts) {
|
||||
/// <summary>Initializes the tree with the options and stores the tree API in the jQuery data object for the current element</summary>
|
||||
this._init(opts.jsonFullMenu, opts.jsonInitNode, jItem, opts.appActions, opts.uiKeys, opts.app, opts.showContext, opts.isDialog, opts.treeType, opts.serviceUrl, opts.dataUrl);
|
||||
this._init(opts.jsonFullMenu, opts.jsonInitNode, jItem, opts.appActions, opts.uiKeys, opts.app, opts.showContext, opts.isDialog, opts.treeType, opts.serviceUrl, opts.dataUrl, opts.umb_clientFolderRoot);
|
||||
//store the api
|
||||
jItem.addClass(this._treeClass);
|
||||
jItem.data("UmbracoTree", this);
|
||||
@@ -81,7 +83,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
/// <summary>This will rebuild the tree structure for the application specified</summary>
|
||||
|
||||
this._debug("rebuildTree");
|
||||
|
||||
|
||||
if (this._app == null || (this._app.toLowerCase() == app.toLowerCase())) {
|
||||
this._debug("not rebuilding");
|
||||
return;
|
||||
@@ -96,21 +98,21 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
this._tree.destroy();
|
||||
this._container.hide();
|
||||
var _this = this;
|
||||
|
||||
|
||||
//check if we should rebuild from a saved tree
|
||||
var saveData = this._container.data("tree_" + app);
|
||||
if (saveData != null) {
|
||||
this._debug("rebuildTree: rebuilding from cache!");
|
||||
|
||||
|
||||
//create the tree from the saved data.
|
||||
this._initNode = saveData.d;
|
||||
this._tree = $.tree_create();
|
||||
this._tree.init(this._container, this._getInitOptions());
|
||||
|
||||
|
||||
this._configureNodes(this._container.find("li"), true);
|
||||
//select the last node
|
||||
var lastSelected = saveData.selected != null ? $(saveData.selected[0]).attr("id") : null;
|
||||
if (lastSelected != null) {
|
||||
if (lastSelected != null) {
|
||||
//create an event handler for the tree sync
|
||||
var _this = this;
|
||||
var foundHandler = function(EV, node) {
|
||||
@@ -125,15 +127,15 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
//add the event handler for the tree sync and sync the tree
|
||||
this.addEventHandler("syncFound", foundHandler);
|
||||
this.setActiveTreeType($(saveData.selected[0]).attr("umb:type"));
|
||||
this.syncTree(lastSelected);
|
||||
this.syncTree(lastSelected);
|
||||
}
|
||||
else {
|
||||
this._container.show();
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//need to get the init node for the new app
|
||||
var parameters = "{'app':'" + app + "','showContextMenu':'" + this._showContext + "', 'isDialog':'" + this._isDialog + "'}"
|
||||
this._currentAJAXRequest = true;
|
||||
@@ -158,7 +160,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
_this._container.show();
|
||||
_this._loadChildNodes(_this._container.find("li:first"), null);
|
||||
_this._currentAJAXRequest = false;
|
||||
$(_this).trigger("rebuiltTree", [msg.app]);
|
||||
$(_this).trigger("rebuiltTree", [msg.app]);
|
||||
},
|
||||
error: function(e) {
|
||||
_this._debug("rebuildTree: AJAX error occurred");
|
||||
@@ -168,50 +170,50 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
|
||||
saveTreeState: function(appAlias) {
|
||||
/// <summary>
|
||||
/// Saves the state of the current application trees so we can restore it next time the user visits the app
|
||||
/// </summary>
|
||||
|
||||
|
||||
this._debug("saveTreeState: " + appAlias + " : ajax request? " + this._currentAJAXRequest);
|
||||
|
||||
|
||||
//if an ajax request is currently in progress, abort saving the tree state and set the
|
||||
//data object for the application to null.
|
||||
if (this._currentAJAXRequest) {
|
||||
this._container.data("tree_" + appAlias, null);
|
||||
return;
|
||||
}
|
||||
|
||||
var treeData = this._tree.getJSON(null, [ "id", "umb:type", "class" ], [ "umb:nodedata", "href", "class", "style" ]);
|
||||
|
||||
|
||||
var treeData = this._tree.getJSON(null, ["id", "umb:type", "class"], ["umb:nodedata", "href", "class", "style"]);
|
||||
|
||||
//need to update the 'state' of the data. jsTree getJSON doesn't return the state of nodes (yet)!
|
||||
this._updateJSONNodeState(treeData);
|
||||
|
||||
this._container.data("tree_" + appAlias, {selected: this._tree.selected, d: treeData});
|
||||
this._updateJSONNodeState(treeData);
|
||||
|
||||
this._container.data("tree_" + appAlias, { selected: this._tree.selected, d: treeData });
|
||||
},
|
||||
|
||||
|
||||
_updateJSONNodeState: function(obj) {
|
||||
/// <summary>
|
||||
/// A recursive function to store the state of the node for the JSON object when using saveTreeState.
|
||||
/// This is required since jsTree doesn't output the state of the tree nodes with the request to getJSON method.
|
||||
/// </summary>
|
||||
|
||||
|
||||
var node = $("li[id='" + obj.attributes.id + "']").filter(function() {
|
||||
return ($(this).attr("umb:type") == obj.attributes["umb:type"]); //filter based on custom namespace requires custom function
|
||||
});
|
||||
});
|
||||
var c = node.attr("class");
|
||||
if (c != null) {
|
||||
var state = c.indexOf("open") > -1 ? "open" : c.indexOf("closed") > -1 ? "closed" : null;
|
||||
if (state != null) obj.state = state;
|
||||
}
|
||||
}
|
||||
if (obj.children != null) {
|
||||
for (var x in obj.children) {
|
||||
this._updateJSONNodeState(obj.children[x]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
syncTree: function(path, forceReload) {
|
||||
/// <summary>
|
||||
/// Syncronizes the tree with the path supplied and makes that node visible/selected.
|
||||
@@ -504,13 +506,13 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
this._currentAJAXRequest = true;
|
||||
TREE_OBJ.settings.data.url = this._getUrl(nodeDef.sourceUrl);
|
||||
},
|
||||
|
||||
|
||||
onJSONData: function(DATA, TREE_OBJ) {
|
||||
this._debug("onJSONData");
|
||||
this._currentAJAXRequest = false;
|
||||
return DATA;
|
||||
},
|
||||
|
||||
|
||||
onChange: function(NODE, TREE_OBJ) {
|
||||
/// <summary>
|
||||
/// Some code taken from the jsTree checkbox tree theme to allow for checkboxes
|
||||
@@ -762,7 +764,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
return null;
|
||||
},
|
||||
|
||||
_init: function(jFullMenu, jInitNode, treeContainer, appActions, uiKeys, app, showContext, isDialog, treeType, serviceUrl, dataUrl) {
|
||||
_init: function(jFullMenu, jInitNode, treeContainer, appActions, uiKeys, app, showContext, isDialog, treeType, serviceUrl, dataUrl, umbClientFolder) {
|
||||
/// <summary>initialization method, must be called on page ready.</summary>
|
||||
/// <param name="jFullMenu">JSON markup for the full context menu in accordance with the jsTree context menu object standard</param>
|
||||
/// <param name="jInitNode">JSON markup for the initial node to show</param>
|
||||
@@ -774,6 +776,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
/// <param name="treeType">determines the type of tree: false/null = normal, 'checkbox' = checkboxes enabled, 'inheritedcheckbox' = parent nodes have checks inherited from children</param>
|
||||
/// <param name="serviceUrl">Url path for the tree client service</param>
|
||||
/// <param name="dataUrl">Url path for the tree data service</param>
|
||||
/// <param name="umbClientFolder">Should be set externally!... the root to the umbraco_client folder</param>
|
||||
|
||||
this._debug("_init: creating new tree with class/id: " + treeContainer.attr("class") + " / " + treeContainer.attr("id"));
|
||||
|
||||
@@ -787,6 +790,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
this._treeType = treeType;
|
||||
this._serviceUrl = serviceUrl;
|
||||
this._dataUrl = dataUrl;
|
||||
this._umb_clientFolderRoot = umbClientFolder;
|
||||
|
||||
//wire up event handlers
|
||||
if (this._menuActions != null) {
|
||||
@@ -820,7 +824,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
/// <summary>return the initialization objects for the tree</summary>
|
||||
|
||||
this._debug("_getInitOptions");
|
||||
|
||||
|
||||
var _this = this;
|
||||
|
||||
var options = {
|
||||
@@ -836,7 +840,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
rtl: false,
|
||||
animation: false,
|
||||
hover_mode: true,
|
||||
//theme_path: "/umbraco_client/Tree/Themes/",
|
||||
theme_path: this._umb_clientFolderRoot + "/Tree/Themes/",
|
||||
theme_name: "umbraco",
|
||||
context: null //no context menu by default
|
||||
},
|
||||
@@ -847,7 +851,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
rules: {
|
||||
metadata: "umb:nodedata",
|
||||
creatable: "none",
|
||||
draggable : "none"
|
||||
draggable: "none"
|
||||
},
|
||||
callback: {
|
||||
//wrapped functions maintain scope in callback
|
||||
@@ -856,7 +860,7 @@ Umbraco.Sys.registerNamespace("Umbraco.Controls");
|
||||
onopen: function(N, T) { _this.onOpen(N, T) },
|
||||
onselect: function(N, T) { _this.onSelect(N, T) },
|
||||
onchange: function(N, T) { _this.onChange(N, T) },
|
||||
onJSONdata : function (D, T) { return _this.onJSONData(D, T) }
|
||||
onJSONdata: function(D, T) { return _this.onJSONData(D, T) }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
119
umbraco/presentation/umbraco_client/Tree/UmbracoTree.min.js
vendored
Normal file
119
umbraco/presentation/umbraco_client/Tree/UmbracoTree.min.js
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
Umbraco.Sys.registerNamespace("Umbraco.Controls"); (function($) {
|
||||
$.fn.UmbracoTree = function(opts) { return this.each(function() { var conf = $.extend({ jsonFullMenu: null, jsonInitNode: null, appActions: null, uiKeys: null, app: "", showContext: true, isDialog: false, treeType: "standard", umb_clientFolderRoot: "/umbraco_client" }, opts); new Umbraco.Controls.UmbracoTree().init($(this), conf); }); }; $.fn.UmbracoTreeAPI = function() { return $(this).data("UmbracoTree") == null ? null : $(this).data("UmbracoTree"); }; Umbraco.Controls.UmbracoTree = function() {
|
||||
return { _actionNode: new Umbraco.Controls.NodeDefinition(), _activeTreeType: "content", _recycleBinId: -20, _umb_clientFolderRoot: "/umbraco_client", _fullMenu: null, _initNode: null, _menuActions: null, _tree: null, _uiKeys: null, _container: null, _app: null, _showContext: true, _isDialog: false, _isDebug: true, _loadedApps: [], _serviceUrl: "", _dataUrl: "", _treeType: "standard", _treeClass: "umbTree", _currenAJAXRequest: false, addEventHandler: function(fnName, fn) { $(this).bind(fnName, fn); }, removeEventHandler: function(fnName, fn) { $(this).unbind(fnName, fn); }, init: function(jItem, opts) { this._init(opts.jsonFullMenu, opts.jsonInitNode, jItem, opts.appActions, opts.uiKeys, opts.app, opts.showContext, opts.isDialog, opts.treeType, opts.serviceUrl, opts.dataUrl, opts.umb_clientFolderRoot); jItem.addClass(this._treeClass); jItem.data("UmbracoTree", this); }, rebuildTree: function(app) {
|
||||
this._debug("rebuildTree"); if (this._app == null || (this._app.toLowerCase() == app.toLowerCase())) { this._debug("not rebuilding"); return; }
|
||||
else { this._app = app; }
|
||||
$("div").remove(".tree-default-context"); this._tree.destroy(); this._container.hide(); var _this = this; var saveData = this._container.data("tree_" + app); if (saveData != null) {
|
||||
this._debug("rebuildTree: rebuilding from cache!"); this._initNode = saveData.d; this._tree = $.tree_create(); this._tree.init(this._container, this._getInitOptions()); this._configureNodes(this._container.find("li"), true); var lastSelected = saveData.selected != null ? $(saveData.selected[0]).attr("id") : null; if (lastSelected != null) { var _this = this; var foundHandler = function(EV, node) { _this.removeEventHandler("syncFound", foundHandler); this._debug("rebuildTree: node synced, selecting node..."); _this.selectNode(node, false, true); this._container.show(); }; this._debug("rebuildTree: syncing to last selected: " + lastSelected); this.addEventHandler("syncFound", foundHandler); this.setActiveTreeType($(saveData.selected[0]).attr("umb:type")); this.syncTree(lastSelected); }
|
||||
else { this._container.show(); }
|
||||
return;
|
||||
}
|
||||
var parameters = "{'app':'" + app + "','showContextMenu':'" + this._showContext + "', 'isDialog':'" + this._isDialog + "'}"
|
||||
this._currentAJAXRequest = true; $.ajax({ type: "POST", url: this._serviceUrl, data: parameters, contentType: "application/json; charset=utf-8", dataType: "json", success: function(msg) {
|
||||
msg = msg.d; if ($.inArray(msg.app, _this._loadedApps) == -1) { _this._debug("loading js for app: " + msg.app); _this._loadedApps.push(msg.app); _this._container.after("<script>" + msg.js + "</script>"); }
|
||||
_this._initNode = eval(msg.json); _this._tree = $.tree_create(); _this._tree.init(_this._container, _this._getInitOptions()); _this._container.show(); _this._loadChildNodes(_this._container.find("li:first"), null); _this._currentAJAXRequest = false; $(_this).trigger("rebuiltTree", [msg.app]);
|
||||
}, error: function(e) { _this._debug("rebuildTree: AJAX error occurred"); _this._currentAJAXRequest = false; $(_this).trigger("ajaxError", [{ msg: "rebuildTree"}]); }
|
||||
});
|
||||
}, saveTreeState: function(appAlias) {
|
||||
this._debug("saveTreeState: " + appAlias + " : ajax request? " + this._currentAJAXRequest); if (this._currentAJAXRequest) { this._container.data("tree_" + appAlias, null); return; }
|
||||
var treeData = this._tree.getJSON(null, ["id", "umb:type", "class"], ["umb:nodedata", "href", "class", "style"]); this._updateJSONNodeState(treeData); this._container.data("tree_" + appAlias, { selected: this._tree.selected, d: treeData });
|
||||
}, _updateJSONNodeState: function(obj) {
|
||||
var node = $("li[id='" + obj.attributes.id + "']").filter(function() { return ($(this).attr("umb:type") == obj.attributes["umb:type"]); }); var c = node.attr("class"); if (c != null) { var state = c.indexOf("open") > -1 ? "open" : c.indexOf("closed") > -1 ? "closed" : null; if (state != null) obj.state = state; }
|
||||
if (obj.children != null) { for (var x in obj.children) { this._updateJSONNodeState(obj.children[x]); } }
|
||||
}, syncTree: function(path, forceReload) { this._debug("syncTree: " + path + ", " + forceReload); this._syncTree.call(this, path, forceReload, null, null); }, childNodeCreated: function() {
|
||||
this._debug("childNodeCreated"); var childrenIds = new Array(); this._actionNode.jsNode.find("ul > li").each(function() { childrenIds.push($(this).attr("id")); }); var _this = this; var currId = this._actionNode.nodeId; this.reloadActionNode(true, false, function(success) {
|
||||
if (success && childrenIds.length > 0) {
|
||||
var found = false; var actionNode = _this.findNode(currId); if (actionNode) { actionNode.find("ul > li").each(function() { if ($.inArray($(this).attr("id"), childrenIds) == -1) { found = $(this); } }); }
|
||||
if (found) { _this._debug("childNodeCreated: selecting new child node: " + found.attr("id")); _this.selectNode(found, true, true); $(_this).trigger("newChildNodeFound", [found]); return; }
|
||||
}
|
||||
_this._debug("childNodeCreated: could not select new child!");
|
||||
});
|
||||
}, moveNode: function(nodeId, parentPath) { this._debug("moveNode"); var old = this.findNode(nodeId); if (old) old.remove(); var newPath = parentPath + "," + nodeId; var _this = this; var foundHandler = function(EV, node) { _this.removeEventHandler("syncFound", foundHandler); _this.selectNode(node, false, true); $(_this).trigger("nodeMoved", [node]); }; this.addEventHandler("syncFound", foundHandler); this.syncTree(newPath); }, copyNode: function(nodeId, parentPath) { this._debug("copyNode"); var originalNode = this.findNode(nodeId); var _this = this; var foundHandler = function(EV, node) { _this.removeEventHandler("syncFound", foundHandler); _this._loadChildNodes(node, null); if (originalNode) _this.selectNode(originalNode, true); $(_this).trigger("nodeCopied", [node]); }; this.addEventHandler("syncFound", foundHandler); this.syncTree(parentPath); }, findNode: function(nodeId, findGlobal) { var _this = this; var branch = this._container.find("li[id='" + nodeId + "']"); if (!findGlobal) branch = branch.filter(function() { return ($(this).attr("umb:type") == _this._activeTreeType); }); var found = branch.length > 0 ? branch : false; this._debug("findNode: " + nodeId + " in '" + this._activeTreeType + "' tree. Found? " + found.length); return found; }, selectNode: function(node, supressEvent, reselect) {
|
||||
this._debug("selectNode"); var selectedId = this._tree.selected != null ? $(this._tree.selected[0]).attr("id") : null; if (reselect || (selectedId == null || selectedId != node.attr("id"))) {
|
||||
if (supressEvent) { this._tree.settings.callback.onselect = function() { }; }
|
||||
this._tree.select_branch(node); var _this = this; this._tree.settings.callback.onselect = function(N, T) { _this.onSelect(N, T) };
|
||||
}
|
||||
}, reloadActionNode: function(supressSelect, supressChildReload, callback) {
|
||||
this._debug("reloadActionNode: supressSelect = " + supressSelect + ", supressChildReload = " + supressChildReload); if (this._actionNode != null && this._actionNode.jsNode != null) {
|
||||
var nodeParent = this._actionNode.jsNode.parents("li:first"); this._debug("reloadActionNode: found " + nodeParent.length + " parent nodes"); if (nodeParent.length == 1) {
|
||||
var nodeDef = this._getNodeDef(nodeParent); this._debug("reloadActionNode: loading ajax for node: " + nodeDef.nodeId); var _this = this; var toReplace = $("<li class='last'><a class='loading' href='#'><div>" + (this._tree.settings.lang.loading || "Loading ...") + "</div></a></li>").replaceAll(this._actionNode.jsNode); $.get(this._getUrl(nodeDef.sourceUrl), null, function(msg) {
|
||||
if (!msg || msg.length == 0) { _this._debug("reloadActionNode: error loading ajax data, performing jsTree refresh"); _this._tree.refresh(); if (callback != null) callback.call(_this, false); return; }
|
||||
var oFound = null; for (var o in msg) {
|
||||
if (msg[o].attributes != null && msg[o].attributes.id == _this._actionNode.nodeId) {
|
||||
oFound = _this._tree.parseJSON(msg[o]); if ($(oFound).attr("umb:type") == _this._actionNode.treeType) { break; }
|
||||
else { oFound = null; }
|
||||
}
|
||||
}
|
||||
if (oFound != null) {
|
||||
_this._debug("reloadActionNode: node is refreshed!"); var reloaded = $(oFound).replaceAll(toReplace); _this._configureNodes(reloaded, true); if (!supressSelect) _this.selectNode(reloaded); if (!supressChildReload) { _this._loadChildNodes(reloaded, function() { if (callback != null) callback.call(_this, true); }); }
|
||||
else { if (callback != null) callback.call(_this, true); }
|
||||
}
|
||||
else { _this._debug("reloadActionNode: error finding child node in ajax data, performing jsTree refresh"); _this._tree.refresh(); if (callback != null) callback.call(_this, false); }
|
||||
}, "json"); return;
|
||||
}
|
||||
this._debug("reloadActionNode: error finding parent node, performing jsTree refresh"); this._tree.refresh(); if (callback != null) callback.call(this, false);
|
||||
}
|
||||
}, getActionNode: function() { return this._actionNode; }, setActiveTreeType: function(treeType) { this._activeTreeType = treeType; }, onNodeDeleting: function(EV) {
|
||||
this._debug("onNodeDeleting")
|
||||
this._tree.close_branch(this._actionNode.jsNode); this._actionNode.jsNode.find("a").attr("class", "loading"); this._actionNode.jsNode.find("a").css("background-image", ""); this._actionNode.jsNode.find("a").html(this._uiKeys['deleting']);
|
||||
}, onNodeDeleted: function(EV) { this._debug("onNodeDeleted"); this._actionNode.jsNode.find("a").removeClass("loading"); this._tree.close_branch(this._actionNode.jsNode); this._actionNode.jsNode.hide("drop", { direction: "down" }, 400); this._updateRecycleBin(); }, onNodeRefresh: function(EV) { this._debug("onNodeRefresh"); this._loadChildNodes(this._actionNode.jsNode, null); }, onSelect: function(NODE, TREE_OBJ) {
|
||||
this.setActiveTreeType($(NODE).attr("umb:type")); var js = $(NODE).children("a").attr("href").replace("javascript:", ""); this._debug("onSelect: js: " + js); try { var func = eval(js); if (func != null) { func.call(); } } catch (e) { }
|
||||
return true;
|
||||
}, onOpen: function(NODE, TREE_OBJ) { this._debug("onOpen: " + $(NODE).attr("id")); var nodes = $(NODE).find("ul > li"); this._configureNodes(nodes); return true; }, onBeforeOpen: function(NODE, TREE_OBJ) { var nodeDef = this._getNodeDef($(NODE)); this._debug("onBeforeOpen: " + nodeDef.nodeId); this._currentAJAXRequest = true; TREE_OBJ.settings.data.url = this._getUrl(nodeDef.sourceUrl); }, onJSONData: function(DATA, TREE_OBJ) { this._debug("onJSONData"); this._currentAJAXRequest = false; return DATA; }, onChange: function(NODE, TREE_OBJ) {
|
||||
if (this._treeType == "checkbox") {
|
||||
var $this = $(NODE).is("li") ? $(NODE) : $(NODE).parent(); if ($this.children("a").hasClass("checked")) $this.children("a").removeClass("checked")
|
||||
else $this.children("a").addClass("checked");
|
||||
}
|
||||
else if (this._treeType == "inheritedcheckbox") {
|
||||
var $this = $(NODE).is("li") ? $(NODE) : $(NODE).parent(); if ($this.children("a.unchecked").size() == 0) { TREE_OBJ.container.find("a").addClass("unchecked"); }
|
||||
$this.children("a").removeClass("clicked"); if ($this.children("a").hasClass("checked")) { $this.find("li").andSelf().children("a").removeClass("checked").removeClass("undetermined").addClass("unchecked"); var state = 0; }
|
||||
else { $this.find("li").andSelf().children("a").removeClass("unchecked").removeClass("undetermined").addClass("checked"); var state = 1; }
|
||||
$this.parents("li").each(function() {
|
||||
if (state == 1) {
|
||||
if ($(this).find("a.unchecked, a.undetermined").size() - 1 > 0) { $(this).parents("li").andSelf().children("a").removeClass("unchecked").removeClass("checked").addClass("undetermined"); return false; }
|
||||
else $(this).children("a").removeClass("unchecked").removeClass("undetermined").addClass("checked");
|
||||
}
|
||||
else {
|
||||
if ($(this).find("a.checked, a.undetermined").size() - 1 > 0) { $(this).parents("li").andSelf().children("a").removeClass("unchecked").removeClass("checked").addClass("undetermined"); return false; }
|
||||
else $(this).children("a").removeClass("checked").removeClass("undetermined").addClass("unchecked");
|
||||
}
|
||||
});
|
||||
}
|
||||
$(this).trigger("nodeClicked", [NODE]);
|
||||
}, onRightClick: function(NODE, TREE_OBJ, EV) { this._actionNode = this._getNodeDef($(NODE)); this.setActiveTreeType($(NODE).attr("umb:type")); this._debug("onRightClick: menu = " + this._actionNode.menu); $("div").remove(".tree-default-context"); if (this._actionNode.menu != "") { TREE_OBJ.settings.ui.context = this._getContextMenu(this._actionNode.menu); TREE_OBJ.context_menu(); var timeout = null; TREE_OBJ.context.mouseenter(function() { clearTimeout(timeout); }); TREE_OBJ.context.mouseleave(function() { timeout = setTimeout(function() { TREE_OBJ.hide_context(); }, 400); }); } }, _debug: function(strMsg) { if (this._isDebug) { Sys.Debug.trace("UmbracoTree: " + strMsg); } }, _configureNodes: function(nodes, reconfigure) {
|
||||
var _this = this; if (!reconfigure) { nodes = nodes.not("li[class*='loaded']"); }
|
||||
this._debug("_configureNodes: " + nodes.length); var rxInput = new RegExp("\\boverlay-\\w+\\b", "gi"); nodes.each(function() {
|
||||
if (_this._treeType != "standard") { $(this).children("a:first").css("background", ""); return; }
|
||||
$(this).children("div").remove(); var m = $(this).attr("class").match(rxInput); if (m != null) { for (i = 0; i < m.length; i++) { _this._debug("_configureNodes: adding overlay: " + m[i] + " for node: " + $(this).attr("id")); $(this).children("a:first").before("<div class='overlay " + m[i] + "'></div>"); } }
|
||||
var txt = $(this).children("a").html(); $(this).children("a").html("<div>" + txt + "</div>"); $(this).addClass("loaded");
|
||||
});
|
||||
}, _getNodeDef: function(NODE) { var nodedata = $(NODE).children("a").metadata({ type: 'attr', name: 'umb:nodedata' }); this._debug("_getNodeDef: " + $(NODE).attr("id") + ", " + nodedata.nodeType + ", " + nodedata.source); var def = new Umbraco.Controls.NodeDefinition(); def.updateDefinition(this._tree, $(NODE), $(NODE).attr("id"), $(NODE).find("a > div").html(), nodedata.nodeType, nodedata.source, nodedata.menu, $(NODE).attr("umb:type")); return def; }, _updateRecycleBin: function() { this._debug("_updateRecycleBin"); var rNode = this.findNode(this._recycleBinId, true); if (rNode) { this._actionNode = this._getNodeDef(rNode); var _this = this; this.reloadActionNode(true, true, function(success) { if (success) { _this.findNode(_this._recycleBinId, true).effect("highlight", {}, 1000); } }); } }, _loadChildNodes: function(liNode, callback) { this._debug("_loadChildNodes: " + liNode); liNode.removeClass("leaf"); this._tree.close_branch(liNode, true); liNode.children("ul:eq(0)").html(""); this._tree.open_branch(liNode, false, callback); }, _syncTree: function(path, forceReload, numPaths, numAsync) {
|
||||
this._debug("_syncTree"); var paths = path.split(","); var found = null; var foundIndex = null; if (numPaths == null) numPaths = (paths.length - 0); for (var i = 0; i < numPaths; i++) { foundIndex = paths.length - (1 + i); found = this.findNode(paths[foundIndex]); this._debug("_syncTree: finding... " + paths[foundIndex] + " found? " + found); if (found) break; }
|
||||
if (!found) { this._debug("no node found in path: " + path + " : " + numPaths); $(this).trigger("syncNotFound", [path]); return; }
|
||||
if (found.attr("id") != paths[paths.length - 1]) {
|
||||
var _this = this; this._loadChildNodes(found, function(NODE, TREE_OBJ) {
|
||||
var pathsToSearch = paths.length - (Number(foundIndex) + 1); if (_this.findNode(paths[foundIndex + 1])) { _this._syncTree(path, forceReload, pathsToSearch, (numAsync == null ? numAsync == 1 : ++numAsync)); }
|
||||
else { _this._debug("node not found in children: " + path + " : " + numPaths); $(this).trigger("syncNotFound", [path]); }
|
||||
});
|
||||
}
|
||||
else {
|
||||
var doReload = (forceReload && (numAsync == null || numAsync < 1)); this._debug("_syncTree: found! numAsync: " + numAsync + ", forceReload: " + forceReload); if (doReload) { this._actionNode = this._getNodeDef(found); this.reloadActionNode(true, true, null); }
|
||||
else { if (found.attr("id") != "-1") this.selectNode(found, true); this._configureNodes(found, doReload); }
|
||||
$(this).trigger("syncFound", [found]);
|
||||
}
|
||||
}, _getContextMenu: function(strMenu) {
|
||||
this._debug("_getContextMenu: " + strMenu); var newMenu = new Array(); for (var i = 0; i < strMenu.length; i++) { var letter = strMenu.charAt(i); var menuItem = this._getMenuItemByLetter(letter); if (menuItem != null) newMenu.push(menuItem); }
|
||||
return newMenu;
|
||||
}, _getMenuItemByLetter: function(letter) {
|
||||
if (letter == ",") return "separator"; for (var m in this._fullMenu) { if (this._fullMenu[m].id == letter) { return this._fullMenu[m]; } }
|
||||
return null;
|
||||
}, _init: function(jFullMenu, jInitNode, treeContainer, appActions, uiKeys, app, showContext, isDialog, treeType, serviceUrl, dataUrl, umbClientFolder) {
|
||||
this._debug("_init: creating new tree with class/id: " + treeContainer.attr("class") + " / " + treeContainer.attr("id")); this._fullMenu = jFullMenu; this._initNode = jInitNode; this._menuActions = appActions; this._uiKeys = uiKeys; this._app = app; this._showContext = showContext; this._isDialog = isDialog; this._treeType = treeType; this._serviceUrl = serviceUrl; this._dataUrl = dataUrl; this._umb_clientFolderRoot = umbClientFolder; if (this._menuActions != null) { var _this = this; this._menuActions.addEventHandler("nodeDeleting", function(E) { _this.onNodeDeleting(E) }); this._menuActions.addEventHandler("nodeDeleted", function(E) { _this.onNodeDeleted(E) }); this._menuActions.addEventHandler("nodeRefresh", function(E) { _this.onNodeRefresh(E) }); }
|
||||
this._container = treeContainer; this._tree = $.tree_create(); this._tree.init(this._container, this._getInitOptions()); this._loadChildNodes(this._container.find("li:first"), null);
|
||||
}, _getUrl: function(nodeSource) {
|
||||
if (nodeSource == null || nodeSource == "") { return this._dataUrl; }
|
||||
var params = nodeSource.split("?")[1]; return this._dataUrl + "?" + params + "&rnd2=" + Umbraco.Utils.generateRandom();
|
||||
}, _getInitOptions: function() { this._debug("_getInitOptions"); var _this = this; var options = { data: { type: "json", async: true, url: "", json: this._initNode, async_data: function(NODE) { return null; } }, ui: { dots: false, rtl: false, animation: false, hover_mode: true, theme_path: this._umb_clientFolderRoot + "/Tree/Themes/", theme_name: "umbraco", context: null }, lang: { new_node: "New folder", loading: "<div>" + (this._tree.settings.lang.loading || "Loading ...") + "</div>" }, rules: { metadata: "umb:nodedata", creatable: "none", draggable: "none" }, callback: { onrgtclk: function(N, T, E) { _this.onRightClick(N, T, E) }, beforeopen: function(N, T) { _this.onBeforeOpen(N, T) }, onopen: function(N, T) { _this.onOpen(N, T) }, onselect: function(N, T) { _this.onSelect(N, T) }, onchange: function(N, T) { _this.onChange(N, T) }, onJSONdata: function(D, T) { return _this.onJSONData(D, T) } } }; return options; }
|
||||
};
|
||||
}
|
||||
})(jQuery);
|
||||
Reference in New Issue
Block a user