private void PopulateSearchByDate(HtmlContext searchPage, FinaliseContext context) { var searchByDate = context.MarkupContexts.OrderByDescending(c => c.PostedDate).ToList(); var currentPeriod = searchByDate[0].PostedDate.ToString("MMMM yyyy"); var lastPeriod = currentPeriod; var sb = new StringBuilder($"<h1>{currentPeriod}</h1>"); foreach (var article in searchByDate) { Console.WriteLine($"\tInserting search entry for: {article.Title}"); currentPeriod = article.PostedDate.ToString("MMMM yyyy"); if (currentPeriod != lastPeriod) { lastPeriod = currentPeriod; sb.Append($"<h1>{currentPeriod}</h1>"); } sb.Append(GetSearchCard( article.Image.Url, article.Image.Credit, article.Image.Provider, article.Title, article.Slug, article.GetPostedDateAsString(), article.Html.Url.RelativeUrl )); } searchPage.Content = searchPage.Content.Replace("$(search-by-post-date)", sb.ToString()); }
public override void Invoke(FinaliseContext context) { Console.WriteLine($"Building article navigations buttons"); var articleMax = context.MarkupContexts.Count - 1; var markups = context.MarkupContexts.OrderBy(a => a.PostedDate).ToList(); for (var i = 0; i <= articleMax; i++) { var previousDisabled = i == 0 ? "disabled" : ""; var previousPath = i == 0 ? "#" : markups[i - 1].Html.Url.RelativeUrl; var nextDisabled = i == articleMax ? "disabled" : ""; var nextPath = i == articleMax ? "#" : markups[i + 1].Html.Url.RelativeUrl; // Markups.Html context contains all the information we need to implement navigation buttons // However this context is read-only during finalise processing. // Instead we have to look up the Html context for the same file. context.HtmlContexts[markups[i].Html.Url.RelativeUrl].Content = markups[i].Html.Content .Replace("$(disable-previous-article-navigation)", previousDisabled) .Replace("$(previous-article-path)", previousPath) .Replace("$(disable-next-article-navigation)", nextDisabled) .Replace("$(next-article-path)", nextPath) ; } }
public override void Invoke(FinaliseContext context) { Console.WriteLine("Generating article search page:"); var searchPage = context.HtmlContexts[_searchUrl]; PopulateSearchByDate(searchPage, context); PopulateSearchByTag(searchPage, context); }
private void PopulateSearchByTag(HtmlContext searchPage, FinaliseContext context) { var searchTable = new StringBuilder(); var searchList = new StringBuilder(); var searchByTag = from article in context.MarkupContexts from tag in article.Tags group article by new { tag.Value, tag.NakedValue } into articleTags orderby articleTags.Key.Value select new { Tag = articleTags.Key.Value, TagId = articleTags.Key.NakedValue, Articles = articleTags.ToList(), ArticlesCount = articleTags.Sum(a => 1) } ; searchTable.Append("<div class=\"list-group\" style=\"max-width: 600px;\">"); // To avoid iterating over the collection twice, we build the search table and the search list together. // The search table contains one row per tag and links to the various sections of the search list. // The search list appears below the search table and has tag per section. Each section contains a series // of cards linking to the various articles with that tag. Each article can appear in multiple sections. foreach (var tag in searchByTag) { Console.WriteLine($"\tInserting search entry for tag: {tag.Tag}"); searchTable.Append(GetSearchTableRow(tag.TagId, tag.Tag, tag.ArticlesCount)); searchList.Append($"<h3 id=\"{tag.TagId}\"><code>{tag.Tag}</code></h3>"); foreach (var article in tag.Articles) { searchList.Append(GetSearchCard( article.Image.Url, article.Image.Credit, article.Image.Provider, article.Title, article.Slug, article.GetPostedDateAsString(), article.Html.Url.RelativeUrl )); } } searchTable.Append("</div><hr>\n"); searchTable.Append(searchList.ToString()); searchPage.Content = searchPage.Content.Replace("$(search-by-tag)", searchTable.ToString()); }
public override void Invoke(FinaliseContext context) { Console.WriteLine("Generating sitemaps page:"); var sb = new StringBuilder(); // Every .html page is added to the sitemaps file. foreach (var html in context.HtmlContexts.Values) { if (html.Path.EndsWith(".template.html")) { continue; } var location = $"https://david-rushton.dev{html.Url}"; var lastModified = ExtractLastModified(html.Content); Console.WriteLine($"\tInserting entry: {html.Url}"); sb.AppendLine(GetPageEntry(location, lastModified)); } // Write sitemaps to file system WriteSitemaps(context.ScaffoldContext.SiteRoot, sb.ToString()); string ExtractLastModified(string htmlContent) { var htmlDoc = new HtmlDocument(); htmlDoc.LoadHtml(htmlContent); return(htmlDoc.DocumentNode .SelectSingleNode("/html/head/meta[@name = \"date\"]") .Attributes["content"].Value ?? DateTime.Now.ToString("yyy-MM-dd") ); } void WriteSitemaps(string path, string urls) { var content = GetSitemapsTemplate(urls); var sitemapsPath = Path.Join(path, "sitemaps.xml"); File.WriteAllText(sitemapsPath, content); } }
public override void Invoke(FinaliseContext context) { var index = context.HtmlContexts["/index.html"]; var articles = context.MarkupContexts .OrderByDescending(a => a.PostedDate) .Take(5) .Select((a, i) => new { a.Title, a.Author, a.PostedDate, a.Slug, Tags = a.GetDelimitedTags(), IsNew = a.AgeInDays <= context.ScaffoldContext.NewBadgeCutoffInDays, ImagePath = a.Image.Url, HtmlUrl = a.Html.Url, Index = i.ToString() }) .ToList() ; Console.WriteLine($"Generating index page: {index.Url}"); index.Content = index.Content .Replace("$(last-updated)", DateTime.Now.ToString("yyyy-MM-dd")) .Replace("$(version-number)", context.ScaffoldContext.VersionNumber) ; foreach (var article in articles) { Console.WriteLine($"\tInserting article preview #{article.Index}: {article.Title}"); index.Content = index.Content .Replace($"$(article-title-{article.Index})", article.Title) .Replace($"$(article-slug-{article.Index})", article.Slug) .Replace($"$(article-tags-{article.Index})", article.Tags) .Replace($"$(article-image-{article.Index})", article.ImagePath) .Replace($"$(article-path-{article.Index})", article.HtmlUrl.RelativeUrl) .Replace($"$(article-badge-{article.Index})", GetBadge(article.IsNew)) ; } }
public abstract void Invoke(FinaliseContext context);