/// <summary>
        /// A method that will return the posts sorted by published date in an efficient way
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="articulateArchiveId"></param>
        /// <param name="pager"></param>
        /// <returns></returns>
        public static IEnumerable<IPublishedContent> GetPostsSortedByPublishedDate(this UmbracoHelper helper, int articulateArchiveId, PagerModel pager)
        {
            var xPathNavigator = helper.UmbracoContext.ContentCache.GetXPathNavigator(false);
            var xPathChildren = $"//* [@id={articulateArchiveId}]/*[@isDoc]";

            //Filter/Sort the children we're looking for with XML
            var xmlListItems = xPathNavigator.Select(xPathChildren)
                .Cast<XPathNavigator>()
                .OrderByDescending(x =>
                {
                    var publishedDate = DateTime.MinValue;

                    var xmlNode = x.SelectSingleNode("publishedDate [not(@isDoc)]");
                    if (xmlNode == null)
                        return publishedDate;

                    publishedDate = xmlNode.ValueAsDateTime;
                    return publishedDate;
                })
                .Skip(pager.CurrentPageIndex * pager.PageSize)
                .Take(pager.PageSize);

            //Now we can select the IPublishedContent instances by Id
            var listItems = helper.TypedContent(xmlListItems.Select(x => int.Parse(x.GetAttribute("id", ""))));

            return listItems;
        }
예제 #2
0
        public ListModel(IPublishedContent content, IEnumerable<IPublishedContent> listItems, PagerModel pager)
            : base(content)
        {
            if (listItems == null) throw new ArgumentNullException("listItems");
            if (pager == null) throw new ArgumentNullException("pager");
            _pager = pager;

            _listItems = listItems;
        }
예제 #3
0
        private ActionResult RenderView(IRenderModel model, int? p = null)
        {
            var listNode = model.Content.Children
               .FirstOrDefault(x => x.DocumentTypeAlias.InvariantEquals("ArticulateArchive"));
            if (listNode == null)
            {
                throw new InvalidOperationException("An ArticulateArchive document must exist under the root Articulate document");
            }

            if (p != null && p.Value == 1)
            {
                return new RedirectToUmbracoPageResult(model.Content, UmbracoContext);
            }

            if (p == null || p.Value <= 0)
            {
                p = 1;
            }

            var rootPageModel = new ListModel(model.Content);

            //TODO: I wonder about the performance of this - when we end up with thousands of blog posts,
            // this will probably not be so efficient. I wonder if using an XPath lookup for batches of children
            // would work? The children count could be cached. I'd rather not put blog posts under 'month' nodes
            // just for the sake of performance. Hrm.... Examine possibly too.

            var totalPosts = listNode.Children.Count();
            var pageSize = rootPageModel.PageSize;
            var totalPages = Convert.ToInt32(Math.Ceiling((double)totalPosts/pageSize));

            //Invalid page, redirect without pages
            if (totalPages > 0 && totalPages < p)
            {
                return new RedirectToUmbracoPageResult(model.Content, UmbracoContext);
            }

            var pager = new PagerModel(
                pageSize,
                p.Value - 1,
                totalPages,
                totalPages > p ? model.Content.Url.EnsureEndsWith('?') + "p=" + (p + 1) : null,
                p > 2 ? model.Content.Url.EnsureEndsWith('?') + "p=" + (p - 1) : p > 1 ? model.Content.Url : null);

            var listModel = new ListModel(listNode, pager);
            return View(PathHelper.GetThemeViewPath(listModel, "List"), listModel);
        }
