Exemplo n.º 1
0
        private IList <NavBE> Nav_GetInternal(DataCommand queryCommand)
        {
            List <NavBE> navPages = new List <NavBE>();

            queryCommand.Execute(delegate(IDataReader dr) {
                while (dr.Read())
                {
                    NavBE np = Nav_Populate(dr);
                    navPages.Add(np);
                }
            });
            return(navPages);
        }
Exemplo n.º 2
0
 //--- Constructors ---
 public ExpandableNavPage(NavBE navPage)
 {
     this.NavPage = navPage;
 }
Exemplo n.º 3
0
        public Yield GetNavigationFull(DreamContext context, DreamMessage request, Result <DreamMessage> response)
        {
            CheckResponseCache(context, false);

            PageBE page = PageBL_GetPageFromUrl(context, false);

            if (page.Title.IsTalk)
            {
                page = PageBL.GetPageByTitle(page.Title.AsFront());
            }

            // check if requestest page exists, otherwise find nearest parent
            uint         new_page_id = NavBL.NEW_PAGE_ID;
            ulong        homepageId  = DekiContext.Current.Instance.HomePageId;
            List <NavBE> list;
            bool         expandableNav = context.GetParam("type", "compact").EqualsInvariantIgnoreCase("expandable");

            // check if a page was found
            if (page.ID == 0)
            {
                // find nearest ancestor and authorize access
                PageBE ancestor = page;
                while (!ancestor.Title.IsHomepage)
                {
                    // fetch ancestor page based on title
                    ulong id = DbUtils.CurrentSession.Nav_GetNearestParent(ancestor.Title);
                    ancestor = PageBL.GetPageById(id);
                    if (PermissionsBL.IsUserAllowed(DekiContext.Current.User, ancestor, Permissions.BROWSE))
                    {
                        break;
                    }

                    // determine parent page title
                    Title title = ancestor.Title.GetParent();
                    if (title == null)
                    {
                        // current ancestor was the homepage
                        break;
                    }
                    ancestor = new PageBE {
                        Title = title
                    };
                }
                if (ancestor.ID == 0)
                {
                    ancestor = PageBL.GetHomePage();
                }
                list = NavBL.QueryNavTreeData(ancestor, context.Culture, expandableNav).ToList();

                // find the nearest parent node and increase its child count
                foreach (NavBE nearestAncestors in list)
                {
                    if (nearestAncestors.Id == ancestor.ID)
                    {
                        nearestAncestors.ChildCount = nearestAncestors.ChildCount + 1;
                        break;
                    }
                }

                // for each missing node, generate a dummy page and insert it into result set
                ulong        ancestor_id       = ancestor.ID;
                string[]     ancestor_segments = ancestor.Title.AsUnprefixedDbSegments();
                string[]     new_page_segments = page.Title.AsUnprefixedDbSegments();
                List <NavBE> newNodes          = new List <NavBE>(32);
                for (int i = ancestor_segments.Length; i < new_page_segments.Length; ++i)
                {
                    string title = string.Join("/", new_page_segments, 0, i + 1);

                    // create dummy node with <page><page_id /><page_namespace /><page_title ><page_parent /><page_children /></page>
                    NavBE newPage = new NavBE {
                        Id         = new_page_id,
                        NameSpace  = (ushort)page.Title.Namespace,
                        Title      = title,
                        ParentId   = (ancestor_id == homepageId) ? 0 : ancestor_id,
                        ChildCount = (i == new_page_segments.Length - 1) ? 0 : 1
                    };
                    newNodes.Add(newPage);

                    // update page information
                    page.ID       = new_page_id;
                    page.ParentID = ancestor_id;
                    ancestor_id   = new_page_id++;
                }

                // check if we need to remove the children nodes of the ancestor
                ancestor_id = (ancestor.ID == homepageId) ? 0 : (uint)ancestor.ID;
                if (!expandableNav && (new_page_segments.Length - ancestor_segments.Length) > 1)
                {
                    // remove ancestor children and add new dummy nodes
                    for (int start = 0; start < list.Count; ++start)
                    {
                        // check if we found a matching child
                        if ((list[start].ParentId == ancestor_id) && (list[start].Id != homepageId))
                        {
                            // look for last child to remove so we can remove an entire range at once
                            int end = start + 1;
                            for (; (end < list.Count) && (list[end].ParentId == ancestor_id) && (list[end].Id != homepageId); ++end)
                            {
                            }
                            list.RemoveRange(start, end - start);
                            --start;
                        }
                    }
                }
                else
                {
                    // find where among the ancestor children we need to insert the dummy node
                    for (int index = 0; index < list.Count; ++index)
                    {
                        NavBE current = list[index];
                        if ((current.ParentId == ancestor_id) && (current.Id != homepageId))
                        {
                            string[] parts = Title.FromDbPath(NS.UNKNOWN, current.Title, current.DisplayName).AsUnprefixedDbSegments();
                            if ((parts.Length > 0) && (new_page_segments.Length > 0) && (string.Compare(parts[parts.Length - 1], new_page_segments[parts.Length - 1], true, context.Culture) > 0))
                            {
                                // found the spot
                                list.InsertRange(index, newNodes);
                                newNodes = null;
                                break;
                            }
                        }
                    }
                }

                // check if we didn't find the spot
                if (newNodes != null)
                {
                    // add new nodes to the end
                    list.AddRange(newNodes);
                }
            }
            else
            {
                list = NavBL.QueryNavTreeData(page, context.Culture, expandableNav).ToList();
            }

            // find first parent
            ulong parent_id    = homepageId;
            int   parent_index = -1;

            for (int i = 0; i < list.Count; ++i)
            {
                if (list[i].Id == parent_id)
                {
                    parent_index = i;
                    break;
                }
            }
            if (parent_index == -1)
            {
                throw new Exception("unexpected [homepage not found]");
            }

            // add any missing ancestor nodes (might have been removed by permission check or might simply not exist)
            string[] page_segments = page.Title.AsUnprefixedDbSegments();
            ushort   ns            = (ushort)page.Title.Namespace;

            for (int i = 0; i <= page_segments.Length; ++i)
            {
                string title = string.Join("/", page_segments, 0, i);

                // loop over all nodes
                bool found = false;
                for (int j = 0; j < list.Count; ++j)
                {
                    NavBE node = list[j];

                    // NOTE (steveb): we walk the path one parent at a time; however, there are a few special cases, because of namespaces
                    //      for instance, the parent page of User:Bob is the homepage (ditto for Template:Page), but the parent page of Admin:Config is Admin:

                    // check if we found a node matching the current title
                    if ((string.Compare(node.Title, title, true, context.Culture) == 0) && (((i == 0) && (ns != (ushort)NS.ADMIN)) ? (node.NameSpace == (ushort)NS.MAIN) : (node.NameSpace == ns)))
                    {
                        found = true;

                        // let's make sure node is pointing to right parent
                        node.ParentId = (parent_id == homepageId) ? 0 : parent_id;
                        parent_id     = node.Id;
                        parent_index  = j;
                        break;
                    }
                }
                if (!found)
                {
                    // node is missing, let's create a new one
                    NavBE newPage = new NavBE {
                        Id        = new_page_id,
                        NameSpace = (ushort)page.Title.Namespace,
                        Title     = title,
                        ParentId  = (parent_id == homepageId) ? 0 : parent_id, ChildCount = 1
                    };

                    // add new page after parent
                    list.Insert(parent_index + 1, newPage);
                    parent_id    = new_page_id++;
                    parent_index = parent_index + 1;
                }
            }

            // build response
            if (ShowDebug(context))
            {
                response.Return(DreamMessage.Ok(NavBL.ConvertNavPageListToDoc(list)));
            }
            else
            {
                XDoc result = expandableNav ? NavBL.ComputeExpandableNavigationDocument(list, page, 0, 0, false) : NavBL.ComputeNavigationDocument(list, page, 0, 0, false, context.GetParam("width", int.MaxValue));
                if (ShowXml(context))
                {
                    response.Return(DreamMessage.Ok(result));
                }
                else
                {
                    response.Return(DreamMessage.Ok(new XDoc("tree").Value(result.Contents)));
                }
            }
            yield break;
        }
