e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
633 lines
19 KiB
C#
633 lines
19 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="SiteMapNode.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* SiteMapNode class definition
|
|
*
|
|
* Copyright (c) 2002 Microsoft Corporation
|
|
*/
|
|
|
|
namespace System.Web {
|
|
|
|
using System;
|
|
using System.Configuration.Provider;
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.ComponentModel;
|
|
using System.Resources;
|
|
using System.Security.Permissions;
|
|
using System.Web.Configuration;
|
|
using System.Web.Compilation;
|
|
using System.Web.UI;
|
|
using System.Web.UI.WebControls;
|
|
using System.Web.Util;
|
|
|
|
/// <devdoc>
|
|
/// <para></para>
|
|
/// </devdoc>
|
|
public class SiteMapNode : ICloneable, IHierarchyData, INavigateUIData {
|
|
|
|
private static readonly string _siteMapNodeType = typeof(SiteMapNode).Name;
|
|
|
|
private SiteMapProvider _provider;
|
|
|
|
private bool _readonly;
|
|
private bool _parentNodeSet;
|
|
private bool _childNodesSet;
|
|
|
|
private VirtualPath _virtualPath;
|
|
private string _title;
|
|
private string _description;
|
|
private string _url;
|
|
private string _key;
|
|
private string _resourceKey;
|
|
|
|
private IList _roles;
|
|
private NameValueCollection _attributes;
|
|
private NameValueCollection _resourceKeys;
|
|
|
|
private SiteMapNode _parentNode;
|
|
private SiteMapNodeCollection _childNodes;
|
|
|
|
public SiteMapNode(SiteMapProvider provider, string key) :
|
|
this(provider, key, null, null, null, null, null, null, null) {
|
|
}
|
|
|
|
public SiteMapNode(SiteMapProvider provider, string key, string url) :
|
|
this(provider, key, url, null, null, null, null, null, null) {
|
|
}
|
|
|
|
public SiteMapNode(SiteMapProvider provider, string key, string url, string title) :
|
|
this(provider, key, url, title, null, null, null, null, null) {
|
|
}
|
|
|
|
public SiteMapNode(SiteMapProvider provider, string key, string url, string title, string description) :
|
|
this(provider, key, url, title, description, null, null, null, null) {
|
|
}
|
|
|
|
public SiteMapNode(SiteMapProvider provider, string key, string url, string title, string description,
|
|
IList roles, NameValueCollection attributes, NameValueCollection explicitResourceKeys, string implicitResourceKey) {
|
|
|
|
_provider = provider;
|
|
_title = title;
|
|
_description = description;
|
|
_roles = roles;
|
|
_attributes = attributes;
|
|
_key = key;
|
|
_resourceKeys = explicitResourceKeys;
|
|
_resourceKey = implicitResourceKey;
|
|
|
|
if (url != null) {
|
|
_url = url.Trim();
|
|
}
|
|
|
|
_virtualPath = CreateVirtualPathFromUrl(_url);
|
|
|
|
if (_key == null) {
|
|
throw new ArgumentNullException("key");
|
|
}
|
|
|
|
if (_provider == null) {
|
|
throw new ArgumentNullException("provider");
|
|
}
|
|
}
|
|
|
|
protected NameValueCollection Attributes {
|
|
get {
|
|
return _attributes;
|
|
}
|
|
set {
|
|
if (_readonly) {
|
|
throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "Attributes"));
|
|
}
|
|
|
|
_attributes = value;
|
|
}
|
|
}
|
|
|
|
// Access custom attributes.
|
|
public virtual string this[string key] {
|
|
get {
|
|
string text = null;
|
|
if (_attributes != null) {
|
|
text = _attributes[key];
|
|
}
|
|
|
|
if (_provider.EnableLocalization) {
|
|
// Try the implicit resource first
|
|
string localizedText = GetImplicitResourceString(key);
|
|
if (localizedText != null) {
|
|
return localizedText;
|
|
}
|
|
|
|
// If not found, try the explicit resource.
|
|
localizedText = GetExplicitResourceString(key, text, true);
|
|
if (localizedText != null) {
|
|
return localizedText;
|
|
}
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
set {
|
|
if (_readonly) {
|
|
throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "Item"));
|
|
}
|
|
|
|
if (_attributes == null) {
|
|
_attributes = new NameValueCollection();
|
|
}
|
|
|
|
_attributes[key] = value;
|
|
}
|
|
}
|
|
|
|
public virtual SiteMapNodeCollection ChildNodes {
|
|
get {
|
|
if (_childNodesSet)
|
|
return _childNodes;
|
|
|
|
return _provider.GetChildNodes(this);
|
|
}
|
|
set {
|
|
if (_readonly) {
|
|
throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "ChildNodes"));
|
|
}
|
|
|
|
_childNodes = value;
|
|
_childNodesSet = true;
|
|
}
|
|
}
|
|
|
|
[
|
|
Localizable(true)
|
|
]
|
|
public virtual string Description {
|
|
get {
|
|
if (_provider.EnableLocalization) {
|
|
string localizedText = GetImplicitResourceString("description");
|
|
if (localizedText != null) {
|
|
return localizedText;
|
|
}
|
|
|
|
localizedText = GetExplicitResourceString("description", _description, true);
|
|
if (localizedText != null) {
|
|
return localizedText;
|
|
}
|
|
}
|
|
|
|
return _description == null? String.Empty : _description;
|
|
}
|
|
set {
|
|
if (_readonly) {
|
|
throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "Description"));
|
|
}
|
|
|
|
_description = value;
|
|
}
|
|
}
|
|
|
|
public string Key {
|
|
get {
|
|
return _key;
|
|
}
|
|
}
|
|
|
|
public virtual bool HasChildNodes {
|
|
get {
|
|
IList children = ChildNodes;
|
|
return children != null && children.Count > 0;
|
|
}
|
|
}
|
|
|
|
public virtual SiteMapNode NextSibling {
|
|
get {
|
|
IList siblings = SiblingNodes;
|
|
if (siblings == null) {
|
|
return null;
|
|
}
|
|
|
|
int index = siblings.IndexOf(this);
|
|
if (index >= 0 && index < siblings.Count - 1) {
|
|
return (SiteMapNode)siblings[index + 1];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// Get parent node. If not found in current provider, search recursively in parent providers.
|
|
public virtual SiteMapNode ParentNode {
|
|
get {
|
|
if (_parentNodeSet)
|
|
return _parentNode;
|
|
|
|
return _provider.GetParentNode(this);
|
|
}
|
|
set {
|
|
if (_readonly) {
|
|
throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "ParentNode"));
|
|
}
|
|
|
|
_parentNode = value;
|
|
_parentNodeSet = true;
|
|
}
|
|
}
|
|
|
|
public virtual SiteMapNode PreviousSibling {
|
|
get {
|
|
IList siblings = SiblingNodes;
|
|
if (siblings == null) {
|
|
return null;
|
|
}
|
|
|
|
int index = siblings.IndexOf(this);
|
|
if (index > 0 && index <= siblings.Count - 1) {
|
|
return (SiteMapNode)siblings[index - 1];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public SiteMapProvider Provider {
|
|
get {
|
|
return _provider;
|
|
}
|
|
}
|
|
|
|
public bool ReadOnly {
|
|
get {
|
|
return _readonly;
|
|
}
|
|
set {
|
|
_readonly = value;
|
|
}
|
|
}
|
|
|
|
public String ResourceKey {
|
|
get {
|
|
return _resourceKey;
|
|
}
|
|
set {
|
|
if (_readonly) {
|
|
throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "ResourceKey"));
|
|
}
|
|
|
|
_resourceKey = value;
|
|
}
|
|
}
|
|
|
|
public IList Roles {
|
|
get {
|
|
return _roles;
|
|
}
|
|
set {
|
|
if (_readonly) {
|
|
throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "Roles"));
|
|
}
|
|
|
|
_roles = value;
|
|
}
|
|
}
|
|
|
|
public virtual SiteMapNode RootNode {
|
|
get {
|
|
SiteMapNode root = _provider.RootProvider.RootNode;
|
|
if (root == null) {
|
|
String name = ((ProviderBase)_provider.RootProvider).Name;
|
|
throw new InvalidOperationException(SR.GetString(SR.SiteMapProvider_Invalid_RootNode, name));
|
|
}
|
|
|
|
return root;
|
|
}
|
|
}
|
|
|
|
private SiteMapNodeCollection SiblingNodes {
|
|
get {
|
|
SiteMapNode parent = ParentNode;
|
|
return parent == null? null : parent.ChildNodes;
|
|
}
|
|
}
|
|
|
|
[
|
|
Localizable(true)
|
|
]
|
|
public virtual string Title {
|
|
get {
|
|
if (_provider.EnableLocalization) {
|
|
string localizedText = GetImplicitResourceString("title");
|
|
if (localizedText != null) {
|
|
return localizedText;
|
|
}
|
|
|
|
localizedText = GetExplicitResourceString("title", _title, true);
|
|
if (localizedText != null) {
|
|
return localizedText;
|
|
}
|
|
}
|
|
|
|
return _title == null? String.Empty : _title;
|
|
}
|
|
set {
|
|
if (_readonly) {
|
|
throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "Title"));
|
|
}
|
|
|
|
_title = value;
|
|
}
|
|
}
|
|
|
|
public virtual string Url {
|
|
get {
|
|
return _url == null? String.Empty : _url;
|
|
}
|
|
set {
|
|
if (_readonly) {
|
|
throw new InvalidOperationException(SR.GetString(SR.SiteMapNode_readonly, "Url"));
|
|
}
|
|
|
|
if (value != null) {
|
|
_url = value.Trim();
|
|
}
|
|
|
|
_virtualPath = CreateVirtualPathFromUrl(_url);
|
|
}
|
|
}
|
|
|
|
internal VirtualPath VirtualPath {
|
|
get {
|
|
return _virtualPath;
|
|
}
|
|
}
|
|
|
|
private VirtualPath CreateVirtualPathFromUrl(string url) {
|
|
if (String.IsNullOrEmpty(url)) {
|
|
return null;
|
|
}
|
|
|
|
if (!UrlPath.IsValidVirtualPathWithoutProtocol(url)) {
|
|
return null;
|
|
}
|
|
|
|
if (UrlPath.IsAbsolutePhysicalPath(url)) {
|
|
return null;
|
|
}
|
|
|
|
// Do not generate the virtualPath class at designtime.
|
|
if (HttpRuntime.AppDomainAppVirtualPath == null) {
|
|
return null;
|
|
}
|
|
|
|
if (UrlPath.IsRelativeUrl(url) && !UrlPath.IsAppRelativePath(url)) {
|
|
url = UrlPath.Combine(HttpRuntime.AppDomainAppVirtualPathString, url);
|
|
}
|
|
|
|
// Remove the query string from url so the path can be validated by Authorization module.
|
|
int queryStringIndex = url.IndexOf('?');
|
|
if (queryStringIndex != -1) {
|
|
url = url.Substring(0, queryStringIndex);
|
|
}
|
|
|
|
return VirtualPath.Create(url,
|
|
VirtualPathOptions.AllowAbsolutePath | VirtualPathOptions.AllowAppRelativePath);
|
|
}
|
|
|
|
public virtual SiteMapNode Clone() {
|
|
ArrayList newRoles = null;
|
|
NameValueCollection newAttributes = null;
|
|
NameValueCollection newResourceKeys = null;
|
|
|
|
if (_roles != null) {
|
|
newRoles = new ArrayList(_roles);
|
|
}
|
|
if (_attributes != null) {
|
|
newAttributes = new NameValueCollection(_attributes);
|
|
}
|
|
if (_resourceKeys != null) {
|
|
newResourceKeys = new NameValueCollection(_resourceKeys);
|
|
}
|
|
|
|
SiteMapNode newNode = new SiteMapNode(_provider, Key, Url, Title, Description, newRoles, newAttributes, newResourceKeys, _resourceKey);
|
|
return newNode;
|
|
}
|
|
|
|
public virtual SiteMapNode Clone(bool cloneParentNodes) {
|
|
SiteMapNode current = Clone();
|
|
|
|
if (cloneParentNodes) {
|
|
SiteMapNode node = current;
|
|
SiteMapNode parent = ParentNode;
|
|
while (parent != null) {
|
|
SiteMapNode cloneParent = parent.Clone();
|
|
node.ParentNode = cloneParent;
|
|
cloneParent.ChildNodes = new SiteMapNodeCollection(node);
|
|
|
|
parent = parent.ParentNode;
|
|
node = cloneParent;
|
|
}
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
public override bool Equals(object obj) {
|
|
SiteMapNode node = obj as SiteMapNode;
|
|
return node != null && (_key == node.Key) &&
|
|
(String.Equals(_url, node._url, StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
public SiteMapNodeCollection GetAllNodes() {
|
|
SiteMapNodeCollection collection = new SiteMapNodeCollection();
|
|
GetAllNodesRecursive(collection);
|
|
return SiteMapNodeCollection.ReadOnly(collection);
|
|
}
|
|
|
|
private void GetAllNodesRecursive(SiteMapNodeCollection collection) {
|
|
SiteMapNodeCollection childNodes = this.ChildNodes;
|
|
|
|
if (childNodes != null && childNodes.Count > 0) {
|
|
collection.AddRange(childNodes);
|
|
foreach(SiteMapNode node in childNodes)
|
|
node.GetAllNodesRecursive(collection);
|
|
}
|
|
}
|
|
|
|
public SiteMapDataSourceView GetDataSourceView(SiteMapDataSource owner, string viewName) {
|
|
return new SiteMapDataSourceView(owner, viewName, this);
|
|
}
|
|
|
|
|
|
public SiteMapHierarchicalDataSourceView GetHierarchicalDataSourceView() {
|
|
return new SiteMapHierarchicalDataSourceView(this);
|
|
}
|
|
|
|
// Helpe method to retrieve localized string based on attribute name
|
|
protected string GetExplicitResourceString(string attributeName, string defaultValue, bool throwIfNotFound) {
|
|
if (attributeName == null) {
|
|
throw new ArgumentNullException("attributeName");
|
|
}
|
|
|
|
string text = null;
|
|
if (_resourceKeys != null) {
|
|
string[] keys = _resourceKeys.GetValues(attributeName);
|
|
if (keys != null && keys.Length > 1) {
|
|
try {
|
|
text = ResourceExpressionBuilder.GetGlobalResourceObject(keys[0], keys[1]) as string;
|
|
}
|
|
catch (MissingManifestResourceException) {
|
|
if (defaultValue != null) {
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
if (text == null && throwIfNotFound) {
|
|
// throw if default value is not specified.
|
|
throw new InvalidOperationException(
|
|
SR.GetString(SR.Res_not_found_with_class_and_key, keys[0], keys[1])); ;
|
|
}
|
|
}
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
// Only use the key to get the hashcode since url can be changed and makes the objects mutable.
|
|
public override int GetHashCode() {
|
|
return _key.GetHashCode();
|
|
}
|
|
|
|
// Helper method to retrieve localized string based on attribute name
|
|
protected string GetImplicitResourceString(string attributeName) {
|
|
if (attributeName == null) {
|
|
throw new ArgumentNullException("attributeName");
|
|
}
|
|
|
|
string text = null;
|
|
if (!String.IsNullOrEmpty(_resourceKey)) {
|
|
try {
|
|
text = ResourceExpressionBuilder.GetGlobalResourceObject(Provider.ResourceKey, ResourceKey + "." + attributeName) as String;
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
return text;
|
|
}
|
|
|
|
public virtual bool IsAccessibleToUser(HttpContext context) {
|
|
return _provider.IsAccessibleToUser(context, this);
|
|
}
|
|
|
|
public virtual bool IsDescendantOf(SiteMapNode node) {
|
|
SiteMapNode parent = ParentNode;
|
|
while (parent != null) {
|
|
if (parent.Equals(node)) {
|
|
return true;
|
|
}
|
|
|
|
parent = parent.ParentNode;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public override string ToString() {
|
|
return Title;
|
|
}
|
|
|
|
#region ICloneable implementation
|
|
|
|
/// <internalonly/>
|
|
object ICloneable.Clone() {
|
|
return Clone();
|
|
}
|
|
#endregion
|
|
|
|
#region IHierarchyData implementation
|
|
|
|
/// <internalonly/>
|
|
bool IHierarchyData.HasChildren {
|
|
get {
|
|
return HasChildNodes;
|
|
}
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
object IHierarchyData.Item {
|
|
get {
|
|
return this;
|
|
}
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
string IHierarchyData.Path {
|
|
get {
|
|
return Key;
|
|
}
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
string IHierarchyData.Type {
|
|
get {
|
|
return _siteMapNodeType;
|
|
}
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
IHierarchicalEnumerable IHierarchyData.GetChildren() {
|
|
return ChildNodes;
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
IHierarchyData IHierarchyData.GetParent() {
|
|
SiteMapNode parentNode = ParentNode;
|
|
if (parentNode == null)
|
|
return null;
|
|
|
|
return parentNode;
|
|
}
|
|
#endregion
|
|
|
|
#region INavigateUIData implementations
|
|
string INavigateUIData.Description {
|
|
get {
|
|
return Description;
|
|
}
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
string INavigateUIData.Name {
|
|
get {
|
|
return Title;
|
|
}
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
string INavigateUIData.NavigateUrl {
|
|
get {
|
|
return Url;
|
|
}
|
|
}
|
|
|
|
|
|
/// <internalonly/>
|
|
string INavigateUIData.Value {
|
|
get {
|
|
return Title;
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|