예제 #4
0
        private ActionResult RenderView(IRenderModel model, int? p = null)
        {
            var listNode = model.Content.Children
               .FirstOrDefault(x => x.DocumentTypeAlias.InvariantEquals("ArticulateArchive"));
            if (listNode == null)
            {
                throw new InvalidOperationException("An ArticulateArchive document must exist under the root Articulate document");
            }

            if (p != null && p.Value == 1)
            {
                return new RedirectToUmbracoPageResult(model.Content, UmbracoContext);
            }

            if (p == null || p.Value <= 0)
            {
                p = 1;
            }

            var rootPageModel = new MasterModel(model.Content);

            //get the count with XPath, this will be the fastest
            var totalPosts = Umbraco.GetPostCount(listNode.Id);

            var pageSize = rootPageModel.PageSize;
            var totalPages = Convert.ToInt32(Math.Ceiling((double)totalPosts/pageSize));

            //Invalid page, redirect without pages
            if (totalPages > 0 && totalPages < p)
            {
                return new RedirectToUmbracoPageResult(model.Content, UmbracoContext);
            }

            var pager = new PagerModel(
                pageSize,
                p.Value - 1,
                totalPages,
                totalPages > p ? model.Content.Url.EnsureEndsWith('?') + "p=" + (p + 1) : null,
                p > 2 ? model.Content.Url.EnsureEndsWith('?') + "p=" + (p - 1) : p > 1 ? model.Content.Url : null);

            var listItems = Umbraco.GetPostsSortedByPublishedDate(listNode.Id, pager);

            var listModel = new ListModel(listNode, listItems, pager);
            return View(PathHelper.GetThemeViewPath(listModel, "List"), listModel);
        }
        public ActionResult Index(RenderModel model, int? maxItems)
        {
            if (!maxItems.HasValue) maxItems = 25;

            var listNode = model.Content.Children
               .FirstOrDefault(x => x.DocumentTypeAlias.InvariantEquals("ArticulateArchive"));
            if (listNode == null)
            {
                throw new InvalidOperationException("An ArticulateArchive document must exist under the root Articulate document");
            }

            var pager = new PagerModel(maxItems.Value, 0, 1);

            var listItems = Umbraco.GetPostsSortedByPublishedDate(listNode.Id, pager);

            var rootPageModel = new ListModel(listNode, listItems, pager);
            
            var feed = FeedGenerator.GetFeed(rootPageModel, rootPageModel.Children<PostModel>());

            return new RssResult(feed, rootPageModel);
        }
        /// <summary>
        /// Used to render the search result listing (virtual node)
        /// </summary>
        /// <param name="model"></param>
        /// <param name="term">
        /// The search term
        /// </param>
        /// <param name="provider">
        /// The search provider name (optional)
        /// </param>
        /// <param name="p"></param>
        /// <returns></returns>
        public ActionResult Search(RenderModel model, string term, string provider = null, int? p = null)
        {
            var tagPage = model.Content as ArticulateVirtualPage;
            if (tagPage == null)
            {
                throw new InvalidOperationException("The RenderModel.Content instance must be of type " + typeof(ArticulateVirtualPage));
            }

            //create a blog model of the main page
            var rootPageModel = new ListModel(model.Content.Parent);

            if (term == null)
            {
                //nothing to search, just render the view
                var emptyList = new ListModel(tagPage, Enumerable.Empty<IPublishedContent>(), new PagerModel(rootPageModel.PageSize, 0, 0));
                return View(PathHelper.GetThemeViewPath(emptyList, "List"), emptyList);
            }

            if (p != null && p.Value == 1)
            {
                return new RedirectToUmbracoPageResult(model.Content, UmbracoContext);
            }

            if (p == null || p.Value <= 0)
            {
                p = 1;
            }

            var splitSearch = term.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            //The fields to search on and their 'weight' (importance)
            var fields = new Dictionary<string, int>
            {
                {"markdown", 2},
                {"richText", 2},
                {"nodeName", 3},
                {"tags", 1},
                {"categories", 1},
                {"umbracoUrlName", 3}
            };

            //The multipliers for match types
            const int exactMatch = 5;
            const int termMatch = 2;

            var fieldQuery = new StringBuilder();
            //build field query
            foreach (var field in fields)
            {
                //full exact match (which has a higher boost)
                fieldQuery.Append(string.Format("{0}:{1}^{2}", field.Key, "\"" + term + "\"", field.Value * exactMatch));
                fieldQuery.Append(" ");
                //NOTE: Phrase match wildcard isn't really supported unless you use the Lucene
                // API like ComplexPhraseWildcardSomethingOrOther...
                //split match
                foreach (var s in splitSearch)
                {
                    //match on each term, no wildcard, higher boost
                    fieldQuery.Append(string.Format("{0}:{1}^{2}", field.Key, s, field.Value * termMatch));
                    fieldQuery.Append(" ");

                    //match on each term, with wildcard
                    fieldQuery.Append(string.Format("{0}:{1}*", field.Key, s));
                    fieldQuery.Append(" ");
                }
            }

            var criteria = provider == null
                ? ExamineManager.Instance.CreateSearchCriteria()
                : ExamineManager.Instance.SearchProviderCollection[provider].CreateSearchCriteria();

            criteria.RawQuery(string.Format("+parentID:{0} +({1})", rootPageModel.BlogArchiveNode.Id, fieldQuery));

            var searchProvider = provider == null
                ? ExamineManager.Instance.DefaultSearchProvider
                : ExamineManager.Instance.SearchProviderCollection[provider];

            var searchResult = Umbraco.TypedSearch(criteria, searchProvider).ToArray();

            //TODO: I wonder about the performance of this - when we end up with thousands of blog posts,
            // this will probably not be so efficient. I wonder if using an XPath lookup for batches of children
            // would work? The children count could be cached. I'd rather not put blog posts under 'month' nodes
            // just for the sake of performance. Hrm.... Examine possibly too.

            var totalPosts = searchResult.Count();
            var pageSize = rootPageModel.PageSize;

            var totalPages = totalPosts == 0 ? 1 : Convert.ToInt32(Math.Ceiling((double)totalPosts / pageSize));

            //Invalid page, redirect without pages
            if (totalPages < p)
            {
                return new RedirectToUmbracoPageResult(model.Content.Parent, UmbracoContext);
            }

            var pager = new PagerModel(
                pageSize,
                p.Value - 1,
                totalPages,
                totalPages > p ? model.Content.Url.EnsureEndsWith('?') + "term=" + term + "&p=" + (p + 1) : null,
                p > 2 ? model.Content.Url.EnsureEndsWith('?') + "term=" + term + "&p=" + (p - 1) : p > 1 ? model.Content.Url.EnsureEndsWith('?') + "term=" + term : null);

            var listModel = new ListModel(tagPage, searchResult, pager);

            return View(PathHelper.GetThemeViewPath(listModel, "List"), listModel);
        }
