/// <summary>
        /// Navigates backward.
        /// </summary>
        public void NavigateBackward()
        {
            // Check if navigation is unlocked
            if (_navigationUnlocked && _navigationUndo.Count > 0)
            {
                // Pop node
                ContentTreeNode node = _navigationUndo.Pop();

                // Lock navigation
                _navigationUnlocked = false;

                // Add to Redo list
                _navigationRedo.Push(SelectedNode);

                // Select node
                RefreshView(node);
                _tree.Select(node);
                node.ExpandAllParents();

                // Set valid sizes for stacks
                //RedoList.SetSize(32);
                //UndoList.SetSize(32);

                // Update search
                UpdateItemsSearch();

                // Unlock navigation
                _navigationUnlocked = true;

                // Update UI
                UpdateUI();
                _view.SelectFirstItem();
            }
        }
Пример #2
0
        // ReSharper disable ParameterTypeCanBeEnumerable.Local
        private void WriteChildList(ContentTreeNode currentNode, HtmlTextWriter xml, int level)
        {
            var childNodes = database.Where(f => f.Parent == currentNode).ToList();

            if (childNodes.Count <= 0)
            {
                return;
            }

            xml.AddAttribute("class", currentNode == null ? menuPart.MenuOuterUlCssClass : menuPart.MenuInnerUlCssClass);
            xml.RenderBeginTag(HtmlTextWriterTag.Ul);
            foreach (var childNode in childNodes.OrderBy(n => n.SortOrder).ThenBy(n => n.Item.ID))
            {
                // Write the <li> if showing the root node, or not at the root node level
                var showCurrentChildNode = menuPart.MenuShowTreeRoot || level != 0;
                if (showCurrentChildNode)
                {
                    WriteListItem(childNode, xml, level, null);
                }
                else
                {
                    // If not showing the current node, then start with the child list.
                    WriteChildList(childNode, xml, level + 1);
                }

                // Show the non-nested <ul> only if we have just added a <li>
                if (showCurrentChildNode && !menuPart.MenuNestChildUls)
                {
                    WriteChildList(childNode, xml, level + 1);
                }
            }
            xml.RenderEndTag();
        }
Пример #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="NavigationButton"/> class.
 /// </summary>
 /// <param name="targetNode">The target node.</param>
 /// <param name="x">The x position.</param>
 /// <param name="y">The y position.</param>
 /// <param name="height">The height.</param>
 public NavigationButton(ContentTreeNode targetNode, float x, float y, float height)
     : base(x, y, 2 * DefaultMargin)
 {
     TargetNode = targetNode;
     Height     = height;
     Text       = targetNode.NavButtonLabel + "/";
 }
Пример #4
0
        private void LoadAssets(ContentTreeNode parent, string[] files)
        {
            for (int i = 0; i < files.Length; i++)
            {
                var path = StringUtils.NormalizePath(files[i]);

                // Check if node already has that element (skip during init when we want to walk project dir very fast)
                if (_isDuringFastSetup || !parent.Folder.ContainsChild(path))
                {
                    // Create file item
                    ContentItem item = null;
                    if (FlaxEngine.Content.GetAssetInfo(path, out var assetInfo))
                    {
                        var proxy = GetAssetProxy(assetInfo.TypeName, path);
                        item = proxy?.ConstructItem(path, assetInfo.TypeName, ref assetInfo.ID);
                    }
                    if (item == null)
                    {
                        item = new FileItem(path);
                    }

                    // Link
                    item.ParentFolder = parent.Folder;

                    // Fire event
                    if (_enableEvents)
                    {
                        ItemAdded?.Invoke(item);
                        WorkspaceModified?.Invoke();
                    }
                    _itemsCreated++;
                }
            }
        }
Пример #5
0
        // ReSharper disable ParameterTypeCanBeEnumerable.Local
        private void WriteChildList(ContentTreeNode currentNode, HtmlTextWriter xml, int level)
        {
            var childNodes = database.Where(f => f.Parent == currentNode).ToList();

            if (childNodes.Count <= 0)
            {
                return;
            }
#if ENABLE_DEBUG_COMMENTS
            xml.Write("<!-- WriteChildList(currentNode = {0}, level = {1} -->\n", currentNode.ItemId, level);
#endif
            xml.AddAttribute("class", currentNode == null ? menuPart.MenuOuterUlCssClass : menuPart.MenuInnerUlCssClass);
            xml.RenderBeginTag(HtmlTextWriterTag.Ul);

            if (currentNode == null && (!menuPart.MenuShowTreeRoot && childNodes.Count > 0))             // indicates that we are starting the menu,
            {
                // Skip directly to the children of the root node.
                childNodes = database.Where(f => f.Parent == childNodes.First()).ToList();
            }

            foreach (var childNode in childNodes.OrderBy(n => n.SortOrder).ThenBy(n => n.Item.ID))
            {
                WriteListItem(childNode, xml, level, null);

                if (!menuPart.MenuNestChildUls)
                {
                    WriteChildList(childNode, xml, level + 1);
                }
            }
            xml.RenderEndTag();
        }
Пример #6
0
 public ContentTreeNode(ContentItem item, ContentTreeNode parent)
 {
     Item      = item;
     Parent    = parent;
     SortOrder = item.SortOrder;
     ItemId    = item.ID;
 }
Пример #7
0
        // ReSharper restore ParameterTypeCanBeEnumerable.Local

        /// <summary>
        /// Writes the top two levels of a tree flattened into a single list, with header styles on the level-1 list
        /// items, and with sub-items in their respective hierarchies.
        /// </summary>
        /// <param name="currentNode"></param>
        /// <param name="xml"></param>
        private void WriteListWithHeaders(ContentTreeNode currentNode, HtmlTextWriter xml)
        {
            var childNodes = database.Where(f => f.Parent == currentNode).ToList();

            if (childNodes.Count <= 0)
            {
                return;
            }

            xml.AddAttribute("class", currentNode == null ? menuPart.MenuOuterUlCssClass : menuPart.MenuInnerUlCssClass);
            xml.RenderBeginTag(HtmlTextWriterTag.Ul);

            foreach (var childNode in childNodes.OrderBy(n => n.SortOrder).ThenBy(n => n.Item.ID))
            {
                WriteListItem(childNode, xml, 0, "nav-header disabled");                 // flattened header item

                var innerChildNodes = database.Where(f => f.Parent == childNode).ToList();
                foreach (var innerChildNode in innerChildNodes.OrderBy(n => n.SortOrder))
                {
                    WriteListItem(innerChildNode, xml, 1, null);

                    if (!menuPart.MenuNestChildUls)
                    {
                        WriteChildList(innerChildNode, xml, 2);
                    }
                }
            }
            xml.RenderEndTag();
        }
