Merge remote-tracking branch 'origin/6.2.0' into 7.0.0-member-editor-wip
Conflicts: src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadContent.cs
This commit is contained in:
14
src/Umbraco.Core/IDisposeOnRequestEnd.cs
Normal file
14
src/Umbraco.Core/IDisposeOnRequestEnd.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Any class implementing this interface that is added to the httpcontext.items keys or values will be disposed of at the end of the request.
|
||||
/// </summary>
|
||||
public interface IDisposeOnRequestEnd : IDisposable
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.CodeAnnotations;
|
||||
|
||||
@@ -9,7 +10,8 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public static class UmbracoObjectTypesExtensions
|
||||
{
|
||||
private static readonly Dictionary<UmbracoObjectTypes, Guid> UmbracoObjectTypeCache = new Dictionary<UmbracoObjectTypes,Guid>();
|
||||
//MUST be concurrent to avoid thread collisions!
|
||||
private static readonly ConcurrentDictionary<UmbracoObjectTypes, Guid> UmbracoObjectTypeCache = new ConcurrentDictionary<UmbracoObjectTypes, Guid>();
|
||||
|
||||
/// <summary>
|
||||
/// Get an UmbracoObjectTypes value from it's name
|
||||
@@ -48,24 +50,22 @@ namespace Umbraco.Core.Models
|
||||
/// <returns>a GUID value of the UmbracoObjectTypes</returns>
|
||||
public static Guid GetGuid(this UmbracoObjectTypes umbracoObjectType)
|
||||
{
|
||||
if (UmbracoObjectTypeCache.ContainsKey(umbracoObjectType))
|
||||
return UmbracoObjectTypeCache[umbracoObjectType];
|
||||
return UmbracoObjectTypeCache.GetOrAdd(umbracoObjectType, types =>
|
||||
{
|
||||
var type = typeof(UmbracoObjectTypes);
|
||||
var memInfo = type.GetMember(umbracoObjectType.ToString());
|
||||
var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoObjectTypeAttribute),
|
||||
false);
|
||||
|
||||
var type = typeof(UmbracoObjectTypes);
|
||||
var memInfo = type.GetMember(umbracoObjectType.ToString());
|
||||
var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoObjectTypeAttribute),
|
||||
false);
|
||||
if (attributes.Length == 0)
|
||||
return Guid.Empty;
|
||||
|
||||
if (attributes.Length == 0)
|
||||
return Guid.Empty;
|
||||
var attribute = ((UmbracoObjectTypeAttribute)attributes[0]);
|
||||
if (attribute == null)
|
||||
return Guid.Empty;
|
||||
|
||||
var attribute = ((UmbracoObjectTypeAttribute)attributes[0]);
|
||||
if (attribute == null)
|
||||
return Guid.Empty;
|
||||
|
||||
UmbracoObjectTypeCache.Add(umbracoObjectType, attribute.ObjectId);
|
||||
|
||||
return attribute.ObjectId;
|
||||
return attribute.ObjectId;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// can then override any additional execution (such as additional loggging, functionality, etc...) that we need to without breaking compatibility since we'll always be exposing
|
||||
/// this object instead of the base PetaPoco database object.
|
||||
/// </remarks>
|
||||
public class UmbracoDatabase : Database
|
||||
public class UmbracoDatabase : Database, IDisposeOnRequestEnd
|
||||
{
|
||||
private readonly Guid _instanceId = Guid.NewGuid();
|
||||
/// <summary>
|
||||
|
||||
@@ -16,6 +16,16 @@ namespace Umbraco.Core
|
||||
private static readonly ConcurrentDictionary<Type, FieldInfo[]> GetFieldsCache = new ConcurrentDictionary<Type, FieldInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]> GetPropertiesCache = new ConcurrentDictionary<Tuple<Type, bool, bool, bool>, PropertyInfo[]>();
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the method is actually overriding a base method
|
||||
/// </summary>
|
||||
/// <param name="m"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsOverride(MethodInfo m)
|
||||
{
|
||||
return m.GetBaseDefinition().DeclaringType != m.DeclaringType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find all assembly references that are referencing the assignTypeFrom Type's assembly found in the assemblyList
|
||||
/// </summary>
|
||||
|
||||
@@ -274,6 +274,7 @@
|
||||
<Compile Include="Events\SaveEventArgs.cs" />
|
||||
<Compile Include="Events\SendToPublishEventArgs.cs" />
|
||||
<Compile Include="IApplicationEventHandler.cs" />
|
||||
<Compile Include="IDisposeOnRequestEnd.cs" />
|
||||
<Compile Include="IO\ResizedImage.cs" />
|
||||
<Compile Include="IO\UmbracoMediaFile.cs" />
|
||||
<Compile Include="Macros\XsltExtension.cs" />
|
||||
|
||||
127
src/Umbraco.Tests/Trees/BaseContentTreeTests.cs
Normal file
127
src/Umbraco.Tests/Trees/BaseContentTreeTests.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using umbraco.cms.presentation.Trees;
|
||||
|
||||
namespace Umbraco.Tests.Trees
|
||||
{
|
||||
[TestFixture]
|
||||
public class BaseContentTreeTests
|
||||
{
|
||||
|
||||
[TearDown]
|
||||
public void TestTearDown()
|
||||
{
|
||||
BaseTree.AfterTreeRender -= EventHandler;
|
||||
BaseTree.BeforeTreeRender -= EventHandler;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Run_Optimized()
|
||||
{
|
||||
var tree1 = new MyOptimizedContentTree1("content");
|
||||
var tree2 = new MyOptimizedContentTree2("content");
|
||||
|
||||
Assert.IsTrue(tree1.UseOptimizedRendering);
|
||||
Assert.IsTrue(tree2.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Not_Optimized_Events_AfterRender()
|
||||
{
|
||||
var tree = new MyOptimizedContentTree1("content");
|
||||
|
||||
BaseTree.AfterTreeRender += EventHandler;
|
||||
|
||||
Assert.IsFalse(tree.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Not_Optimized_Events_BeforeRender()
|
||||
{
|
||||
var tree = new MyOptimizedContentTree1("content");
|
||||
|
||||
BaseTree.BeforeTreeRender += EventHandler;
|
||||
|
||||
Assert.IsFalse(tree.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Not_Optimized_Overriden_Method()
|
||||
{
|
||||
var tree = new MyNotOptimizedContentTree("content");
|
||||
|
||||
Assert.IsFalse(tree.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
private void EventHandler(object sender, TreeEventArgs treeEventArgs)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//optimized because we are not overriding OnRenderNode
|
||||
public class MyOptimizedContentTree1 : BaseContentTree
|
||||
{
|
||||
public MyOptimizedContentTree1(string application)
|
||||
: base(application)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CreateRootNode(ref XmlTreeNode rootNode)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class MyOptimizedContentTree2 : BaseContentTree
|
||||
{
|
||||
public MyOptimizedContentTree2(string application)
|
||||
: base(application)
|
||||
{
|
||||
}
|
||||
|
||||
protected override bool LoadMinimalDocument
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected override void CreateRootNode(ref XmlTreeNode rootNode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//even if we override it will still be optimized because of the LoadMinimalDocument flag
|
||||
protected override void OnRenderNode(ref XmlTreeNode xNode, umbraco.cms.businesslogic.web.Document doc)
|
||||
{
|
||||
base.OnRenderNode(ref xNode, doc);
|
||||
}
|
||||
}
|
||||
|
||||
public class MyNotOptimizedContentTree : BaseContentTree
|
||||
{
|
||||
public MyNotOptimizedContentTree(string application)
|
||||
: base(application)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CreateRootNode(ref XmlTreeNode rootNode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool LoadMinimalDocument
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
protected override void OnRenderNode(ref XmlTreeNode xNode, umbraco.cms.businesslogic.web.Document doc)
|
||||
{
|
||||
base.OnRenderNode(ref xNode, doc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
65
src/Umbraco.Tests/Trees/BaseMediaTreeTests.cs
Normal file
65
src/Umbraco.Tests/Trees/BaseMediaTreeTests.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using NUnit.Framework;
|
||||
using umbraco.cms.presentation.Trees;
|
||||
|
||||
namespace Umbraco.Tests.Trees
|
||||
{
|
||||
[TestFixture]
|
||||
public class BaseMediaTreeTests
|
||||
{
|
||||
|
||||
[TearDown]
|
||||
public void TestTearDown()
|
||||
{
|
||||
BaseTree.AfterTreeRender -= EventHandler;
|
||||
BaseTree.BeforeTreeRender -= EventHandler;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Run_Optimized()
|
||||
{
|
||||
var tree = new MyOptimizedMediaTree("media");
|
||||
|
||||
Assert.IsTrue(tree.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Not_Optimized_Events_AfterRender()
|
||||
{
|
||||
var tree = new MyOptimizedMediaTree("media");
|
||||
|
||||
BaseTree.AfterTreeRender += EventHandler;
|
||||
|
||||
Assert.IsFalse(tree.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Not_Optimized_Events_BeforeRender()
|
||||
{
|
||||
var tree = new MyOptimizedMediaTree("media");
|
||||
|
||||
BaseTree.BeforeTreeRender += EventHandler;
|
||||
|
||||
Assert.IsFalse(tree.UseOptimizedRendering);
|
||||
}
|
||||
|
||||
private void EventHandler(object sender, TreeEventArgs treeEventArgs)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class MyOptimizedMediaTree : BaseMediaTree
|
||||
{
|
||||
public MyOptimizedMediaTree(string application)
|
||||
: base(application)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CreateRootNode(ref XmlTreeNode rootNode)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -427,6 +427,8 @@
|
||||
<Compile Include="TestHelpers\Entities\MockedContentTypes.cs" />
|
||||
<Compile Include="TestHelpers\Entities\MockedEntity.cs" />
|
||||
<Compile Include="TestHelpers\Entities\MockedMedia.cs" />
|
||||
<Compile Include="Trees\BaseContentTreeTests.cs" />
|
||||
<Compile Include="Trees\BaseMediaTreeTests.cs" />
|
||||
<Compile Include="UmbracoExamine\ContentServiceTest.cs" />
|
||||
<Compile Include="UmbracoExamine\EventsTest.cs" />
|
||||
<Compile Include="TypeHelperTests.cs" />
|
||||
|
||||
@@ -28,11 +28,13 @@ namespace Umbraco.Web.Routing
|
||||
/// <param name="pcr">The content request.</param>
|
||||
public PublishedContentRequestEngine(PublishedContentRequest pcr)
|
||||
{
|
||||
if (pcr == null) throw new ArgumentException("pcr is null.");
|
||||
_pcr = pcr;
|
||||
|
||||
_routingContext = pcr.RoutingContext;
|
||||
|
||||
var umbracoContext = _routingContext.UmbracoContext;
|
||||
if (_routingContext == null) throw new ArgumentException("pcr.RoutingContext is null.");
|
||||
|
||||
var umbracoContext = _routingContext.UmbracoContext;
|
||||
if (umbracoContext == null) throw new ArgumentException("pcr.RoutingContext.UmbracoContext is null.");
|
||||
if (umbracoContext.RoutingContext != _routingContext) throw new ArgumentException("RoutingContext confusion.");
|
||||
// no! not set yet.
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Umbraco.Web
|
||||
/// <summary>
|
||||
/// Class that encapsulates Umbraco information of a specific HTTP request
|
||||
/// </summary>
|
||||
public class UmbracoContext : DisposableObject
|
||||
public class UmbracoContext : DisposableObject, IDisposeOnRequestEnd
|
||||
{
|
||||
private const string HttpContextItemName = "Umbraco.Web.UmbracoContext";
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
@@ -527,11 +527,15 @@ namespace Umbraco.Web
|
||||
/// <param name="http"></param>
|
||||
private static void DisposeHttpContextItems(HttpContext http)
|
||||
{
|
||||
// do not process if client-side request
|
||||
if (http.Request.Url.IsClientSideRequest())
|
||||
return;
|
||||
|
||||
//get a list of keys to dispose
|
||||
var keys = new HashSet<object>();
|
||||
foreach (DictionaryEntry i in http.Items)
|
||||
{
|
||||
if (i.Value is IDisposable || i.Key is IDisposable)
|
||||
if (i.Value is IDisposeOnRequestEnd || i.Key is IDisposeOnRequestEnd)
|
||||
{
|
||||
keys.Add(i.Key);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using umbraco.BasePages;
|
||||
using umbraco.BusinessLogic;
|
||||
@@ -25,14 +27,7 @@ namespace umbraco.cms.presentation.Trees
|
||||
public BaseContentTree(string application) : base(application) { }
|
||||
|
||||
private User _user;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the (legacy) Document object passed to the OnRenderNode-method
|
||||
/// should be initialized with a full set of properties.
|
||||
/// By default the Document will be initialized, so setting the boolean to True will
|
||||
/// ensure that the Document object is loaded with a minimum set of properties to
|
||||
/// improve performance.
|
||||
/// </summary>
|
||||
|
||||
protected virtual bool LoadMinimalDocument { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -74,61 +69,69 @@ function openContent(id) {
|
||||
/// Renders the specified tree item.
|
||||
/// </summary>
|
||||
/// <param name="Tree">The tree.</param>
|
||||
/*public override void Render(ref XmlTree Tree)
|
||||
{
|
||||
//get documents to render
|
||||
Document[] docs = Document.GetChildrenForTree(m_id);
|
||||
|
||||
var args = new TreeEventArgs(Tree);
|
||||
OnBeforeTreeRender(docs, args);
|
||||
|
||||
foreach (Document dd in docs)
|
||||
{
|
||||
List<IAction> allowedUserOptions = GetUserActionsForNode(dd);
|
||||
if (CanUserAccessNode(dd, allowedUserOptions))
|
||||
{
|
||||
|
||||
XmlTreeNode node = CreateNode(dd, allowedUserOptions);
|
||||
|
||||
OnRenderNode(ref node, dd);
|
||||
|
||||
OnBeforeNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
if (node != null)
|
||||
{
|
||||
Tree.Add(node);
|
||||
OnAfterNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
OnAfterTreeRender(docs, args);
|
||||
}*/
|
||||
public override void Render(ref XmlTree Tree)
|
||||
{
|
||||
//get documents to render
|
||||
var entities = Services.EntityService.GetChildren(m_id, UmbracoObjectTypes.Document).ToArray();
|
||||
|
||||
var args = new TreeEventArgs(Tree);
|
||||
OnBeforeTreeRender(entities, args, true);
|
||||
|
||||
foreach (var entity in entities)
|
||||
if (UseOptimizedRendering == false)
|
||||
{
|
||||
var e = entity as UmbracoEntity;
|
||||
List<IAction> allowedUserOptions = GetUserActionsForNode(e);
|
||||
if (CanUserAccessNode(e, allowedUserOptions))
|
||||
//We cannot run optimized mode since there are subscribers to events/methods that require document instances
|
||||
// so we'll render the original way by looking up the docs.
|
||||
|
||||
//get documents to render
|
||||
var docs = Document.GetChildrenForTree(m_id);
|
||||
|
||||
var args = new TreeEventArgs(Tree);
|
||||
OnBeforeTreeRender(docs, args);
|
||||
|
||||
foreach (var dd in docs)
|
||||
{
|
||||
XmlTreeNode node = CreateNode(e, allowedUserOptions);
|
||||
|
||||
OnRenderNode(ref node, new Document(entity, LoadMinimalDocument));
|
||||
|
||||
OnBeforeNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
if (node != null)
|
||||
var allowedUserOptions = GetUserActionsForNode(dd);
|
||||
if (CanUserAccessNode(dd, allowedUserOptions))
|
||||
{
|
||||
Tree.Add(node);
|
||||
OnAfterNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
|
||||
var node = CreateNode(dd, allowedUserOptions);
|
||||
|
||||
OnRenderNode(ref node, dd);
|
||||
|
||||
OnBeforeNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
if (node != null)
|
||||
{
|
||||
Tree.Add(node);
|
||||
OnAfterNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
OnAfterTreeRender(docs, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//We ARE running in optmized mode, this means we will NOT be raising the BeforeTreeRender or AfterTreeRender
|
||||
// events and NOT calling the OnRenderNode method - we've already detected that there are not subscribers or implementations
|
||||
// to call so that is fine.
|
||||
|
||||
var entities = Services.EntityService.GetChildren(m_id, UmbracoObjectTypes.Document).ToArray();
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
var e = entity as UmbracoEntity;
|
||||
var allowedUserOptions = GetUserActionsForNode(e);
|
||||
if (CanUserAccessNode(e, allowedUserOptions))
|
||||
{
|
||||
var node = CreateNode(e, allowedUserOptions);
|
||||
|
||||
//in optimized mode the LoadMinimalDocument will ALWAYS be true, if it is not true then we will
|
||||
// be rendering in non-optimized mode and this code will not get executed so we don't need to worry
|
||||
// about performance here.
|
||||
OnRenderNode(ref node, new Document(e, LoadMinimalDocument));
|
||||
|
||||
OnBeforeNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
if (node != null)
|
||||
{
|
||||
Tree.Add(node);
|
||||
OnAfterNodeRender(ref Tree, ref node, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OnAfterTreeRender(entities, args, true);
|
||||
}
|
||||
|
||||
#region Tree Create-node-helper Methods - Legacy
|
||||
@@ -476,5 +479,35 @@ function openContent(id) {
|
||||
return umbraco.BusinessLogic.Actions.Action.FromString(fullMenu);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if we can use the EntityService to render the tree or revert to the original way
|
||||
/// using normal documents
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We determine this by:
|
||||
/// * If there are any subscribers to the events: BeforeTreeRender or AfterTreeRender - then we cannot run optimized
|
||||
/// * If there are any overrides of the method: OnRenderNode - then we cannot run optimized
|
||||
/// </remarks>
|
||||
internal bool UseOptimizedRendering
|
||||
{
|
||||
get
|
||||
{
|
||||
if (HasEntityBasedEventSubscribers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//now we need to check if the current tree type has OnRenderNode overridden with a custom implementation
|
||||
//Strangely - this even works in med trust!
|
||||
var method = this.GetType().GetMethod("OnRenderNode", BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(XmlTreeNode).MakeByRefType(), typeof(Document) }, null);
|
||||
if (TypeHelper.IsOverride(method) && LoadMinimalDocument == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
@@ -10,6 +11,7 @@ using Umbraco.Core.PropertyEditors;
|
||||
using umbraco.BasePages;
|
||||
using umbraco.BusinessLogic;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
using umbraco.interfaces;
|
||||
using Umbraco.Core;
|
||||
using Media = umbraco.cms.businesslogic.media.Media;
|
||||
@@ -21,7 +23,6 @@ namespace umbraco.cms.presentation.Trees
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public abstract class BaseMediaTree : BaseTree
|
||||
{
|
||||
private DisposableTimer _timer;
|
||||
private User _user;
|
||||
|
||||
public BaseMediaTree(string application)
|
||||
@@ -61,78 +62,109 @@ function openMedia(id) {
|
||||
}
|
||||
}
|
||||
|
||||
//Updated Render method for improved performance, but currently not usable because of backwards compatibility
|
||||
//with the OnBeforeTreeRender/OnAfterTreeRender events, which sends an array for legacy Media items.
|
||||
public override void Render(ref XmlTree tree)
|
||||
{
|
||||
//_timer = DisposableTimer.Start(x => LogHelper.Debug<BaseMediaTree>("Media tree loaded" + " (took " + x + "ms)"));
|
||||
|
||||
var entities = Services.EntityService.GetChildren(m_id, UmbracoObjectTypes.Media).ToArray();
|
||||
|
||||
var args = new TreeEventArgs(tree);
|
||||
OnBeforeTreeRender(entities, args, false);
|
||||
|
||||
foreach (UmbracoEntity entity in entities)
|
||||
if (UseOptimizedRendering == false)
|
||||
{
|
||||
XmlTreeNode xNode = XmlTreeNode.Create(this);
|
||||
xNode.NodeID = entity.Id.ToString(CultureInfo.InvariantCulture);
|
||||
xNode.Text = entity.Name;
|
||||
//We cannot run optimized mode since there are subscribers to events/methods that require document instances
|
||||
// so we'll render the original way by looking up the docs.
|
||||
|
||||
xNode.HasChildren = entity.HasChildren;
|
||||
xNode.Source = this.IsDialog ? GetTreeDialogUrl(entity.Id) : GetTreeServiceUrl(entity.Id);
|
||||
var docs = new Media(m_id).Children;
|
||||
|
||||
xNode.Icon = entity.ContentTypeIcon;
|
||||
xNode.OpenIcon = entity.ContentTypeIcon;
|
||||
|
||||
if (IsDialog == false)
|
||||
var args = new TreeEventArgs(tree);
|
||||
OnBeforeTreeRender(docs, args);
|
||||
|
||||
foreach (var dd in docs)
|
||||
{
|
||||
if(this.ShowContextMenu == false)
|
||||
xNode.Menu = null;
|
||||
xNode.Action = "javascript:openMedia(" + entity.Id + ");";
|
||||
}
|
||||
else
|
||||
{
|
||||
xNode.Menu = this.ShowContextMenu ? new List<IAction>(new IAction[] { ActionRefresh.Instance }) : null;
|
||||
if (this.DialogMode == TreeDialogModes.fulllink)
|
||||
var e = dd;
|
||||
var xNode = PerformNodeRender(e.Id, e.Text, e.HasChildren, e.ContentType.IconUrl, e.ContentType.Alias, () => GetLinkValue(e, e.Id.ToString(CultureInfo.InvariantCulture)));
|
||||
|
||||
|
||||
OnBeforeNodeRender(ref tree, ref xNode, EventArgs.Empty);
|
||||
if (xNode != null)
|
||||
{
|
||||
string nodeLink = GetLinkValue(entity);
|
||||
if (string.IsNullOrEmpty(nodeLink) == false)
|
||||
{
|
||||
xNode.Action = "javascript:openMedia('" + nodeLink + "');";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.Equals(entity.ContentTypeAlias, Constants.Conventions.MediaTypes.Folder, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
//#U4-2254 - Inspiration to use void from here: http://stackoverflow.com/questions/4924383/jquery-object-object-error
|
||||
xNode.Action = "javascript:void jQuery('.umbTree #" + entity.Id.ToString(CultureInfo.InvariantCulture) + "').click();";
|
||||
}
|
||||
else
|
||||
{
|
||||
xNode.Action = null;
|
||||
xNode.Style.DimNode();
|
||||
}
|
||||
}
|
||||
tree.Add(xNode);
|
||||
OnAfterNodeRender(ref tree, ref xNode, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
OnAfterTreeRender(docs, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
//We ARE running in optmized mode, this means we will NOT be raising the BeforeTreeRender or AfterTreeRender
|
||||
// events - we've already detected that there are not subscribers or implementations
|
||||
// to call so that is fine.
|
||||
|
||||
var entities = Services.EntityService.GetChildren(m_id, UmbracoObjectTypes.Media).ToArray();
|
||||
|
||||
foreach (UmbracoEntity entity in entities)
|
||||
{
|
||||
var e = entity;
|
||||
var xNode = PerformNodeRender(e.Id, entity.Name, e.HasChildren, e.ContentTypeIcon, e.ContentTypeAlias, () => GetLinkValue(e));
|
||||
|
||||
OnBeforeNodeRender(ref tree, ref xNode, EventArgs.Empty);
|
||||
if (xNode != null)
|
||||
{
|
||||
tree.Add(xNode);
|
||||
OnAfterNodeRender(ref tree, ref xNode, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private XmlTreeNode PerformNodeRender(int nodeId, string nodeName, bool hasChildren, string icon, string contentTypeAlias, Func<string> getLinkValue)
|
||||
{
|
||||
var xNode = XmlTreeNode.Create(this);
|
||||
xNode.NodeID = nodeId.ToString(CultureInfo.InvariantCulture);
|
||||
xNode.Text = nodeName;
|
||||
|
||||
xNode.HasChildren = hasChildren;
|
||||
xNode.Source = this.IsDialog ? GetTreeDialogUrl(nodeId) : GetTreeServiceUrl(nodeId);
|
||||
|
||||
xNode.Icon = icon;
|
||||
xNode.OpenIcon = icon;
|
||||
|
||||
if (IsDialog == false)
|
||||
{
|
||||
if (this.ShowContextMenu == false)
|
||||
xNode.Menu = null;
|
||||
xNode.Action = "javascript:openMedia(" + nodeId + ");";
|
||||
}
|
||||
else
|
||||
{
|
||||
xNode.Menu = this.ShowContextMenu ? new List<IAction>(new IAction[] { ActionRefresh.Instance }) : null;
|
||||
if (this.DialogMode == TreeDialogModes.fulllink)
|
||||
{
|
||||
string nodeLink = getLinkValue();
|
||||
if (string.IsNullOrEmpty(nodeLink) == false)
|
||||
{
|
||||
xNode.Action = "javascript:openMedia('" + nodeLink + "');";
|
||||
}
|
||||
else
|
||||
{
|
||||
xNode.Action = "javascript:openMedia('" + entity.Id.ToString(CultureInfo.InvariantCulture) + "');";
|
||||
if (string.Equals(contentTypeAlias, Constants.Conventions.MediaTypes.Folder, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
//#U4-2254 - Inspiration to use void from here: http://stackoverflow.com/questions/4924383/jquery-object-object-error
|
||||
xNode.Action = "javascript:void jQuery('.umbTree #" + nodeId.ToString(CultureInfo.InvariantCulture) + "').click();";
|
||||
}
|
||||
else
|
||||
{
|
||||
xNode.Action = null;
|
||||
xNode.Style.DimNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OnBeforeNodeRender(ref tree, ref xNode, EventArgs.Empty);
|
||||
if (xNode != null)
|
||||
else
|
||||
{
|
||||
tree.Add(xNode);
|
||||
OnAfterNodeRender(ref tree, ref xNode, EventArgs.Empty);
|
||||
xNode.Action = "javascript:openMedia('" + nodeId.ToString(CultureInfo.InvariantCulture) + "');";
|
||||
}
|
||||
}
|
||||
|
||||
//stop the timer and log the output
|
||||
//_timer.Dispose();
|
||||
|
||||
OnAfterTreeRender(entities, args, false);
|
||||
return xNode;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value for a link in WYSIWYG mode, by default only media items that have a
|
||||
@@ -192,5 +224,26 @@ function openMedia(id) {
|
||||
/// </summary>
|
||||
public static List<Guid> LinkableMediaDataTypes { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if we can use the EntityService to render the tree or revert to the original way
|
||||
/// using normal documents
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We determine this by:
|
||||
/// * If there are any subscribers to the events: BeforeTreeRender or AfterTreeRender - then we cannot run optimized
|
||||
/// </remarks>
|
||||
internal bool UseOptimizedRendering
|
||||
{
|
||||
get
|
||||
{
|
||||
if (HasEntityBasedEventSubscribers)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,6 +528,7 @@ namespace umbraco.cms.presentation.Trees
|
||||
AfterTreeRender(sender, e);
|
||||
}
|
||||
|
||||
[Obsolete("Do not use this method to raise events, it is no longer used and will cause very high performance spikes!")]
|
||||
protected internal virtual void OnBeforeTreeRender(IEnumerable<IUmbracoEntity> sender, TreeEventArgs e, bool isContent)
|
||||
{
|
||||
if (BeforeTreeRender != null)
|
||||
@@ -543,6 +544,7 @@ namespace umbraco.cms.presentation.Trees
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Do not use this method to raise events, it is no longer used and will cause very high performance spikes!")]
|
||||
protected internal virtual void OnAfterTreeRender(IEnumerable<IUmbracoEntity> sender, TreeEventArgs e, bool isContent)
|
||||
{
|
||||
if (AfterTreeRender != null)
|
||||
@@ -558,6 +560,14 @@ namespace umbraco.cms.presentation.Trees
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if there are subscribers to either BeforeTreeRender or AfterTreeRender
|
||||
/// </summary>
|
||||
internal bool HasEntityBasedEventSubscribers
|
||||
{
|
||||
get { return BeforeTreeRender != null || AfterTreeRender != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that is raised once actions are assigned to nodes
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user