예제 #7
0
        /// <summary>
        /// Constructor accepting an explicit list of child items
        /// </summary>
        /// <param name="content"></param>
        /// <param name="listItems"></param>
        /// <param name="pager"></param>
        /// <remarks>
        /// Default sorting by published date will be disabled for this list model, it is assumed that the list items will
        /// already be sorted.
        /// </remarks>
        public ListModel(IPublishedContent content, IEnumerable <IPublishedContent> listItems, PagerModel pager)
            : base(content)
        {
            if (content == null)
            {
                throw new ArgumentNullException(nameof(content));
            }
            if (listItems == null)
            {
                throw new ArgumentNullException(nameof(listItems));
            }
            if (pager == null)
            {
                throw new ArgumentNullException(nameof(pager));
            }

            _pager     = pager;
            _listItems = listItems;
            if (content.ContentType.Alias.Equals("ArticulateArchive"))
            {
                PageTitle = BlogTitle + " - " + BlogDescription;
            }
            else
            {
                PageTags = Name;
            }
        }
예제 #8
0
 /// <summary>
 /// Constructor accepting an explicit list of child items
 /// </summary>
 /// <param name="content"></param>
 /// <param name="listItems"></param>
 /// <param name="pager"></param>
 /// <remarks>
 /// Default sorting by published date will be disabled for this list model, it is assumed that the list items will
 /// already be sorted.
 /// </remarks>
 public ListModel(IPublishedContent content, IEnumerable <IPublishedContent> listItems, PagerModel pager)
     : base(content)
 {
     if (listItems == null)
     {
         throw new ArgumentNullException("listItems");
     }
     if (pager == null)
     {
         throw new ArgumentNullException("pager");
     }
     _pager       = pager;
     _disableSort = true;
     _listItems   = listItems;
 }
        /// <summary>
        /// Returns a list of the most recent posts
        /// </summary>
        /// <param name="helper"></param>
        /// <param name="masterModel"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static IEnumerable<PostModel> GetRecentPosts(this UmbracoHelper helper, IMasterModel masterModel, int count)
        {
            var listNode = masterModel.RootBlogNode.Children
               .FirstOrDefault(x => x.DocumentTypeAlias.InvariantEquals("ArticulateArchive"));
            if (listNode == null)
            {
                throw new InvalidOperationException("An ArticulateArchive document must exist under the root Articulate document");
            }

            var pager = new PagerModel(count, 0, 1);

            var listItems = helper.GetPostsSortedByPublishedDate(listNode.Id, pager);

            var rootPageModel = new ListModel(listNode, listItems, pager);
            return rootPageModel.Children<PostModel>();
        }