Exemplo n.º 4
0
        public static XDoc ComputeNavigationDocument(IList <NavBE> list, PageBE page, uint splitSibling, uint splitChildren, bool hidden, int max_width)
        {
            XDoc          result          = new XDoc("tree");
            List <string> css             = new List <string>();
            List <string> fetchedChildren = new List <string>();
            List <NavBE>  childrenNodes   = new List <NavBE>();
            ulong         homepageId      = DekiContext.Current.Instance.HomePageId;
            NavDocStage   stage           = NavDocStage.None;

            if (splitSibling > 0)
            {
                stage = NavDocStage.SiblingPre;
                result.Start("siblings-pre");
            }
            else if (splitChildren > 0)
            {
                stage = NavDocStage.ChildrenPre;
                result.Start("siblings-pre").End();
                result.Start("children-pre");
            }
            int splitSiblingIndex  = 0;
            int splitChildrenIndex = 0;

            // fix page_parent_id: it's stored as zero for home and children of home
            ulong page_parent_id = page.ParentID;

            if ((page_parent_id == 0) && (page.ID != homepageId))
            {
                page_parent_id = homepageId;
            }
            int page_index = 0;

            // iterate over result set
            int siblingIndex = 0;
            int childIndex   = 0;

            foreach (NavBE node in list)
            {
                // retrieve page values
                uint  node_id        = node.Id;
                ulong node_parent_id = node.ParentId;
                bool  virtual_node   = (node_id >= NEW_PAGE_ID);

                // fix parent_id: it's stored as zero for home and children of home
                if ((node_parent_id == 0) && (node_id != homepageId))
                {
                    node_parent_id = homepageId;
                }

                // set node index (if possible)
                if (node_id == page.ID)
                {
                    page_index = siblingIndex;
                }

                // check if we need to split the output
                if (node_id == splitSibling)
                {
                    splitSiblingIndex = siblingIndex;
                    stage             = NavDocStage.ChildrenPre;
                    result.End().Start("children-pre");
                    if (splitChildren == 0)
                    {
                        stage = NavDocStage.ChildrenPost;
                        result.End().Start("children-post");
                    }
                    continue;
                }
                if (node_id == splitChildren)
                {
                    splitChildrenIndex = childIndex;
                    stage = NavDocStage.ChildrenPost;
                    result.End().Start("children-post");
                    continue;
                }
                if (((stage == NavDocStage.ChildrenPre) || (stage == NavDocStage.ChildrenPost)) && (splitSibling > 0) && (node_parent_id != splitSibling))
                {
                    if (stage == NavDocStage.ChildrenPre)
                    {
                        result.End().Start("children-post");
                    }
                    stage = NavDocStage.SiblingPost;
                    result.End().Start("siblings-post");
                }

                // check if this node is part of the result set (only include ancestors, siblings, and children of selected node)
                bool  ancestor  = false;
                Title nodeTitle = Title.FromDbPath((NS)node.NameSpace, node.Title, node.DisplayName);
                if ((node_id != page.ID /* selected */) && (node_parent_id != page_parent_id /* sibling */) && (node_parent_id != page.ID /* child */))
                {
                    ancestor = (node_id == page_parent_id /* immediate parent */) || (node_id == homepageId) || nodeTitle.IsParentOf(page.Title);
                    if (!ancestor)
                    {
                        continue;
                    }
                }

                // don't include siblings root user pages
                if (((page.Title.IsUser) || (page.Title.IsSpecial) || (page.Title.IsTemplate)) && (page_parent_id == homepageId) && (node_parent_id == homepageId) && (node_id != page.ID))
                {
                    continue;
                }

                // 'div' element
                result.Start("div");

                // 'class' attribute
                css.Clear();
                css.Add("node");
                if (hidden)
                {
                    css.Add("closedNode");
                }

                // 'c' (children) attribute
                fetchedChildren.Clear();
                childrenNodes.Clear();
                uint parentId = (node_id == homepageId) ? 0 : node_id;
                for (int i = 0; i < list.Count; ++i)
                {
                    NavBE child = list[i];
                    if ((child.ParentId == parentId) & (child.Id != homepageId))
                    {
                        Title childTitle = Title.FromDbPath((NS)child.NameSpace, child.Title, child.DisplayName);

                        // skip children if they are siblings of the top User: or Template: page
                        if (((page.Title.IsUser) || (page.Title.IsSpecial) || (page.Title.IsTemplate)) && (node_id == homepageId) && !childTitle.IsParentOf(page.Title))
                        {
                            continue;
                        }
                        childrenNodes.Add(child);
                        fetchedChildren.Add("n" + child.Id);
                    }
                }
                int totalChildrenCount = node.ChildCount ?? fetchedChildren.Count;

                // 'p' (parent) attribute
                string p = null;
                if (node_id != homepageId)
                {
                    p = "n" + node_parent_id;
                }

                // 'cd' (child-data) and 'sd' (sibling-data) attribute
                string cd = null;
                string sd;
                if (node_id == page.ID)
                {
                    // active node
                    if (node_id == homepageId)
                    {
                        css.Add("dockedNode");
                        css.Add("homeNode");
                        css.Add("parentClosed");
                        css.Add("homeSelected");
                    }
                    else
                    {
                        css.Add("childNode");
                        if (!hidden)
                        {
                            css.Add("sibling");
                        }
                        if (totalChildrenCount > 0)
                        {
                            css.Add("parentOpen");
                        }
                    }
                    css.Add("selected");

                    // we have all the child data
                    cd = "1";
                    sd = "1";
                }
                else if (node_parent_id == page_parent_id)
                {
                    // sibling of active node
                    css.Add("childNode");
                    if (!hidden)
                    {
                        css.Add("sibling");
                    }
                    if (totalChildrenCount > 0)
                    {
                        css.Add("parentClosed");
                    }

                    // if no children exist, then we have all the child data
                    cd = ((totalChildrenCount > 0) ? "0" : "1");
                    sd = "1";
                }
                else if (node_parent_id == page.ID)
                {
                    // child of active node
                    css.Add("childNode");
                    if ((node_parent_id == homepageId) && !hidden)
                    {
                        css.Add("sibling");
                    }
                    if ((page.ID != homepageId) && !hidden)
                    {
                        css.Add("selectedChild");
                    }
                    if (totalChildrenCount > 0)
                    {
                        css.Add("parentClosed");
                    }

                    // if no children exist, then we have all the child data
                    cd = ((totalChildrenCount > 0) ? "0" : "1");
                    sd = "1";
                }
                else if (ancestor)
                {
                    // ancestor of active node (parent and above)
                    css.Add("dockedNode");
                    if (node_id == homepageId)
                    {
                        css.Add("homeNode");
                    }
                    if (node_id == page_parent_id)
                    {
                        css.Add("lastDocked");
                    }
                    css.Add("parentClosed");

                    // check if we are the last docked node or have more than one child
                    if ((node_id == page_parent_id) || (totalChildrenCount == 1))
                    {
                        cd = "1";
                    }
                    else
                    {
                        // find the child node that is actually included in the tree
                        foreach (NavBE child in childrenNodes)
                        {
                            Title childTitle = Title.FromDbPath((NS)child.NameSpace, child.Title, child.DisplayName);
                            if (childTitle.IsParentOf(page.Title))
                            {
                                cd = "n" + child.Id;
                                break;
                            }
                        }
                        if (cd == null)
                        {
#if DEBUG
                            throw new Exception("unexpected [expected to find child nodes]");
#else
                            cd = "1";
#endif
                        }
                    }

                    // check if parent of this node has more than one child
                    if ((node_id == homepageId) || (result[string.Format("div[@id='{0}']/@cd", "n" + node_parent_id)].Contents == "1"))
                    {
                        sd = "1";
                    }
                    else
                    {
                        sd = "0";
                    }
                }
                else
                {
                    throw new Exception("unexpected");
                }

                // attributes
                result.Attr("class", string.Join(" ", css.ToArray()));
                result.Attr("id", "n" + node_id.ToString());
                if (fetchedChildren.Count > 0)
                {
                    result.Attr("c", string.Join(",", fetchedChildren.ToArray()));
                }
                if (p != null)
                {
                    result.Attr("p", p);
                }

                // NOTE (steveb): this is used by the JS in the browser to correlate nodes in the pane (it's never used by anything else; hence the different format)
                string safe_path = nodeTitle.AsPrefixedDbPath().Replace("//", "%2f");
                result.Attr("path", (safe_path.Length == 0) ? string.Empty : (safe_path + "/"));

                // root page always has all children if they belong to User:, Template:, or Special: namespace
                if ((cd != "1") && !virtual_node && ((page.Title.IsMain) || (((page.Title.IsTemplate) || (page.Title.IsUser) || (page.Title.IsSpecial)) && (node_id != homepageId))))
                {
                    result.Attr("cd", cd);
                }

                // children of root page always have all siblings if they belong to User:, Template:, or Special: namespace
                if ((sd != "1") && !virtual_node && ((page.Title.IsMain) || (((page.Title.IsTemplate) || (page.Title.IsUser) || (page.Title.IsSpecial)) && (node_parent_id != homepageId))))
                {
                    result.Attr("sd", "0");
                }
                if (virtual_node || ((node_id == homepageId) && (!page.Title.IsMain)))
                {
                    result.Attr("reload", "1");
                }

                // div contents
                result.Start("a");

                // set page title
                string name = nodeTitle.AsUserFriendlyName();
                result.Attr("href", Utils.AsPublicUiUri(nodeTitle));
                result.Attr("title", name);
                result.Elem("span", DekiWikiService.ScreenFont.Truncate(name, max_width));
                result.End();
                result.End();
                if (node_parent_id == page_parent_id)
                {
                    ++siblingIndex;
                }
                else if (node_parent_id == page.ID)
                {
                    ++childIndex;
                }
            }

            // post-process created list
            if ((splitSibling > 0) || (splitChildren > 0))
            {
                if (stage == NavDocStage.SiblingPre)
                {
                    result.End().Start("siblings-post");
                    result.End().Start("children-pre");
                    result.End().Start("children-post");
                }
                else if (stage == NavDocStage.ChildrenPre)
                {
                    result.End().Start("children-post");
                    result.End().Start("siblings-post");
                }
                else if (stage == NavDocStage.ChildrenPost)
                {
                    result.End().Start("siblings-post");
                }
                result.End();

                // truncate siblings and children
                TruncateList(result["siblings-pre/div | siblings-post/div"], ~splitSiblingIndex, hidden);
                TruncateList(result["children-pre/div | children-post/div"], ~splitChildrenIndex, hidden);
            }
            else if (hidden)
            {
                // truncate full list
                TruncateList(result["div"], 0, hidden);
            }
            else
            {
                // truncate children of selected node
                TruncateList(result[string.Format("div[@p='n{0}']", page.ID)], 0, hidden);

                // truncate siblings of selected node
                TruncateList(result[string.Format("div[@p='n{0}']", page_parent_id)], page_index, hidden);
            }
            return(result);
        }