U4-5301 - fix AppendDocumentXml + nodes sorting
This commit is contained in:
@@ -128,59 +128,115 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the children of the parentNode that match the xpath selector
|
||||
/// </summary>
|
||||
/// <param name="parentNode"></param>
|
||||
/// <param name="childXPathSelector">An xpath expression used to select child nodes of the XmlElement</param>
|
||||
/// <param name="childSelector">An expression that returns true if the XElement passed in is a valid child node to be sorted</param>
|
||||
/// <param name="orderByValue">The value to order the results by</param>
|
||||
internal static void SortNodes(
|
||||
/// Sorts the children of a parentNode.
|
||||
/// </summary>
|
||||
/// <param name="parentNode">The parent node.</param>
|
||||
/// <param name="childNodesXPath">An XPath expression to select children of <paramref name="parentNode"/> to sort.</param>
|
||||
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
|
||||
internal static void SortNodes(
|
||||
XmlNode parentNode,
|
||||
string childXPathSelector,
|
||||
Func<XElement, bool> childSelector,
|
||||
Func<XElement, object> orderByValue)
|
||||
string childNodesXPath,
|
||||
Func<XmlNode, int> orderBy)
|
||||
{
|
||||
var sortedChildNodes = parentNode.SelectNodes(childNodesXPath).Cast<XmlNode>()
|
||||
.OrderBy(orderBy)
|
||||
.ToArray();
|
||||
|
||||
// append child nodes to last position, in sort-order
|
||||
// so all child nodes will go after the property nodes
|
||||
foreach (var node in sortedChildNodes)
|
||||
parentNode.AppendChild(node); // moves the node to the last position
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the children of a parentNode if needed.
|
||||
/// </summary>
|
||||
/// <param name="parentNode">The parent node.</param>
|
||||
/// <param name="childNodesXPath">An XPath expression to select children of <paramref name="parentNode"/> to sort.</param>
|
||||
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
|
||||
/// <returns>A value indicating whether sorting was needed.</returns>
|
||||
/// <remarks>same as SortNodes but will do nothing if nodes are already sorted - should improve performances.</remarks>
|
||||
internal static bool SortNodesIfNeeded(
|
||||
XmlNode parentNode,
|
||||
string childNodesXPath,
|
||||
Func<XmlNode, int> orderBy)
|
||||
{
|
||||
// ensure orderBy runs only once per node
|
||||
// checks whether nodes are already ordered
|
||||
// and actually sorts only if needed
|
||||
|
||||
var childNodesAndOrder = parentNode.SelectNodes(childNodesXPath).Cast<XmlNode>()
|
||||
.Select(x => Tuple.Create(x, orderBy(x))).ToArray();
|
||||
|
||||
var a = 0;
|
||||
foreach (var x in childNodesAndOrder)
|
||||
{
|
||||
if (a > x.Item2)
|
||||
{
|
||||
a = -1;
|
||||
break;
|
||||
}
|
||||
a = x.Item2;
|
||||
}
|
||||
|
||||
if (a >= 0)
|
||||
return false;
|
||||
|
||||
// append child nodes to last position, in sort-order
|
||||
// so all child nodes will go after the property nodes
|
||||
foreach (var x in childNodesAndOrder.OrderBy(x => x.Item2))
|
||||
parentNode.AppendChild(x.Item1); // moves the node to the last position
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts a single child node of a parentNode.
|
||||
/// </summary>
|
||||
/// <param name="parentNode">The parent node.</param>
|
||||
/// <param name="childNodesXPath">An XPath expression to select children of <paramref name="parentNode"/> to sort.</param>
|
||||
/// <param name="node">The child node to sort.</param>
|
||||
/// <param name="orderBy">A function returning the value to order the nodes by.</param>
|
||||
/// <returns>A value indicating whether sorting was needed.</returns>
|
||||
/// <remarks>Assuming all nodes but <paramref name="node"/> are sorted, this will move the node to
|
||||
/// the right position without moving all the nodes (as SortNodes would do) - should improve perfs.</remarks>
|
||||
internal static bool SortNode(
|
||||
XmlNode parentNode,
|
||||
string childNodesXPath,
|
||||
XmlNode node,
|
||||
Func<XmlNode, int> orderBy)
|
||||
{
|
||||
var nodeSortOrder = orderBy(node);
|
||||
var childNodesAndOrder = parentNode.SelectNodes(childNodesXPath).Cast<XmlNode>()
|
||||
.Select(x => Tuple.Create(x, orderBy(x))).ToArray();
|
||||
|
||||
var xElement = parentNode.ToXElement();
|
||||
var children = xElement.Elements().Where(x => childSelector(x)).ToArray(); //(DONT conver to method group, the build server doesn't like it)
|
||||
|
||||
var data = children
|
||||
.OrderByDescending(orderByValue) //order by the sort order desc
|
||||
.Select(x => children.IndexOf(x)) //store the current item's index (DONT conver to method group, the build server doesn't like it)
|
||||
.ToList();
|
||||
// find the first node with a sortOrder > node.sortOrder
|
||||
var i = 0;
|
||||
while (i < childNodesAndOrder.Length && childNodesAndOrder[i].Item2 <= nodeSortOrder)
|
||||
i++;
|
||||
|
||||
//get the minimum index that a content node exists in the parent
|
||||
var minElementIndex = xElement.Elements()
|
||||
.TakeWhile(x => childSelector(x) == false)
|
||||
.Count();
|
||||
|
||||
//if the minimum index is zero, then it is the very first node inside the parent,
|
||||
// if it is not, we need to store the child property node that exists just before the
|
||||
// first content node found so we can insert elements after it when we're sorting.
|
||||
var insertAfter = minElementIndex == 0 ? null : parentNode.ChildNodes[minElementIndex - 1];
|
||||
|
||||
var selectedChildren = parentNode.SelectNodes(childXPathSelector);
|
||||
if (selectedChildren == null)
|
||||
// if one was found
|
||||
if (i < childNodesAndOrder.Length)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("The childXPathSelector value did not return any results {0}", childXPathSelector));
|
||||
}
|
||||
|
||||
var childElements = selectedChildren.Cast<XmlElement>().ToArray();
|
||||
|
||||
//iterate over the ndoes starting with the node with the highest sort order.
|
||||
//then we insert this node at the begginning of the parent so that by the end
|
||||
//of the iteration the node with the least sort order will be at the top.
|
||||
foreach (var node in data.Select(index => childElements[index]))
|
||||
{
|
||||
if (insertAfter == null)
|
||||
// and node is just before, we're done already
|
||||
// else we need to move it right before the node that was found
|
||||
if (i > 0 && childNodesAndOrder[i - 1].Item1 != node)
|
||||
{
|
||||
parentNode.PrependChild(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
parentNode.InsertAfter(node, insertAfter);
|
||||
parentNode.InsertBefore(node, childNodesAndOrder[i].Item1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// and node is the last one, we're done already
|
||||
// else we need to append it as the last one
|
||||
if (i > 0 && childNodesAndOrder[i - 1].Item1 != node)
|
||||
{
|
||||
parentNode.AppendChild(node);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// used by DynamicNode only, see note in TryCreateXPathDocumentFromPropertyValue
|
||||
|
||||
@@ -86,8 +86,7 @@ namespace Umbraco.Tests
|
||||
XmlHelper.SortNodes(
|
||||
parentNode,
|
||||
"./* [@id]",
|
||||
element => element.Attribute("id") != null,
|
||||
element => element.AttributeValue<int>("sortOrder"));
|
||||
x => x.AttributeValue<int>("sortOrder"));
|
||||
watch.Stop();
|
||||
totalTime += watch.ElapsedMilliseconds;
|
||||
watch.Reset();
|
||||
@@ -125,8 +124,7 @@ namespace Umbraco.Tests
|
||||
XmlHelper.SortNodes(
|
||||
parentNode,
|
||||
"./* [@id]",
|
||||
element => element.Attribute("id") != null,
|
||||
element => element.AttributeValue<int>("sortOrder"));
|
||||
x => x.AttributeValue<int>("sortOrder"));
|
||||
|
||||
//do assertions just to make sure it is working properly.
|
||||
var currSort = 0;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Web.Script.Serialization;
|
||||
using umbraco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Models;
|
||||
using System.Linq;
|
||||
@@ -81,6 +82,7 @@ namespace Umbraco.Web.Cache
|
||||
public override void Refresh(int id)
|
||||
{
|
||||
RuntimeCacheProvider.Current.Delete(typeof(IContent), id);
|
||||
content.Instance.UpdateSortOrder(id);
|
||||
base.Refresh(id);
|
||||
}
|
||||
|
||||
@@ -94,6 +96,7 @@ namespace Umbraco.Web.Cache
|
||||
public override void Refresh(IContent instance)
|
||||
{
|
||||
RuntimeCacheProvider.Current.Delete(typeof(IContent), instance.Id);
|
||||
content.Instance.UpdateSortOrder(instance);
|
||||
base.Refresh(instance);
|
||||
}
|
||||
|
||||
@@ -112,6 +115,7 @@ namespace Umbraco.Web.Cache
|
||||
foreach (var payload in DeserializeFromJsonPayload(jsonPayload))
|
||||
{
|
||||
RuntimeCacheProvider.Current.Delete(typeof(IContent), payload.Id);
|
||||
content.Instance.UpdateSortOrder(payload.Id);
|
||||
}
|
||||
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(jsonPayload, MessageType.RefreshByJson));
|
||||
|
||||
@@ -2,12 +2,14 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using System.Xml.XPath;
|
||||
using umbraco.cms.presentation;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
@@ -19,12 +21,14 @@ using umbraco.BusinessLogic.Utils;
|
||||
using umbraco.cms.businesslogic;
|
||||
using umbraco.cms.businesslogic.cache;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
using Umbraco.Core.Models;
|
||||
using umbraco.DataLayer;
|
||||
using umbraco.presentation.nodeFactory;
|
||||
using Umbraco.Web;
|
||||
using Action = umbraco.BusinessLogic.Actions.Action;
|
||||
using Node = umbraco.NodeFactory.Node;
|
||||
using Umbraco.Core;
|
||||
using File = System.IO.File;
|
||||
|
||||
namespace umbraco
|
||||
{
|
||||
@@ -322,7 +326,7 @@ namespace umbraco
|
||||
}
|
||||
}
|
||||
|
||||
public static void TransferValuesFromDocumentXmlToPublishedXml(XmlNode DocumentNode, XmlNode PublishedNode)
|
||||
private static void TransferValuesFromDocumentXmlToPublishedXml(XmlNode DocumentNode, XmlNode PublishedNode)
|
||||
{
|
||||
// Remove all attributes and data nodes from the published node
|
||||
PublishedNode.Attributes.RemoveAll();
|
||||
@@ -353,8 +357,12 @@ namespace umbraco
|
||||
if (d.Published)
|
||||
{
|
||||
var parentId = d.Level == 1 ? -1 : d.Parent.Id;
|
||||
xmlContentCopy = AppendDocumentXml(d.Id, d.Level, parentId,
|
||||
GetPreviewOrPublishedNode(d, xmlContentCopy, false), xmlContentCopy);
|
||||
|
||||
// fix sortOrder - see note in UpdateSortOrder
|
||||
var node = GetPreviewOrPublishedNode(d, xmlContentCopy, false);
|
||||
var attr = ((XmlElement)node).GetAttributeNode("sortOrder");
|
||||
attr.Value = d.sortOrder.ToString();
|
||||
xmlContentCopy = AppendDocumentXml(d.Id, d.Level, parentId, node, xmlContentCopy);
|
||||
|
||||
// update sitemapprovider
|
||||
if (updateSitemapProvider && SiteMap.Provider is UmbracoSiteMapProvider)
|
||||
@@ -382,79 +390,113 @@ namespace umbraco
|
||||
return xmlContentCopy;
|
||||
}
|
||||
|
||||
public static XmlDocument AppendDocumentXml(int id, int level, int parentId, XmlNode docNode, XmlDocument xmlContentCopy)
|
||||
// appends a node (docNode) into a cache (xmlContentCopy)
|
||||
// and returns a cache (not necessarily the original one)
|
||||
//
|
||||
internal static XmlDocument AppendDocumentXml(int id, int level, int parentId, XmlNode docNode, XmlDocument xmlContentCopy)
|
||||
{
|
||||
// Find the document in the xml cache
|
||||
// sanity checks
|
||||
if (id != docNode.AttributeValue<int>("id"))
|
||||
throw new ArgumentException("Values of id and docNode/@id are different.");
|
||||
if (parentId != docNode.AttributeValue<int>("parentID"))
|
||||
throw new ArgumentException("Values of parentId and docNode/@parentID are different.");
|
||||
|
||||
// find the document in the cache
|
||||
XmlNode currentNode = xmlContentCopy.GetElementById(id.ToString());
|
||||
|
||||
// if the document is not there already then it's a new document
|
||||
// we must make sure that its document type exists in the schema
|
||||
var xmlContentCopy2 = xmlContentCopy;
|
||||
if (currentNode == null && UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema == false)
|
||||
{
|
||||
xmlContentCopy = ValidateSchema(docNode.Name, xmlContentCopy);
|
||||
// ValidateSchema looks for the doctype in the schema and if not found
|
||||
// creates a new XML document with a schema containing the doctype. If
|
||||
// a new cache copy is returned, must import the new node into the new
|
||||
// copy.
|
||||
var xmlContentCopy2 = xmlContentCopy;
|
||||
xmlContentCopy = ValidateSchema(docNode.Name, xmlContentCopy);
|
||||
if (xmlContentCopy != xmlContentCopy2)
|
||||
docNode = xmlContentCopy.ImportNode(docNode, true);
|
||||
}
|
||||
|
||||
// Find the parent (used for sortering and maybe creation of new node)
|
||||
// find the parent
|
||||
XmlNode parentNode = level == 1
|
||||
? xmlContentCopy.DocumentElement
|
||||
: xmlContentCopy.GetElementById(parentId.ToString());
|
||||
? xmlContentCopy.DocumentElement
|
||||
: xmlContentCopy.GetElementById(parentId.ToString());
|
||||
|
||||
if (parentNode != null)
|
||||
// no parent = cannot do anything
|
||||
if (parentNode == null)
|
||||
return xmlContentCopy;
|
||||
|
||||
// define xpath for getting the children nodes (not properties) of a node
|
||||
var childNodesXPath = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema
|
||||
? "./node"
|
||||
: "./* [@id]";
|
||||
|
||||
// insert/move the node under the parent
|
||||
if (currentNode == null)
|
||||
{
|
||||
if (currentNode == null)
|
||||
// document not there, new node, append
|
||||
currentNode = docNode;
|
||||
parentNode.AppendChild(currentNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// document found... we could just copy the currentNode children nodes over under
|
||||
// docNode, then remove currentNode and insert docNode... the code below tries to
|
||||
// be clever and faster, though only benchmarking could tell whether it's worth the
|
||||
// pain...
|
||||
|
||||
// first copy current parent ID - so we can compare with target parent
|
||||
var moving = currentNode.AttributeValue<int>("parentID") != parentId;
|
||||
|
||||
if (docNode.Name == currentNode.Name)
|
||||
{
|
||||
currentNode = docNode;
|
||||
parentNode.AppendChild(currentNode);
|
||||
// name has not changed, safe to just update the current node
|
||||
// by transfering values eg copying the attributes, and importing the data elements
|
||||
TransferValuesFromDocumentXmlToPublishedXml(docNode, currentNode);
|
||||
|
||||
// if moving, move the node to the new parent
|
||||
// else it's already under the right parent
|
||||
// (but maybe the sort order has been updated)
|
||||
if (moving)
|
||||
parentNode.AppendChild(currentNode); // remove then append to parentNode
|
||||
}
|
||||
else
|
||||
{
|
||||
//check the current parent id
|
||||
var currParentId = currentNode.AttributeValue<int>("parentID");
|
||||
// name has changed, must use docNode (with new name)
|
||||
// move children nodes from currentNode to docNode (already has properties)
|
||||
foreach (XmlNode child in currentNode.SelectNodes(childNodesXPath))
|
||||
docNode.AppendChild(child); // remove then append to docNode
|
||||
|
||||
//update the node with it's new values
|
||||
TransferValuesFromDocumentXmlToPublishedXml(docNode, currentNode);
|
||||
|
||||
//If the node is being moved we also need to ensure that it exists under the new parent!
|
||||
// http://issues.umbraco.org/issue/U4-2312
|
||||
// we were never checking this before and instead simply changing the parentId value but not
|
||||
// changing the actual parent.
|
||||
|
||||
//check the new parent
|
||||
if (currParentId != currentNode.AttributeValue<int>("parentID"))
|
||||
// and put docNode in the right place - if parent has not changed, then
|
||||
// just replace, else remove currentNode and insert docNode under the right parent
|
||||
// (but maybe not at the right position due to sort order)
|
||||
if (moving)
|
||||
{
|
||||
//ok, we've actually got to move the node
|
||||
parentNode.AppendChild(currentNode);
|
||||
currentNode.ParentNode.RemoveChild(currentNode);
|
||||
parentNode.AppendChild(docNode);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TODO: Update with new schema!
|
||||
var xpath = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema
|
||||
? "./node"
|
||||
: "./* [@id]";
|
||||
|
||||
var childNodes = parentNode.SelectNodes(xpath);
|
||||
|
||||
// Sort the nodes if the added node has a lower sortorder than the last
|
||||
if (childNodes != null && childNodes.Count > 0)
|
||||
{
|
||||
//get the biggest sort order for all children including the one added
|
||||
var largestSortOrder = childNodes.Cast<XmlNode>().Max(x => x.AttributeValue<int>("sortOrder"));
|
||||
var currentSortOrder = currentNode.AttributeValue<int>("sortOrder");
|
||||
//if the current item's sort order is less than the largest sort order in the list then
|
||||
//we need to resort the xml structure since this item belongs somewhere in the middle.
|
||||
//http://issues.umbraco.org/issue/U4-509
|
||||
if (childNodes.Count > 1 && currentSortOrder < largestSortOrder)
|
||||
else
|
||||
{
|
||||
SortNodes(ref parentNode);
|
||||
// replacing might screw the sort order
|
||||
parentNode.ReplaceChild(docNode, currentNode);
|
||||
}
|
||||
|
||||
currentNode = docNode;
|
||||
}
|
||||
}
|
||||
|
||||
return xmlContentCopy;
|
||||
// if the nodes are not ordered, must sort
|
||||
// (see U4-509 + has to work with ReplaceChild too)
|
||||
//XmlHelper.SortNodesIfNeeded(parentNode, childNodesXPath, x => x.AttributeValue<int>("sortOrder"));
|
||||
|
||||
// but...
|
||||
// if we assume that nodes are always correctly sorted
|
||||
// then we just need to ensure that currentNode is at the right position.
|
||||
// should be faster that moving all the nodes around.
|
||||
XmlHelper.SortNode(parentNode, childNodesXPath, currentNode, x => x.AttributeValue<int>("sortOrder"));
|
||||
|
||||
return xmlContentCopy;
|
||||
}
|
||||
|
||||
private static XmlNode GetPreviewOrPublishedNode(Document d, XmlDocument xmlContentCopy, bool isPreview)
|
||||
@@ -472,18 +514,36 @@ namespace umbraco
|
||||
/// <summary>
|
||||
/// Sorts the documents.
|
||||
/// </summary>
|
||||
/// <param name="parentNode">The parent node.</param>
|
||||
public static void SortNodes(ref XmlNode parentNode)
|
||||
/// <param name="parentId">The parent node identifier.</param>
|
||||
public void SortNodes(int parentId)
|
||||
{
|
||||
var xpath = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema
|
||||
? "./node"
|
||||
: "./* [@id]";
|
||||
var childNodesXPath = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema
|
||||
? "./node"
|
||||
: "./* [@id]";
|
||||
|
||||
XmlHelper.SortNodes(
|
||||
parentNode,
|
||||
xpath,
|
||||
element => element.Attribute("id") != null,
|
||||
element => element.AttributeValue<int>("sortOrder"));
|
||||
lock (XmlContentInternalSyncLock)
|
||||
{
|
||||
// modify a clone of the cache because even though we're into the write-lock
|
||||
// we may have threads reading at the same time. why is this an option?
|
||||
var wip = UmbracoConfig.For.UmbracoSettings().Content.CloneXmlContent
|
||||
? CloneXmlDoc(XmlContentInternal)
|
||||
: XmlContentInternal;
|
||||
|
||||
var parentNode = parentId == -1
|
||||
? XmlContent.DocumentElement
|
||||
: XmlContent.GetElementById(parentId.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
if (parentNode == null) return;
|
||||
|
||||
var sorted = XmlHelper.SortNodesIfNeeded(
|
||||
parentNode,
|
||||
childNodesXPath,
|
||||
x => x.AttributeValue<int>("sortOrder"));
|
||||
|
||||
if (sorted == false) return;
|
||||
|
||||
XmlContentInternal = wip;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -531,6 +591,50 @@ namespace umbraco
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual void UpdateSortOrder(int contentId)
|
||||
{
|
||||
var content = ApplicationContext.Current.Services.ContentService.GetById(contentId);
|
||||
if (content != null) return;
|
||||
UpdateSortOrder(content);
|
||||
}
|
||||
|
||||
internal virtual void UpdateSortOrder(IContent c)
|
||||
{
|
||||
// the XML in database is updated only when content is published, and then
|
||||
// it contains the sortOrder value at the time the XML was generated. when
|
||||
// a document with unpublished changes is sorted, then it is simply saved
|
||||
// (see ContentService) and so the sortOrder has changed but the XML has
|
||||
// not been updated accordingly.
|
||||
|
||||
// this updates the published cache to take care of the situation
|
||||
// without ContentService having to ... what exactly?
|
||||
|
||||
// no need to do it if the content is published without unpublished changes,
|
||||
// though, because in that case the XML will get re-generated with the
|
||||
// correct sort order.
|
||||
if (c.Published)
|
||||
return;
|
||||
|
||||
lock (XmlContentInternalSyncLock)
|
||||
{
|
||||
var wip = UmbracoConfig.For.UmbracoSettings().Content.CloneXmlContent
|
||||
? CloneXmlDoc(XmlContentInternal)
|
||||
: XmlContentInternal;
|
||||
|
||||
var node = wip.GetElementById(c.Id.ToString());
|
||||
if (node == null) return;
|
||||
var attr = node.GetAttributeNode("sortOrder");
|
||||
var sortOrder = c.SortOrder.ToString();
|
||||
if (attr.Value == sortOrder) return;
|
||||
|
||||
// only if node was actually modified
|
||||
attr.Value = sortOrder;
|
||||
XmlContentInternal = wip;
|
||||
|
||||
// no need to clear any cache
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the document cache for multiple documents
|
||||
/// </summary>
|
||||
@@ -1010,6 +1114,13 @@ order by umbracoNode.level, umbracoNode.sortOrder";
|
||||
int parentId = dr.GetInt("parentId");
|
||||
string xml = dr.GetString("xml");
|
||||
|
||||
// fix sortOrder - see notes in UpdateSortOrder
|
||||
var tmp = new XmlDocument();
|
||||
tmp.LoadXml(xml);
|
||||
var attr = tmp.DocumentElement.GetAttributeNode("sortOrder");
|
||||
attr.Value = dr.GetInt("sortOrder").ToString();
|
||||
xml = tmp.InnerXml;
|
||||
|
||||
// Call the eventhandler to allow modification of the string
|
||||
var e1 = new ContentCacheLoadNodeEventArgs();
|
||||
FireAfterContentCacheDatabaseLoadXmlString(ref xml, e1);
|
||||
|
||||
@@ -155,14 +155,9 @@ namespace umbraco.presentation.webservices
|
||||
// Save content with new sort order and update db+cache accordingly
|
||||
var sorted = contentService.Sort(sortedContent);
|
||||
|
||||
// Refresh sort order on cached xml
|
||||
XmlNode parentNode = parentId == -1
|
||||
? content.Instance.XmlContent.DocumentElement
|
||||
: content.Instance.XmlContent.GetElementById(parentId.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
//only try to do the content sort if the the parent node is available...
|
||||
if (parentNode != null)
|
||||
content.SortNodes(ref parentNode);
|
||||
// refresh sort order on cached xml
|
||||
// but no... this is not distributed - solely relying on content service & events should be enough
|
||||
//content.Instance.SortNodes(parentId);
|
||||
|
||||
//send notifications! TODO: This should be put somewhere centralized instead of hard coded directly here
|
||||
ApplicationContext.Services.NotificationService.SendNotification(contentService.GetById(parentId), ActionSort.Instance, UmbracoContext, ApplicationContext);
|
||||
|
||||
Reference in New Issue
Block a user