예제 #10
0
 public AuthorModel(IPublishedContent content, IEnumerable <IPublishedContent> listItems, PagerModel pager, int postCount)
     : base(content, listItems, pager)
 {
     PostCount = postCount;
 }
        private ActionResult RenderByTagOrCategory(RenderModel model, int? p, string tagGroup, string baseUrl)
        {
            var tagPage = model.Content as ArticulateVirtualPage;
            if (tagPage == null)
            {
                throw new InvalidOperationException("The RenderModel.Content instance must be of type " + typeof(ArticulateVirtualPage));
            }

            //create a blog model of the main page
            var rootPageModel = new ListModel(model.Content.Parent);

            var contentByTag = Umbraco.GetContentByTag(rootPageModel, tagPage.Name, tagGroup, baseUrl);

            //this is a special case in the event that a tag contains a '.', when this happens we change it to a '-' 
            // when generating the URL. So if the above doesn't return any tags and the tag contains a '-', then we
            // will replace them with '.' and do the lookup again
            if (contentByTag == null && tagPage.Name.Contains("-"))
            {
                contentByTag = Umbraco.GetContentByTag(
                    rootPageModel,
                    tagPage.Name.Replace('-', '.'),
                    tagGroup,
                    baseUrl);
            }

            if (p != null && p.Value == 1)
            {
                return new RedirectToUmbracoPageResult(model.Content, UmbracoContext);
            } 
            
            if (p == null || p.Value <= 0)
            {
                p = 1;
            }

            //TODO: I wonder about the performance of this - when we end up with thousands of blog posts, 
            // this will probably not be so efficient. I wonder if using an XPath lookup for batches of children
            // would work? The children count could be cached. I'd rather not put blog posts under 'month' nodes
            // just for the sake of performance. Hrm.... Examine possibly too.

            var totalPosts = contentByTag == null ? 0 : contentByTag.PostCount;
            var pageSize = rootPageModel.PageSize;
            var totalPages = totalPosts == 0 ? 1 : Convert.ToInt32(Math.Ceiling((double)totalPosts / pageSize));

            //Invalid page, redirect without pages
            if (totalPages < p)
            {
                return new RedirectToUmbracoPageResult(model.Content.Parent, UmbracoContext);
            }

            var pager = new PagerModel(
                pageSize,
                p.Value - 1,
                totalPages,
                totalPages > p ? model.Content.Url.EnsureEndsWith('?') + "p=" + (p + 1) : null,
                p > 2 ? model.Content.Url.EnsureEndsWith('?') + "p=" + (p - 1) : p > 1 ? model.Content.Url : null);

            var listModel = new ListModel(tagPage, contentByTag == null ? Enumerable.Empty<PostModel>() : contentByTag.Posts, pager);

            return View(PathHelper.GetThemeViewPath(listModel, "List"), listModel);
        }