Пример #8
0
        public dynamic GetLocationFromXml(XmlNode arg, Database db)
        {
            var     node     = new ContentTreeNode(_sitecoreDataAccessService.GetLatestItemData(arg.Attributes?["id"]?.InnerText));
            dynamic location = new ExpandoObject();

            location.item        = node;
            location.description = arg.Attributes?["description"]?.InnerText;
            return(location);
        }
Пример #9
0
        public override void Process(HttpRequestArgs args)
        {
            try
            {
                var guidString = args.Context.Request.Form["__PARAMETERS"];
                if (guidString != null)
                {
                    int guidStart = guidString.IndexOf('"') + 1;
                    int guidStop  = guidString.LastIndexOf('"');
                    if (guidStart != -1 && guidStop > guidStart)
                    {
                        guidString = guidString.Substring(guidStart, guidStop - guidStart);
                        HttpCookie myCookie = args.Context.Request.Cookies["scseditorcontext" + Regex.Replace(Context.GetUserName(), "[^a-zA-Z0-9 -]", string.Empty)];

                        if (!_sitecoreDataAccessService.TryGetItemData(guidString, out IItemData item))
                        {
                            return;
                        }

                        if (item != null)
                        {
                            SessionStateSection SessionSettings = (SessionStateSection)ConfigurationManager.GetSection("system.web/sessionState");

                            EditingContextRegistration.Related[HttpContext.Current.Request.Cookies[SessionSettings.CookieName]?.Value ?? ""]   = _sitecoreDataAccessService.GetItemReferences(item).Select(x => new TypeContentTreeNode(x)).OrderBy(x => x.DisplayName).ToList();
                            EditingContextRegistration.Referrers[HttpContext.Current.Request.Cookies[SessionSettings.CookieName]?.Value ?? ""] = _sitecoreDataAccessService.GetItemReferrers(item).Select(x => new TypeContentTreeNode(x)).OrderBy(x => x.DisplayName).ToList();
                        }
                        ContentTreeNode current = new ContentTreeNode(item, false);
                        if (string.IsNullOrWhiteSpace(current.DisplayName))
                        {
                            return;
                        }
                        if (myCookie?.Value != null)
                        {
                            var list = GetValue(myCookie, current.Id);
                            list.Add($"{current.Id}|{current.DatabaseName}");
                            if (list.Count > 10)
                            {
                                list.RemoveAt(0);
                            }
                            SetValue(myCookie, string.Join(",", list));
                            args.Context.Response.Cookies.Add(myCookie);
                        }
                        else
                        {
                            myCookie = new HttpCookie("scseditorcontext" + Regex.Replace(Context.GetUserName(), "[^a-zA-Z0-9 -]", string.Empty));
                            SetValue(myCookie, $"{current.Id}|{current.DatabaseName}");
                            myCookie.Expires = DateTime.Now.AddDays(1d);
                            args.Context.Response.Cookies.Add(myCookie);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Log.Warn("unable to register action for SCS Editing Context", e, this);
            }
        }
        public dynamic GetLocationFromXml(XmlNode arg, Database db)
        {
            var     node     = new ContentTreeNode(db.DataManager.DataEngine.GetItem(new ID(arg.Attributes?["id"]?.InnerText), LanguageManager.DefaultLanguage, Sitecore.Data.Version.Latest));
            dynamic location = new ExpandoObject();

            location.item        = node;
            location.description = arg.Attributes?["description"]?.InnerText;
            return(location);
        }
        private void Init()
        {
            using (new SecurityDisabler())
            {
                IItemData idata = GetResources.GetRemoteItemData(_args, _args.id);

                Item      parent  = db.GetItem(new ID(idata.ParentId));
                IItemData tmpData = idata;
                root = db.GetItem(new ID(idata.Id));
                if (_args.mirror && root != null)
                {
                    Stack <Item> items = new Stack <Item>();
                    items.Push(root);
                    while (items.Any())
                    {
                        var curItem = items.Pop();
                        allowedItems.Add(curItem.ID.Guid);
                        foreach (Item child in curItem.Children)
                        {
                            items.Push(child);
                        }
                    }
                }

                if (_args.pullParent && parent == null)
                {
                    Stack <IItemData> path = new Stack <IItemData>();
                    var tmp = _args.children;
                    _args.children = false;
                    while (parent == null)
                    {
                        parent = db.GetItem(new ID(tmpData.ParentId));
                        path.Push(tmpData);
                        _args.id = tmpData.ParentId.ToString();
                        tmpData  = GetResources.GetRemoteItemData(_args, tmpData.ParentId.ToString());
                    }
                    while (path.Any())
                    {
                        var cur = path.Pop();

                        InstallItem(cur);
                    }
                    _args.children = tmp;
                }

                RootNode = new ContentTreeNode(parent.Database.GetItem(new ID(idata.Id)));
                if (RootNode.Icon == "")
                {
                    RootNode = new ContentTreeNode(parent.Database.GetItem(new ID(idata.TemplateId)))
                    {
                        Id          = new ID(idata.Id).ToString(),
                        DisplayName = idata.Name
                    };
                }
                RootNode.Server = _args.server;
            }
        }
        /// <summary>
        /// Navigates directory up.
        /// </summary>
        public void NavigateUp()
        {
            ContentTreeNode target  = _root;
            ContentTreeNode current = SelectedNode;

            if (current?.Folder.ParentFolder != null)
            {
                target = current.Folder.ParentFolder.Node;
            }

            Navigate(target);
        }
Пример #13
0
        private void LoadScripts(ContentTreeNode parent, string[] files)
        {
            for (int i = 0; i < files.Length; i++)
            {
                var path = StringUtils.NormalizePath(files[i]);

                // Check if node already has that element (skip during init when we want to walk project dir very fast)
                if (_isDuringFastSetup || !parent.Folder.ContainsChild(path))
                {
                    // Create file item
                    ContentItem item;
                    if (path.EndsWith(".cs"))
                    {
                        item = new CSharpScriptItem(path);
                    }
                    else if (path.EndsWith(".cpp") || path.EndsWith(".h"))
                    {
                        item = new CppScriptItem(path);
                    }
                    else if (path.EndsWith(".shader") || path.EndsWith(".hlsl"))
                    {
                        item = new ShaderSourceItem(path);
                    }
                    else
                    {
                        item = new FileItem(path);
                    }

                    // Link
                    item.ParentFolder = parent.Folder;

                    // Fire event
                    if (_enableEvents)
                    {
                        ItemAdded?.Invoke(item);
                        WorkspaceModified?.Invoke();
                        if (!path.EndsWith(".Gen.cs"))
                        {
                            if (item is ScriptItem)
                            {
                                ScriptsBuilder.MarkWorkspaceDirty();
                            }
                            if (item is ScriptItem || item is ShaderSourceItem)
                            {
                                Editor.CodeEditing.SelectedEditor.OnFileAdded(path);
                            }
                        }
                    }
                    _itemsCreated++;
                }
            }
        }
Пример #14
0
        private void WriteListItem(ContentTreeNode childNode, HtmlTextWriter xml, int level, string cssClass)
        {
            // write LI...
            var sn         = menuPart;
            var childItem  = childNode.Item;
            var isSelected = childItem.ID == cId;

            if (cssClass == null)
            {
                cssClass = childNode.IsAncestor
                                        ? sn.MenuAncestorLiCssClass
                                        : isSelected ? sn.MenuSelectedLiCssClass : sn.MenuLiCssClass;
            }

            xml.AddAttribute("class", cssClass);
            xml.RenderBeginTag(HtmlTextWriterTag.Li);

            if (isSelected || (level == 0 && sn.MenuDontLinkTopLevel))
            {
                xml.RenderBeginTag(HtmlTextWriterTag.A);                 // wrap in a dummy <a> for Bootstrap 3, http://stackoverflow.com/questions/18329010/what-happened-to-nav-header-class
                xml.Write(childItem.Title);
                xml.RenderEndTag();
            }
            else
            {
                xml.AddAttribute("href", childItem.Url);
                xml.RenderBeginTag(HtmlTextWriterTag.A);
                xml.Write(childItem.Title);

                // render caret if subitems exist
                if (sn.MenuShowCaretOnItemsWithChildren &&
                    database.Any(f => f.Parent == childNode))
                {
                    // <b class="caret"></b>
                    xml.Write(' ');
                    xml.AddAttribute("class", "caret");
                    xml.RenderBeginTag(HtmlTextWriterTag.B);
                    xml.RenderEndTag();
                }
                xml.RenderEndTag();
            }

            if (menuPart.MenuNestChildUls)
            {
                WriteChildList(childNode, xml, level + 1);
            }

            xml.RenderEndTag();             // </li>
            xml.WriteLine();
        }
Пример #15
0
        private void LoadAssets(ContentTreeNode parent, string directory)
        {
            // Find files
            var files = Directory.GetFiles(directory, "*.*", SearchOption.TopDirectoryOnly);

            // Add them
            for (int i = 0; i < files.Length; i++)
            {
                var path = StringUtils.NormalizePath(files[i]);

                // Check if node already has that element (skip during init when we want to walk project dir very fast)
                if (_isDuringFastSetup || !parent.Folder.ContainsChild(path))
                {
                    // It can be any type of asset: binary, text, cooked, package, etc.
                    // The best idea is to just ask Flax.
                    // Flax isn't John Snow. Flax knows something :)
                    // Also Flax Content Layer is using smart caching so this query gonna be fast.

                    ContentItem item = null;

                    // Try using in-build asset
                    string typeName;
                    Guid   id;
                    if (FlaxEngine.Content.GetAssetInfo(path, out typeName, out id))
                    {
                        var proxy = GetAssetProxy(typeName, path);
                        item = proxy?.ConstructItem(path, typeName, ref id);
                    }

                    // Generic file
                    if (item == null)
                    {
                        item = new FileItem(path);
                    }

                    // Link
                    item.ParentFolder = parent.Folder;

                    // Fire event
                    if (_enableEvents)
                    {
                        ItemAdded?.Invoke(item);
                        OnWorkspaceModified?.Invoke();
                    }
                    _itemsCreated++;
                }
            }
        }
Пример #16
0
        public override void Process(HttpRequestArgs args)
        {
            var guidString = args.Context.Request.Form["__PARAMETERS"];

            if (guidString != null)
            {
                int guidStart = guidString.IndexOf('"') + 1;
                int guidStop  = guidString.LastIndexOf('"');
                if (guidStart != -1 && guidStop > guidStart)
                {
                    guidString = guidString.Substring(guidStart, guidStop - guidStart);
                    HttpCookie myCookie = args.Context.Request.Cookies["scseditorcontext" + Context.GetUserName()];
                    var        database = Context.ContentDatabase ?? Context.Database ?? Factory.GetDatabase("master");
                    ID         tmp;
                    try
                    {
                        tmp = new ID(guidString);
                    }
                    catch (Exception)
                    {
                        return;
                    }
                    ContentTreeNode current = new ContentTreeNode(database.GetItem(tmp), false);
                    if (string.IsNullOrWhiteSpace(current.DisplayName))
                    {
                        return;
                    }
                    if (myCookie?.Value != null)
                    {
                        var list = myCookie.Value.Split(',').Where(x => !x.StartsWith(current.Id)).ToList();
                        list.Add($"{current.Id}|{current.DatabaseName}|{current.DisplayName}|{current.Icon}");
                        if (list.Count > 20)
                        {
                            list.RemoveAt(0);
                        }
                        myCookie.Value = string.Join(",", list);
                        args.Context.Response.Cookies.Add(myCookie);
                    }
                    else
                    {
                        myCookie         = new HttpCookie("scseditorcontext" + Context.GetUserName());
                        myCookie.Value   = HttpUtility.UrlEncode($"{current.Id}|{current.DatabaseName}|{current.DisplayName}|{current.Icon}");
                        myCookie.Expires = DateTime.Now.AddDays(1d);
                        args.Context.Response.Cookies.Add(myCookie);
                    }
                }
            }
        }
Пример #17
0
        // ReSharper disable ParameterTypeCanBeEnumerable.Local
        private void WriteChildList(ContentTreeNode currentNode, HtmlTextWriter xml, int level)
        {
            var childNodes = database.Where(f => f.Parent == currentNode).ToList();

            if (childNodes.Count <= 0)
            {
                return;
            }

            xml.AddAttribute("class", currentNode == null ? menuPart.MenuOuterUlCssClass : menuPart.MenuInnerUlCssClass);
            xml.RenderBeginTag(HtmlTextWriterTag.Ul);
            foreach (var childNode in childNodes.OrderBy(n => n.SortOrder).OrderBy(n => n.Item.ID))
            {
                WriteListItem(childNode, xml, level, null);
                WriteChildList(childNode, xml, level + 1);
            }
            xml.RenderEndTag();
        }
        private void Navigate(ContentTreeNode source, ContentTreeNode target)
        {
            if (target == null)
            {
                target = _root;
            }

            // Check if can do this action
            if (_navigationUnlocked && source != target)
            {
                // Lock navigation
                _navigationUnlocked = false;

                // Check if already added to the Undo on the top
                if (source != null && (_navigationUndo.Count == 0 || _navigationUndo.Peek() != source))
                {
                    // Add to Undo list
                    _navigationUndo.Push(source);
                }

                // Show folder contents and select tree node
                RefreshView(target);
                _tree.Select(target);
                target.ExpandAllParents();

                // Clear redo list
                _navigationRedo.Clear();

                // Set valid sizes for stacks
                //RedoList.SetSize(32);
                //UndoList.SetSize(32);

                // Update search
                UpdateItemsSearch();

                // Unlock navigation
                _navigationUnlocked = true;

                // Update UI
                UpdateUI();
                _view.SelectFirstItem();
            }
        }
        private void UpdateNavigationBar()
        {
            if (_navigationBar == null)
            {
                return;
            }

            bool wasLayoutLocked = _navigationBar.IsLayoutLocked;

            _navigationBar.IsLayoutLocked = true;

            // Remove previous buttons
            _navigationBar.DisposeChildren();

            // Spawn buttons
            var nodes = NavUpdateCache;

            nodes.Clear();
            ContentTreeNode node = SelectedNode;

            while (node != null)
            {
                nodes.Add(node);
                node = node.ParentNode;
            }
            float x = NavigationBar.DefaultButtonsMargin;
            float h = _toolStrip.ItemsHeight - 2 * ToolStrip.DefaultMarginV;

            for (int i = nodes.Count - 1; i >= 0; i--)
            {
                var button = new ContentNavigationButton(nodes[i], x, ToolStrip.DefaultMarginV, h);
                button.PerformLayout();
                x += button.Width + NavigationBar.DefaultButtonsMargin;
                _navigationBar.AddChild(button);
            }
            nodes.Clear();

            // Update
            _navigationBar.IsLayoutLocked = wasLayoutLocked;
            _navigationBar.PerformLayout();
        }
Пример #20
0
 private void RefreshView(ContentTreeNode target)
 {
     if (target == _root)
     {
         // Special case for root folder
         List <ContentItem> items = new List <ContentItem>(8);
         for (int i = 0; i < _root.ChildrenCount; i++)
         {
             if (_root.GetChild(i) is ContentTreeNode node)
             {
                 items.Add(node.Folder);
             }
         }
         _view.ShowItems(items);
     }
     else
     {
         // Show folder contents
         _view.ShowItems(target.Folder.Children);
     }
 }
Пример #21
0
        private void WriteListItem(ContentTreeNode childNode, HtmlTextWriter xml, int level, string cssClass)
        {
            // write LI...
            var sn         = menuPart;
            var childItem  = childNode.Item;
            var isSelected = childItem.ID == cId;

            if (cssClass == null)
            {
                cssClass = isSelected ? sn.MenuSelectedLiCssClass : sn.MenuLiCssClass;
            }
            xml.AddAttribute("class", cssClass);
            xml.RenderBeginTag(HtmlTextWriterTag.Li);

            if (isSelected || (level == 0 && sn.MenuDontLinkTopLevel))
            {
                xml.Write(childItem.Title);
            }
            else
            {
                xml.AddAttribute("href", childItem.Url);
                xml.RenderBeginTag(HtmlTextWriterTag.A);
                xml.Write(childItem.Title);

                // render caret if subitems exist
                if (sn.MenuShowCaretOnItemsWithChildren &&
                    database.Any(f => f.Parent == childNode))
                {
                    // <b class="caret"></b>
                    xml.Write(' ');
                    xml.AddAttribute("class", "caret");
                    xml.RenderBeginTag(HtmlTextWriterTag.B);
                    xml.RenderEndTag();
                }
                xml.RenderEndTag();
            }

            xml.RenderEndTag();             // </li>
            xml.WriteLine();
        }
Пример #22
0
 /// <summary>
 /// Refreshes the view.
 /// </summary>
 /// <param name="target">The target location.</param>
 public void RefreshView(ContentTreeNode target)
 {
     _view.IsSearching = false;
     if (target == _root)
     {
         // Special case for root folder
         List <ContentItem> items = new List <ContentItem>(8);
         for (int i = 0; i < _root.ChildrenCount; i++)
         {
             if (_root.GetChild(i) is ContentTreeNode node)
             {
                 items.Add(node.Folder);
             }
         }
         _view.ShowItems(items, _sortType, false, true);
     }
     else
     {
         // Show folder contents
         _view.ShowItems(target.Folder.Children, _sortType, false, true);
     }
 }
Пример #23
0
        private void LoadScripts(ContentTreeNode parent, string directory)
        {
            // Find files
            var files = Directory.GetFiles(directory, ScriptProxy.ExtensionFiler, SearchOption.TopDirectoryOnly);

            // Add them
            bool anyAdded = false;

            for (int i = 0; i < files.Length; i++)
            {
                var path = StringUtils.NormalizePath(files[i]);

                // Check if node already has that element (skip during init when we want to walk project dir very fast)
                if (_isDuringFastSetup || !parent.Folder.ContainsChild(path))
                {
                    // Create item object
                    var item = new ScriptItem(path);

                    // Link
                    item.ParentFolder = parent.Folder;

                    // Fire event
                    if (_enableEvents)
                    {
                        ItemAdded?.Invoke(item);
                        OnWorkspaceModified?.Invoke();
                    }
                    _itemsCreated++;
                    anyAdded = true;
                }
            }

            if (anyAdded && _enableEvents)
            {
                ScriptsBuilder.MarkWorkspaceDirty();
            }
        }
Пример #24
0
		private void WriteListItem(ContentTreeNode childNode, HtmlTextWriter xml, int level, string cssClass)
		{
#if ENABLE_DEBUG_COMMENTS
			// debug output
			xml.Write("<!-- WriteListItem(childNode.itemId = {0}, parent.itemId = {2}, level = {1} -->", 
				childNode != null ? childNode.ItemId : -1, 
				level, 
				(childNode != null && childNode.Parent != null) ? childNode.Parent.ItemId : -1);
#endif

			// write LI...
			var sn = menuPart;
			var childItem = childNode.Item;
			var isSelected = childItem.ID == currentPageId;

			if (cssClass == null)
				cssClass = childNode.IsAncestor
					? sn.MenuAncestorLiCssClass
					: isSelected ? sn.MenuSelectedLiCssClass : sn.MenuLiCssClass;

			xml.AddAttribute("class", cssClass);
			xml.RenderBeginTag(HtmlTextWriterTag.Li);

			if (isSelected || (level == 0 && sn.MenuDontLinkTopLevel))
			{
				xml.RenderBeginTag(HtmlTextWriterTag.A); // wrap in a dummy <a> for Bootstrap 3, http://stackoverflow.com/questions/18329010/what-happened-to-nav-header-class
				xml.Write(childItem.Title);
				xml.RenderEndTag();
			}
			else
			{
				xml.AddAttribute("href", childItem.Url);
				xml.RenderBeginTag(HtmlTextWriterTag.A);
				xml.Write(childItem.Title);

				// render caret if subitems exist
				if (sn.MenuShowCaretOnItemsWithChildren
					&& QueryApplicableChildren(childItem).Any() /* has any applicable children */)
				{
					if (!String.IsNullOrWhiteSpace(sn.MenuCaretCustomHtml))
						xml.Write(sn.MenuCaretCustomHtml);
					else
					{
						// <b class="caret"></b> 
						xml.Write(' ');
						xml.AddAttribute("class", "caret");
						xml.RenderBeginTag(HtmlTextWriterTag.B);
						xml.RenderEndTag();
					}
				}
				xml.RenderEndTag();
			}

			if (menuPart.MenuNestChildUls)
			{
				WriteChildList(childNode, xml, level + 1);
			}

			xml.RenderEndTag(); // </li>
			xml.WriteLine();
		}
Пример #25
0
        private RouteData GetRouteData(ContentTreeNode treeNode)
        {
            var routeData = new RouteData(this, RouteHandler);
            var segments = treeNode.GetPath();

            for (var i = 0; i < segments.Length; i++)
                routeData.Values.Add(i.ToString(), segments[i]);

            routeData.Values.Add("TreeNodeId", treeNode.TreeNodeId);
            routeData.Values.Add("ActionId", treeNode.ActionId);
            routeData.Values.Add("action", treeNode.Action);
            routeData.Values.Add("controller", treeNode.Controller);

            return routeData;
        }
Пример #26
0
        /// <summary>
        /// Builds the internal navigation tree structure.
        /// </summary>
        /// <param name="currentPage">The current page.</param>
        /// <returns></returns>
        private List <ContentTreeNode> BuildNavigationTree(ContentItem currentPage)
        {
            var navTree = new List <ContentTreeNode>();

            if (currentPage == null)
            {
                return(navTree);
            }

            if (currentPage.VersionOf != null && currentPage.VersionOf.Value != null)
            {
                currentPage = currentPage.VersionOf.Value;                 // get the published version
            }
            // follow the ancestral trail up to the desired "start from level"
            var convertedAncestralTrail = Array.ConvertAll(currentPage.AncestralTrail.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries), int.Parse);

            var xn = menuPart.MenuStartFromLevel;

            if (xn < 0)
            {
                xn += convertedAncestralTrail.Length;                 // handle "zero" case
            }
            var expandedParents = new List <ContentTreeNode>();

            for (var i = Math.Max(xn, 0); i < convertedAncestralTrail.Length; ++i)
            {
                var ancestorItem = Context.Current.Persister.Get(convertedAncestralTrail[i]);
                var ancestorNode = new ContentTreeNode(ancestorItem, navTree.LastOrDefault())
                {
                    IsAncestor = true
                };
                navTree.Add(ancestorNode);

                // expand the ancestor
                // ReSharper disable LoopCanBeConvertedToQuery
                foreach (var item in QueryApplicableChildren(ancestorItem))
                {
                    expandedParents.Add(new ContentTreeNode(item, ancestorNode));
                }
                // ReSharper restore LoopCanBeConvertedToQuery
            }


            // Add current item ================================================================

            if (currentPage.Visible || menuPart.MenuShowCurrentItemIfHidden)
            {
                // -- add a node for the current page --
                var navItemCurrent = new ContentTreeNode(currentPage, navTree.LastOrDefault());
                var navItemCParent = navTree.LastOrDefault();
                navTree.Add(navItemCurrent);

                // -- get children and siblings --
                // ReSharper disable LoopCanBeConvertedToQuery
                foreach (var child in QueryApplicableChildren(currentPage).OrderBy(f => f.SortOrder))
                {
                    navTree.Add(new ContentTreeNode(child, navItemCurrent));
                }
                // ReSharper restore LoopCanBeConvertedToQuery
            }



            // add the ancestors we just expanded
            // ReSharper disable LoopCanBeConvertedToQuery
            foreach (var item in expandedParents)
            {
                if (navTree.All(f => f.ItemId != item.ItemId))
                {
                    navTree.Add(item);
                }
            }
            // ReSharper restore LoopCanBeConvertedToQuery



            // show siblings of the current item (put under navItemCParent)
            //if (menuPart.ShowSiblings != MenuPartBase.SiblingDisplayOptions.Never)
            //{
            //	if (menuPart.ShowSiblings == MenuPartBase.SiblingDisplayOptions.Always
            //		|| (menuPart.ShowSiblings == MenuPartBase.SiblingDisplayOptions.OnlyIfItemHasNoChildren && chil.Length > 0))
            //	{
            //		// ok...
            //		// ReSharper disable LoopCanBeConvertedToQuery
            //		foreach (var sibling in sibs.OrderBy(f => f.SortOrder))
            //			navTree.Add(new ContentTreeNode(sibling, navItemCParent));
            //		// ReSharper restore LoopCanBeConvertedToQuery
            //	}
            //}

            return(navTree);
        }
Пример #27
0
		private void WriteListItem(ContentTreeNode childNode, HtmlTextWriter xml, int level, string cssClass)
		{
			// write LI...
			var sn = menuPart;
			var childItem = childNode.Item;
			var isSelected = childItem.ID == cId;

			if (cssClass == null)
				cssClass = childNode.IsAncestor
					? sn.MenuAncestorLiCssClass
					: isSelected ? sn.MenuSelectedLiCssClass : sn.MenuLiCssClass;

			xml.AddAttribute("class", cssClass);
			xml.RenderBeginTag(HtmlTextWriterTag.Li);

			if (isSelected || (level == 0 && sn.MenuDontLinkTopLevel))
			{
				xml.RenderBeginTag(HtmlTextWriterTag.A); // wrap in a dummy <a> for Bootstrap 3, http://stackoverflow.com/questions/18329010/what-happened-to-nav-header-class
				xml.Write(childItem.Title);
				xml.RenderEndTag();
			}
			else
			{
				xml.AddAttribute("href", childItem.Url);
				xml.RenderBeginTag(HtmlTextWriterTag.A);
				xml.Write(childItem.Title);

				// render caret if subitems exist
				if (sn.MenuShowCaretOnItemsWithChildren
					&& database.Any(f => f.Parent == childNode))
				{
					// <b class="caret"></b> 
					xml.Write(' ');
					xml.AddAttribute("class", "caret");
					xml.RenderBeginTag(HtmlTextWriterTag.B);
					xml.RenderEndTag();
				}
				xml.RenderEndTag();
			}

			if (menuPart.MenuNestChildUls)
			{
				WriteChildList(childNode, xml, level + 1);
			}

			xml.RenderEndTag(); // </li>
			xml.WriteLine();
		}
Пример #28
0
 private void AddFolder2Root(ContentTreeNode node)
 {
     // Add to the root
     _root.AddChild(node);
 }
        private void Init()
        {
            using (new SecurityDisabler())
            {
                IItemData idata = GetResources.GetRemoteItemData(_args, _args.id);

                Item parent = db.GetItem(new ID(idata.ParentId));
                IItemData tmpData = idata;
                root = db.GetItem(new ID(idata.Id));
                if (_args.mirror && root != null)
                {
                    Stack<Item> items = new Stack<Item>();
                    items.Push(root);
                    while (items.Any())
                    {
                        var curItem = items.Pop();
                        allowedItems.Add(curItem.ID.Guid);
                        foreach (Item child in curItem.Children)
                            items.Push(child);
                    }
                }

                if (_args.pullParent && parent == null)
                {

                    Stack<IItemData> path = new Stack<IItemData>();
                    var tmp = _args.children;
                    _args.children = false;
                    while (parent == null)
                    {
                        parent = db.GetItem(new ID(tmpData.ParentId));
                        path.Push(tmpData);
                        _args.id = tmpData.ParentId.ToString();
                        tmpData = GetResources.GetRemoteItemData(_args, tmpData.ParentId.ToString());
                    }
                    while (path.Any())
                    {
                        var cur = path.Pop();

                        InstallItem(cur);
                    }
                    _args.children = tmp;

                }

                RootNode = new ContentTreeNode(parent.Database.GetItem(new ID(idata.Id)));
                if (RootNode.Icon == "")
                {
                    RootNode = new ContentTreeNode(parent.Database.GetItem(new ID(idata.TemplateId)))
                    {
                        Id = new ID(idata.Id).ToString(),
                        DisplayName = idata.Name
                    };
                }
                RootNode.Server = _args.server;
            }
        }
Пример #30
0
			public ContentTreeNode(ContentItem item, ContentTreeNode parent)
			{
				Item = item;
				Parent = parent;
				SortOrder = item.SortOrder;
				ItemId = item.ID;
			}
Пример #31
0
		private List<ContentTreeNode> BuildNavTree()
		{
			List<ContentTreeNode> navTree = new List<ContentTreeNode>();
			var ci = Content.Current.Page;
			if (ci == null)
				return navTree;
			cId = ci.ID; // need to cache this due to the following if clause:
			if (ci.VersionOf != null && ci.VersionOf.Value != null)
				ci = ci.VersionOf.Value; // get the published version

			// follow the ancestral trail up to the desired "start from level"
			var convertedAncestralTrail = Array.ConvertAll(ci.AncestralTrail.Split(new [] { '/' }, StringSplitOptions.RemoveEmptyEntries), int.Parse);

			var xn = menuPart.MenuStartFromLevel;
			if (xn < 0)
				xn += convertedAncestralTrail.Length; // handle "zero" case

			var expandedParents = new List<ContentTreeNode>();
			for (var i = Math.Max(xn, 0); i < convertedAncestralTrail.Length; ++i)
			{
				var ancestorItem = Context.Current.Persister.Get(Convert.ToInt32(convertedAncestralTrail[i]));
				var ancestorNode = new ContentTreeNode(ancestorItem, navTree.LastOrDefault());
				navTree.Add(ancestorNode);

				// expand the ancestor
				// ReSharper disable LoopCanBeConvertedToQuery
				foreach (var item in GetChildren(ancestorItem))
					expandedParents.Add(new ContentTreeNode(item, ancestorNode));
				// ReSharper restore LoopCanBeConvertedToQuery
			}


			// Add current item ================================================================

			if (ci.Visible || menuPart.MenuShowCurrentItemIfHidden)
			{
				// -- add a node for the current page --
				var navItemCurrent = new ContentTreeNode(ci, navTree.LastOrDefault());
				var navItemCParent = navTree.LastOrDefault();
				navTree.Add(navItemCurrent);

				// -- get children and sibilings --
				// ReSharper disable LoopCanBeConvertedToQuery
				foreach (var child in GetChildren(ci).OrderBy(f => f.SortOrder))
					navTree.Add(new ContentTreeNode(child, navItemCurrent));
				// ReSharper restore LoopCanBeConvertedToQuery
			}



			// add the ancestors we just expanded 
			// ReSharper disable LoopCanBeConvertedToQuery
			foreach (var item in expandedParents)
				if (navTree.All(f => f.ItemId != item.ItemId))
					navTree.Add(item);
			// ReSharper restore LoopCanBeConvertedToQuery



			// show sibilings of the current item (put under navItemCParent)
			//if (menuPart.ShowSibilings != MenuPartBase.SibilingDisplayOptions.Never)
			//{
			//	if (menuPart.ShowSibilings == MenuPartBase.SibilingDisplayOptions.Always
			//		|| (menuPart.ShowSibilings == MenuPartBase.SibilingDisplayOptions.OnlyIfItemHasNoChildren && chil.Length > 0))
			//	{
			//		// ok...
			//		// ReSharper disable LoopCanBeConvertedToQuery
			//		foreach (var sibiling in sibs.OrderBy(f => f.SortOrder))
			//			navTree.Add(new ContentTreeNode(sibiling, navItemCParent));
			//		// ReSharper restore LoopCanBeConvertedToQuery
			//	}
			//}

			return navTree;
		}
 /// <summary>
 /// Navigates to the specified target content location.
 /// </summary>
 /// <param name="target">The target.</param>
 public void Navigate(ContentTreeNode target)
 {
     Navigate(SelectedNode, target);
 }
Пример #33
0
		// ReSharper disable ParameterTypeCanBeEnumerable.Local
		private void WriteChildList(ContentTreeNode currentNode, HtmlTextWriter xml, int level)
		{
			var childNodes = database.Where(f => f.Parent == currentNode).ToList();
			if (childNodes.Count <= 0) return;
#if ENABLE_DEBUG_COMMENTS
			xml.Write("<!-- WriteChildList(currentNode = {0}, level = {1} -->\n", currentNode.ItemId, level);
#endif
			xml.AddAttribute("class", currentNode == null ? menuPart.MenuOuterUlCssClass : menuPart.MenuInnerUlCssClass);
			xml.RenderBeginTag(HtmlTextWriterTag.Ul);

			if (currentNode == null && (!menuPart.MenuShowTreeRoot && childNodes.Count > 0)) // indicates that we are starting the menu, 
			{
				// Skip directly to the children of the root node.
				childNodes = database.Where(f => f.Parent == childNodes.First()).ToList();
			}

			foreach (var childNode in childNodes.OrderBy(n => n.SortOrder).ThenBy(n => n.Item.ID))
			{
				WriteListItem(childNode, xml, level, null);

				if (!menuPart.MenuNestChildUls)
				{
					WriteChildList(childNode, xml, level + 1);
				}
			}
			xml.RenderEndTag();
		}
Пример #34
0
        private RouteData GetRouteData(ContentTreeNode treeNode, HttpContextBase httpContext)
        {
            var routeData = GetRouteData(treeNode);
            var queryString = HttpUtility.ParseQueryString(httpContext.Request.Url.Query);
            var queryStringCollectionToCopy = new NameValueCollection();
            foreach (var item in queryString.Keys)
            {
                if (item != null)
                {
                    queryStringCollectionToCopy.Add(item.ToString(), queryString[item.ToString()]);
                }
            }
            queryStringCollectionToCopy.CopyTo(routeData.Values);

            return routeData;
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ContentNavigationButton"/> class.
 /// </summary>
 /// <param name="targetNode">The target node.</param>
 /// <param name="x">The x position.</param>
 /// <param name="y">The y position.</param>
 /// <param name="height">The height.</param>
 public ContentNavigationButton(ContentTreeNode targetNode, float x, float y, float height)
     : base(x, y, height)
 {
     TargetNode = targetNode;
     Text       = targetNode.NavButtonLabel + "/";
 }
Пример #36
0
 private string GetUrlForTreeNode(ContentTreeNode contentTreeNode)
 {
     var segments = contentTreeNode.GetPath();
     var sb = new StringBuilder();
     for(var n = 0; n < segments.Count(); n++)
     {
         sb.Append(segments[n]);
         if (n < segments.Count() - 1) sb.Append("/");
     }
     return sb.ToString();
 }
Пример #37
0
 private void RemoveFolder2Root(ContentTreeNode node)
 {
     // Remove from the root
     _root.RemoveChild(node);
 }
Пример #38
0
        private void WriteListItem(ContentTreeNode childNode, HtmlTextWriter xml, int level, string cssClass)
        {
#if ENABLE_DEBUG_COMMENTS
            // debug output
            xml.Write("<!-- WriteListItem(childNode.itemId = {0}, parent.itemId = {2}, level = {1} -->",
                      childNode != null ? childNode.ItemId : -1,
                      level,
                      (childNode != null && childNode.Parent != null) ? childNode.Parent.ItemId : -1);
#endif

            // write LI...
            var sn         = menuPart;
            var childItem  = childNode.Item;
            var isSelected = childItem.ID == currentPageId;

            if (cssClass == null)
            {
                cssClass = childNode.IsAncestor
                                        ? sn.MenuAncestorLiCssClass
                                        : isSelected ? sn.MenuSelectedLiCssClass : sn.MenuLiCssClass;
            }

            xml.AddAttribute("class", cssClass);
            xml.RenderBeginTag(HtmlTextWriterTag.Li);

            if (isSelected || (level == 0 && sn.MenuDontLinkTopLevel))
            {
                xml.RenderBeginTag(HtmlTextWriterTag.A);                 // wrap in a dummy <a> for Bootstrap 3, http://stackoverflow.com/questions/18329010/what-happened-to-nav-header-class
                xml.Write(childItem.Title);
                xml.RenderEndTag();
            }
            else
            {
                xml.AddAttribute("href", childItem.Url);
                xml.RenderBeginTag(HtmlTextWriterTag.A);
                xml.Write(childItem.Title);

                // render caret if subitems exist
                if (sn.MenuShowCaretOnItemsWithChildren &&
                    QueryApplicableChildren(childItem).Any() /* has any applicable children */)
                {
                    if (!String.IsNullOrWhiteSpace(sn.MenuCaretCustomHtml))
                    {
                        xml.Write(sn.MenuCaretCustomHtml);
                    }
                    else
                    {
                        // <b class="caret"></b>
                        xml.Write(' ');
                        xml.AddAttribute("class", "caret");
                        xml.RenderBeginTag(HtmlTextWriterTag.B);
                        xml.RenderEndTag();
                    }
                }
                xml.RenderEndTag();
            }

            if (menuPart.MenuNestChildUls)
            {
                WriteChildList(childNode, xml, level + 1);
            }

            xml.RenderEndTag();             // </li>
            xml.WriteLine();
        }
Пример #39
0
		private void WriteListItem(ContentTreeNode childNode, HtmlTextWriter xml, int level, string cssClass)
		{
			// write LI...
			var sn = menuPart;
			var childItem = childNode.Item;
			var isSelected = childItem.ID == cId;

			if (cssClass == null)
				cssClass = isSelected ? sn.MenuSelectedLiCssClass : sn.MenuLiCssClass;
			xml.AddAttribute("class", cssClass);
			xml.RenderBeginTag(HtmlTextWriterTag.Li);

			if (isSelected || (level == 0 && sn.MenuDontLinkTopLevel))
			{
				xml.Write(childItem.Title);
			}
			else
			{
				xml.AddAttribute("href", childItem.Url);
				xml.RenderBeginTag(HtmlTextWriterTag.A);
				xml.Write(childItem.Title);

				// render caret if subitems exist
				if (sn.MenuShowCaretOnItemsWithChildren
					&& database.Any(f => f.Parent == childNode))
				{
					// <b class="caret"></b> 
					xml.Write(' ');
					xml.AddAttribute("class", "caret");
					xml.RenderBeginTag(HtmlTextWriterTag.B);
					xml.RenderEndTag();
				}
				xml.RenderEndTag();
			}

			xml.RenderEndTag(); // </li>
			xml.WriteLine();
		}
Пример #40
0
        private void loadFolder(ContentTreeNode node, bool checkSubDirs)
        {
            if (node == null)
            {
                return;
            }

            // Temporary data
            var folder = node.Folder;
            var path   = folder.Path;

            // Check for missing files/folders (skip it during fast tree setup)
            if (!_isDuringFastSetup)
            {
                for (int i = 0; i < folder.Children.Count; i++)
                {
                    var child = folder.Children[i];
                    if (!child.Exists)
                    {
                        // Send info
                        Editor.Log(string.Format($"Content item \'{child.Path}\' has been removed"));

                        // Destroy it
                        Delete(child);

                        i--;
                    }
                }
            }

            // Find elements (use separate path for scripts and assets - perf stuff)
            if (node.CanHaveAssets)
            {
                LoadAssets(node, path);
            }
            if (node.CanHaveScripts)
            {
                LoadScripts(node, path);
            }

            // Get child directories
            var childFolders = Directory.GetDirectories(path);

            // Load child folders
            bool sortChildren = false;

            for (int i = 0; i < childFolders.Length; i++)
            {
                var childPath = StringUtils.NormalizePath(childFolders[i]);

                // Check if node already has that element (skip during init when we want to walk project dir very fast)
                ContentFolder childFolderNode = _isDuringFastSetup ? null : node.Folder.FindChild(childPath) as ContentFolder;
                if (childFolderNode == null)
                {
                    // Create node
                    ContentTreeNode n = new ContentTreeNode(node, childPath);
                    if (!_isDuringFastSetup)
                    {
                        sortChildren = true;
                    }

                    // Load child folder
                    loadFolder(n, true);

                    // Fire event
                    if (_enableEvents)
                    {
                        ItemAdded?.Invoke(n.Folder);
                        OnWorkspaceModified?.Invoke();
                    }
                    _itemsCreated++;
                }
                else if (checkSubDirs)
                {
                    // Update child folder
                    loadFolder(childFolderNode.Node, true);
                }
            }
            if (sortChildren)
            {
                node.SortChildren();
            }
        }
Пример #41
0
		// ReSharper disable ParameterTypeCanBeEnumerable.Local
		private void WriteChildList(ContentTreeNode currentNode, HtmlTextWriter xml, int level)
		{
			var childNodes = database.Where(f => f.Parent == currentNode).ToList();
			if (childNodes.Count <= 0) return;

			xml.AddAttribute("class", currentNode == null ? menuPart.MenuOuterUlCssClass : menuPart.MenuInnerUlCssClass);
			xml.RenderBeginTag(HtmlTextWriterTag.Ul);
			foreach (var childNode in childNodes.OrderBy(n => n.SortOrder).ThenBy(n => n.Item.ID))
			{
				// Write the <li> if showing the root node, or not at the root node level
				var showCurrentChildNode = menuPart.MenuShowTreeRoot || level != 0;
				if (showCurrentChildNode)
				{
					WriteListItem(childNode, xml, level, null);
				}
				else
				{
					// If not showing the current node, then start with the child list.
					WriteChildList(childNode, xml, level + 1);
				}

				// Show the non-nested <ul> only if we have just added a <li>
				if (showCurrentChildNode && !menuPart.MenuNestChildUls)
				{
					WriteChildList(childNode, xml, level + 1);
				}
			}
			xml.RenderEndTag();
		}
Пример #42
0
		// ReSharper restore ParameterTypeCanBeEnumerable.Local

		/// <summary>
		/// Writes the top two levels of a tree flattened into a single list, with header styles on the level-1 list
		/// items, and with sub-items in their respective hierarchies. 
		/// </summary>
		/// <param name="menuPart"></param>
		/// <param name="database"></param>
		/// <param name="currentNode"></param>
		/// <param name="xml"></param>
		private void WriteListWithHeaders(ContentTreeNode currentNode, HtmlTextWriter xml)
		{
			var childNodes = database.Where(f => f.Parent == currentNode).ToList();
			if (childNodes.Count <= 0) return;

			xml.AddAttribute("class", currentNode == null ? menuPart.MenuOuterUlCssClass : menuPart.MenuInnerUlCssClass);
			xml.RenderBeginTag(HtmlTextWriterTag.Ul);
			foreach (var childNode in childNodes.OrderBy(n => n.SortOrder).OrderBy(n => n.Item.ID))
			{
				WriteListItem(childNode, xml, 0, "nav-header"); // header item

				var childNodes2 = database.Where(f => f.Parent == childNode).OrderBy(n => n.SortOrder).ToList();
				foreach (var childnode2 in childNodes2)
				{
					WriteListItem(childnode2, xml, 1, null);
					WriteChildList(childnode2, xml, 2);
				}
			}
			xml.RenderEndTag();
		}
Пример #43
0
		// ReSharper disable ParameterTypeCanBeEnumerable.Local
		private void WriteChildList(ContentTreeNode currentNode, HtmlTextWriter xml, int level)
		{
			var childNodes = database.Where(f => f.Parent == currentNode).ToList();
			if (childNodes.Count <= 0) return;

			xml.AddAttribute("class", currentNode == null ? menuPart.MenuOuterUlCssClass : menuPart.MenuInnerUlCssClass);
			xml.RenderBeginTag(HtmlTextWriterTag.Ul);
			foreach (var childNode in childNodes.OrderBy(n => n.SortOrder).OrderBy(n => n.Item.ID))
			{
				WriteListItem(childNode, xml, level, null);
				WriteChildList(childNode, xml, level + 1);
			}
			xml.RenderEndTag();
		}