562 lines
14 KiB
C#
562 lines
14 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.Linq;
|
|
using System.Web;
|
|
using System.Xml;
|
|
using System.Xml.Serialization;
|
|
using System.Xml.XPath;
|
|
using umbraco.cms.businesslogic;
|
|
using umbraco.cms.businesslogic.propertytype;
|
|
using umbraco.interfaces;
|
|
using Umbraco.Core;
|
|
using Umbraco.Web;
|
|
|
|
namespace umbraco.NodeFactory
|
|
{
|
|
/// <summary>
|
|
/// Summary description for Node.
|
|
/// </summary>
|
|
|
|
[Serializable]
|
|
[XmlType(Namespace = "http://umbraco.org/webservices/")]
|
|
public class Node : INode
|
|
{
|
|
private Hashtable _aliasToNames = new Hashtable();
|
|
|
|
private bool _initialized = false;
|
|
private Nodes _children = new Nodes();
|
|
private Node _parent = null;
|
|
private int _id;
|
|
private int _template;
|
|
private string _name;
|
|
private string _nodeTypeAlias;
|
|
private string _writerName;
|
|
private string _creatorName;
|
|
private int _writerID;
|
|
private int _creatorID;
|
|
private string _urlName;
|
|
private string _path;
|
|
private DateTime _createDate;
|
|
private DateTime _updateDate;
|
|
private Guid _version;
|
|
private Properties _properties = new Properties();
|
|
private XmlNode _pageXmlNode;
|
|
private int _sortOrder;
|
|
private int _level;
|
|
|
|
public Nodes Children
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _children;
|
|
}
|
|
}
|
|
|
|
public INode Parent
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _parent;
|
|
}
|
|
}
|
|
|
|
public int Id
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _id;
|
|
}
|
|
}
|
|
|
|
public int template
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _template;
|
|
}
|
|
}
|
|
|
|
public int SortOrder
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _sortOrder;
|
|
}
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _name;
|
|
}
|
|
}
|
|
|
|
public string Url
|
|
{
|
|
get { return library.NiceUrl(Id); }
|
|
}
|
|
|
|
public string NodeTypeAlias
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _nodeTypeAlias;
|
|
}
|
|
}
|
|
|
|
public string WriterName
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _writerName;
|
|
}
|
|
}
|
|
|
|
public string CreatorName
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _creatorName;
|
|
}
|
|
}
|
|
|
|
public int WriterID
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _writerID;
|
|
}
|
|
}
|
|
|
|
public int CreatorID
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _creatorID;
|
|
}
|
|
}
|
|
|
|
|
|
public string Path
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _path;
|
|
}
|
|
}
|
|
|
|
public DateTime CreateDate
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _createDate;
|
|
}
|
|
}
|
|
|
|
public DateTime UpdateDate
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _updateDate;
|
|
}
|
|
}
|
|
|
|
public Guid Version
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _version;
|
|
}
|
|
}
|
|
|
|
public string UrlName
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _urlName;
|
|
}
|
|
}
|
|
|
|
public string NiceUrl
|
|
{
|
|
get
|
|
{
|
|
return library.NiceUrl(Id);
|
|
}
|
|
}
|
|
|
|
public int Level
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _level;
|
|
}
|
|
}
|
|
|
|
public List<IProperty> PropertiesAsList
|
|
{
|
|
get { return Properties.Cast<IProperty>().ToList(); }
|
|
}
|
|
|
|
public Properties Properties
|
|
{
|
|
get
|
|
{
|
|
if (!_initialized)
|
|
initialize();
|
|
return _properties;
|
|
}
|
|
}
|
|
|
|
public Node()
|
|
{
|
|
_pageXmlNode = ((IHasXmlNode)library.GetXmlNodeCurrent().Current).GetNode();
|
|
initializeStructure();
|
|
initialize();
|
|
}
|
|
|
|
public Node(XmlNode NodeXmlNode)
|
|
{
|
|
_pageXmlNode = NodeXmlNode;
|
|
initializeStructure();
|
|
initialize();
|
|
}
|
|
|
|
public Node(XmlNode NodeXmlNode, bool DisableInitializing)
|
|
{
|
|
_pageXmlNode = NodeXmlNode;
|
|
initializeStructure();
|
|
if (!DisableInitializing)
|
|
initialize();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Special constructor for by-passing published vs. preview xml to use
|
|
/// when updating the SiteMapProvider
|
|
/// </summary>
|
|
/// <param name="NodeId"></param>
|
|
/// <param name="forcePublishedXml"></param>
|
|
public Node(int NodeId, bool forcePublishedXml)
|
|
{
|
|
if (forcePublishedXml)
|
|
{
|
|
if (NodeId != -1)
|
|
_pageXmlNode = content.Instance.XmlContent.GetElementById(NodeId.ToString());
|
|
else
|
|
{
|
|
_pageXmlNode = content.Instance.XmlContent.DocumentElement;
|
|
|
|
}
|
|
initializeStructure();
|
|
initialize();
|
|
}
|
|
else
|
|
{
|
|
throw new ArgumentException("Use Node(int NodeId) if not forcing published xml");
|
|
|
|
}
|
|
}
|
|
|
|
public Node(int NodeId)
|
|
{
|
|
if (NodeId != -1)
|
|
_pageXmlNode = ((IHasXmlNode)library.GetXmlNodeById(NodeId.ToString()).Current).GetNode();
|
|
else
|
|
{
|
|
if (UmbracoContext.Current != null)
|
|
{
|
|
var cache = UmbracoContext.Current.ContentCache.InnerCache as Umbraco.Web.PublishedCache.XmlPublishedCache.PublishedContentCache;
|
|
_pageXmlNode = cache.GetXml(UmbracoContext.Current, false).DocumentElement;
|
|
}
|
|
else if (presentation.UmbracoContext.Current != null)
|
|
{
|
|
_pageXmlNode = umbraco.presentation.UmbracoContext.Current.GetXml().DocumentElement;
|
|
}
|
|
else
|
|
{
|
|
_pageXmlNode = content.Instance.XmlContent.DocumentElement;
|
|
}
|
|
|
|
|
|
}
|
|
initializeStructure();
|
|
initialize();
|
|
}
|
|
|
|
public IProperty GetProperty(string Alias)
|
|
{
|
|
foreach (Property p in Properties)
|
|
{
|
|
if (p.Alias == Alias)
|
|
return p;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public IProperty GetProperty(string Alias, out bool propertyExists)
|
|
{
|
|
foreach (Property p in Properties)
|
|
{
|
|
if (p.Alias == Alias)
|
|
{
|
|
propertyExists = true;
|
|
return p;
|
|
}
|
|
}
|
|
propertyExists = false;
|
|
return null;
|
|
}
|
|
|
|
public static Node GetNodeByXpath(string xpath)
|
|
{
|
|
XPathNodeIterator itNode = library.GetXmlNodeByXPath(xpath);
|
|
XmlNode nodeXmlNode = null;
|
|
if (itNode.MoveNext())
|
|
{
|
|
nodeXmlNode = ((IHasXmlNode)itNode.Current).GetNode();
|
|
}
|
|
if (nodeXmlNode != null)
|
|
{
|
|
return new Node(nodeXmlNode);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public List<INode> ChildrenAsList
|
|
{
|
|
get { return Children.Cast<INode>().ToList(); }
|
|
}
|
|
|
|
public DataTable ChildrenAsTable()
|
|
{
|
|
return GenerateDataTable(this);
|
|
}
|
|
|
|
public DataTable ChildrenAsTable(string nodeTypeAliasFilter)
|
|
{
|
|
return GenerateDataTable(this, nodeTypeAliasFilter);
|
|
}
|
|
|
|
private DataTable GenerateDataTable(INode node, string nodeTypeAliasFilter = "")
|
|
{
|
|
var firstNode = nodeTypeAliasFilter.IsNullOrWhiteSpace()
|
|
? node.ChildrenAsList.Any()
|
|
? node.ChildrenAsList[0]
|
|
: null
|
|
: node.ChildrenAsList.FirstOrDefault(x => x.NodeTypeAlias == nodeTypeAliasFilter);
|
|
if (firstNode == null)
|
|
return new DataTable(); //no children found
|
|
|
|
//use new utility class to create table so that we don't have to maintain code in many places, just one
|
|
var dt = Umbraco.Core.DataTableExtensions.GenerateDataTable(
|
|
//pass in the alias of the first child node since this is the node type we're rendering headers for
|
|
firstNode.NodeTypeAlias,
|
|
//pass in the callback to extract the Dictionary<string, string> of column aliases to names
|
|
alias =>
|
|
{
|
|
var userFields = ContentType.GetAliasesAndNames(alias);
|
|
//ensure the standard fields are there
|
|
var allFields = new Dictionary<string, string>()
|
|
{
|
|
{"Id", "Id"},
|
|
{"NodeName", "NodeName"},
|
|
{"NodeTypeAlias", "NodeTypeAlias"},
|
|
{"CreateDate", "CreateDate"},
|
|
{"UpdateDate", "UpdateDate"},
|
|
{"CreatorName", "CreatorName"},
|
|
{"WriterName", "WriterName"},
|
|
{"Url", "Url"}
|
|
};
|
|
foreach (var f in userFields.Where(f => !allFields.ContainsKey(f.Key)))
|
|
{
|
|
allFields.Add(f.Key, f.Value);
|
|
}
|
|
return allFields;
|
|
},
|
|
//pass in a callback to populate the datatable, yup its a bit ugly but it's already legacy and we just want to maintain code in one place.
|
|
() =>
|
|
{
|
|
//create all row data
|
|
var tableData = Umbraco.Core.DataTableExtensions.CreateTableData();
|
|
//loop through each child and create row data for it
|
|
foreach (Node n in Children)
|
|
{
|
|
if (!nodeTypeAliasFilter.IsNullOrWhiteSpace())
|
|
{
|
|
if (n.NodeTypeAlias != nodeTypeAliasFilter)
|
|
continue; //skip this one, it doesn't match the filter
|
|
}
|
|
|
|
var standardVals = new Dictionary<string, object>()
|
|
{
|
|
{"Id", n.Id},
|
|
{"NodeName", n.Name},
|
|
{"NodeTypeAlias", n.NodeTypeAlias},
|
|
{"CreateDate", n.CreateDate},
|
|
{"UpdateDate", n.UpdateDate},
|
|
{"CreatorName", n.CreatorName},
|
|
{"WriterName", n.WriterName},
|
|
{"Url", library.NiceUrl(n.Id)}
|
|
};
|
|
var userVals = new Dictionary<string, object>();
|
|
foreach (var p in from Property p in n.Properties where p.Value != null select p)
|
|
{
|
|
userVals[p.Alias] = p.Value;
|
|
}
|
|
//add the row data
|
|
Umbraco.Core.DataTableExtensions.AddRowData(tableData, standardVals, userVals);
|
|
}
|
|
return tableData;
|
|
}
|
|
);
|
|
return dt;
|
|
}
|
|
|
|
private void initializeStructure()
|
|
{
|
|
// Load parent if it exists and is a node
|
|
|
|
if (_pageXmlNode != null && _pageXmlNode.SelectSingleNode("..") != null)
|
|
{
|
|
XmlNode parent = _pageXmlNode.SelectSingleNode("..");
|
|
if (parent != null && (parent.Name == "node" || (parent.Attributes != null && parent.Attributes.GetNamedItem("isDoc") != null)))
|
|
_parent = new Node(parent, true);
|
|
}
|
|
}
|
|
|
|
private void initialize()
|
|
{
|
|
if (_pageXmlNode != null)
|
|
{
|
|
_initialized = true;
|
|
if (_pageXmlNode.Attributes != null)
|
|
{
|
|
_id = int.Parse(_pageXmlNode.Attributes.GetNamedItem("id").Value);
|
|
if (_pageXmlNode.Attributes.GetNamedItem("template") != null)
|
|
_template = int.Parse(_pageXmlNode.Attributes.GetNamedItem("template").Value);
|
|
if (_pageXmlNode.Attributes.GetNamedItem("sortOrder") != null)
|
|
_sortOrder = int.Parse(_pageXmlNode.Attributes.GetNamedItem("sortOrder").Value);
|
|
if (_pageXmlNode.Attributes.GetNamedItem("nodeName") != null)
|
|
_name = _pageXmlNode.Attributes.GetNamedItem("nodeName").Value;
|
|
if (_pageXmlNode.Attributes.GetNamedItem("writerName") != null)
|
|
_writerName = _pageXmlNode.Attributes.GetNamedItem("writerName").Value;
|
|
if (_pageXmlNode.Attributes.GetNamedItem("urlName") != null)
|
|
_urlName = _pageXmlNode.Attributes.GetNamedItem("urlName").Value;
|
|
// Creatorname is new in 2.1, so published xml might not have it!
|
|
try
|
|
{
|
|
_creatorName = _pageXmlNode.Attributes.GetNamedItem("creatorName").Value;
|
|
}
|
|
catch
|
|
{
|
|
_creatorName = _writerName;
|
|
}
|
|
|
|
//Added the actual userID, as a user cannot be looked up via full name only...
|
|
if (_pageXmlNode.Attributes.GetNamedItem("creatorID") != null)
|
|
_creatorID = int.Parse(_pageXmlNode.Attributes.GetNamedItem("creatorID").Value);
|
|
if (_pageXmlNode.Attributes.GetNamedItem("writerID") != null)
|
|
_writerID = int.Parse(_pageXmlNode.Attributes.GetNamedItem("writerID").Value);
|
|
|
|
if (UmbracoSettings.UseLegacyXmlSchema)
|
|
{
|
|
if (_pageXmlNode.Attributes.GetNamedItem("nodeTypeAlias") != null)
|
|
_nodeTypeAlias = _pageXmlNode.Attributes.GetNamedItem("nodeTypeAlias").Value;
|
|
}
|
|
else
|
|
{
|
|
_nodeTypeAlias = _pageXmlNode.Name;
|
|
}
|
|
|
|
if (_pageXmlNode.Attributes.GetNamedItem("path") != null)
|
|
_path = _pageXmlNode.Attributes.GetNamedItem("path").Value;
|
|
if (_pageXmlNode.Attributes.GetNamedItem("version") != null)
|
|
_version = new Guid(_pageXmlNode.Attributes.GetNamedItem("version").Value);
|
|
if (_pageXmlNode.Attributes.GetNamedItem("createDate") != null)
|
|
_createDate = DateTime.Parse(_pageXmlNode.Attributes.GetNamedItem("createDate").Value);
|
|
if (_pageXmlNode.Attributes.GetNamedItem("updateDate") != null)
|
|
_updateDate = DateTime.Parse(_pageXmlNode.Attributes.GetNamedItem("updateDate").Value);
|
|
if (_pageXmlNode.Attributes.GetNamedItem("level") != null)
|
|
_level = int.Parse(_pageXmlNode.Attributes.GetNamedItem("level").Value);
|
|
|
|
}
|
|
|
|
// load data
|
|
string dataXPath = UmbracoSettings.UseLegacyXmlSchema ? "data" : "* [not(@isDoc)]";
|
|
foreach (XmlNode n in _pageXmlNode.SelectNodes(dataXPath))
|
|
_properties.Add(new Property(n));
|
|
|
|
// load children
|
|
string childXPath = UmbracoSettings.UseLegacyXmlSchema ? "node" : "* [@isDoc]";
|
|
XPathNavigator nav = _pageXmlNode.CreateNavigator();
|
|
XPathExpression expr = nav.Compile(childXPath);
|
|
expr.AddSort("@sortOrder", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Number);
|
|
XPathNodeIterator iterator = nav.Select(expr);
|
|
while (iterator.MoveNext())
|
|
{
|
|
_children.Add(
|
|
new Node(((IHasXmlNode)iterator.Current).GetNode(), true)
|
|
);
|
|
}
|
|
}
|
|
// else
|
|
// throw new ArgumentNullException("Node xml source is null");
|
|
}
|
|
|
|
public static Node GetCurrent()
|
|
{
|
|
int id = getCurrentNodeId();
|
|
return new Node(id);
|
|
}
|
|
|
|
public static int getCurrentNodeId()
|
|
{
|
|
if (HttpContext.Current.Items["pageID"] == null)
|
|
throw new InvalidOperationException("There is no current node.");
|
|
|
|
var intAttempt = HttpContext.Current.Items["pageID"].TryConvertTo<int>();
|
|
if (intAttempt == false)
|
|
{
|
|
throw new InvalidOperationException("The pageID value in the HttpContext.Items cannot be converted to an integer");
|
|
}
|
|
return intAttempt.Result;
|
|
}
|
|
}
|
|
} |