예제 #12
0
 public ListModel(IPublishedContent content, PagerModel pager)
     : base(content)
 {
     if (pager == null) throw new ArgumentNullException("pager");
     _pager = pager;
 }
        /// <summary>
        /// Used to render the search result listing (virtual node)
        /// </summary>
        /// <param name="model"></param>
        /// <param name="term">
        /// The search term
        /// </param>
        /// <param name="provider">
        /// The search provider name (optional)
        /// </param>
        /// <param name="p"></param>
        /// <returns></returns>
        public ActionResult Search(RenderModel model, string term, string provider = null, int? p = null)
        {
            var tagPage = model.Content as ArticulateVirtualPage;
            if (tagPage == null)
            {
                throw new InvalidOperationException("The RenderModel.Content instance must be of type " + typeof(ArticulateVirtualPage));
            }

            //create a blog model of the main page
            var rootPageModel = new ListModel(model.Content.Parent);

            if (term == null)
            {
                //nothing to search, just render the view
                var emptyList = new ListModel(tagPage, Enumerable.Empty<IPublishedContent>(), new PagerModel(rootPageModel.PageSize, 0, 0));
                return View(PathHelper.GetThemeViewPath(emptyList, "List"), emptyList);
            }

            if (p != null && p.Value == 1)
            {
                return new RedirectToUmbracoPageResult(model.Content, UmbracoContext);
            }

            if (p == null || p.Value <= 0)
            {
                p = 1;
            }

            var searchResult = _articulateSearchPlugin.Search(term, provider, rootPageModel.BlogArchiveNode.Id);

            //TODO: I wonder about the performance of this - when we end up with thousands of blog posts,
            // this will probably not be so efficient. I wonder if using an XPath lookup for batches of children
            // would work? The children count could be cached. I'd rather not put blog posts under 'month' nodes
            // just for the sake of performance. Hrm.... Examine possibly too.

            var totalPosts = searchResult.Count();
            var pageSize = rootPageModel.PageSize;

            var totalPages = totalPosts == 0 ? 1 : Convert.ToInt32(Math.Ceiling((double)totalPosts / pageSize));

            //Invalid page, redirect without pages
            if (totalPages < p)
            {
                return new RedirectToUmbracoPageResult(model.Content.Parent, UmbracoContext);
            }

            var pager = new PagerModel(
                pageSize,
                p.Value - 1,
                totalPages,
                totalPages > p ? model.Content.Url.EnsureEndsWith('?') + "term=" + term + "&p=" + (p + 1) : null,
                p > 2 ? model.Content.Url.EnsureEndsWith('?') + "term=" + term + "&p=" + (p - 1) : p > 1 ? model.Content.Url.EnsureEndsWith('?') + "term=" + term : null);

            var listModel = new ListModel(tagPage, searchResult, pager);

            return View(PathHelper.GetThemeViewPath(listModel, "List"), listModel);
        }
        /// <summary>
        /// Used to render the search result listing (virtual node)
        /// </summary>
        /// <param name="model"></param>
        /// <param name="term">
        /// The search term
        /// </param>
        /// <param name="provider">
        /// The search provider name (optional)
        /// </param>
        /// <param name="p"></param>
        /// <returns></returns>
        public ActionResult Search(RenderModel model, string term, string provider = null, int? p = null)
        {
            var tagPage = model.Content as ArticulateVirtualPage;
            if (tagPage == null)
            {
                throw new InvalidOperationException("The RenderModel.Content instance must be of type " + typeof(ArticulateVirtualPage));
            }

            //create a blog model of the main page
            var rootPageModel = new MasterModel(model.Content.Parent);

            if (term == null)
            {
                //nothing to search, just render the view
                var emptyList = new ListModel(tagPage, Enumerable.Empty<IPublishedContent>(), new PagerModel(rootPageModel.PageSize, 0, 0));
                return View(PathHelper.GetThemeViewPath(emptyList, "List"), emptyList);
            }

            if (p != null && p.Value == 1)
            {
                return new RedirectToUmbracoPageResult(model.Content, UmbracoContext);
            }

            if (p == null || p.Value <= 0)
            {
                p = 1;
            }

            int totalPosts;
            var searchResult = ArticulateSearcher.Search(term, provider, rootPageModel.BlogArchiveNode.Id, rootPageModel.PageSize, p.Value - 1, out totalPosts);

            var pageSize = rootPageModel.PageSize;

            var totalPages = totalPosts == 0 ? 1 : Convert.ToInt32(Math.Ceiling((double)totalPosts / pageSize));

            //Invalid page, redirect without pages
            if (totalPages < p)
            {
                return new RedirectToUmbracoPageResult(model.Content.Parent, UmbracoContext);
            }

            var pager = new PagerModel(
                pageSize,
                p.Value - 1,
                totalPages,
                totalPages > p ? model.Content.Url.EnsureEndsWith('?') + "term=" + term + "&p=" + (p + 1) : null,
                p > 2 ? model.Content.Url.EnsureEndsWith('?') + "term=" + term + "&p=" + (p - 1) : p > 1 ? model.Content.Url.EnsureEndsWith('?') + "term=" + term : null);

            var listModel = new ListModel(tagPage, searchResult, pager);

            return View(PathHelper.GetThemeViewPath(listModel, "List"), listModel);
        }