#region using using System; using System.Web; using System.Web.UI; using BlogEngine.Core.Web.Controls; using BlogEngine.Core; using System.Text.RegularExpressions; using System.Collections.Generic; #endregion /// /// Breaks a post where [more] is found in the body and adds a link to full post. /// [Extension("Breaks a post where [more] is found in the body and adds a link to full post", "1.4", "BlogEngine.NET", 1010)] public class BreakPost { /// /// Hooks up an event handler to the Post.Serving event. /// static BreakPost() { Post.Serving += new EventHandler(Post_Serving); } /// /// Handles the Post.Serving event to take care of the [more] keyword. /// private static void Post_Serving(object sender, ServingEventArgs e) { if (!e.Body.Contains("[more]")) return; if (e.Location == ServingLocation.PostList) { AddMoreLink(sender, e); } else if (e.Location == ServingLocation.SinglePost) { PrepareFullPost(e); } else if (e.Location == ServingLocation.Feed) { e.Body = e.Body.Replace("[more]", string.Empty); } } private static Regex openingTagRegex = new Regex(@"<([A-Z][A-Z0-9]*?)\b[^>/]*>", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static Regex closedTagRegex = new Regex(@"]*>", RegexOptions.IgnoreCase | RegexOptions.Compiled); /// /// Replaces the [more] string with a hyperlink to the full post. /// private static void AddMoreLink(object sender, ServingEventArgs e) { Post post = (Post)sender; int index = e.Body.IndexOf("[more]"); string link = "" + Resources.labels.more + "..."; string NewBody = e.Body.Substring(0, index); // Need to close any open HTML tags in NewBody where the matching close tags have been truncated. string closingTagsToAppend = string.Empty; MatchCollection openingTagsCollection = openingTagRegex.Matches(NewBody); if (openingTagsCollection.Count > 0) { // Copy the opening tags in MatchCollection to a generic list. List openingTags = new List(); foreach (Match openTag in openingTagsCollection) { if (openTag.Groups.Count == 2) { openingTags.Add(openTag.Groups[1].Value); } } MatchCollection closingTagsCollection = closedTagRegex.Matches(NewBody); // Iterate through closed tags and remove the first matching open tag from the openingTags list. foreach (Match closedTag in closingTagsCollection) { if (closedTag.Groups.Count == 2) { int indexToRemove = openingTags.FindIndex(delegate(string openTag) { return openTag.Equals(closedTag.Groups[1].Value, StringComparison.InvariantCultureIgnoreCase); }); if (indexToRemove != -1) openingTags.RemoveAt(indexToRemove); } } // A closing tag needs to be created for any remaining tags in the openingTags list. if (openingTags.Count > 0) { // Reverse the order of the tags so tags opened later are closed first. openingTags.Reverse(); closingTagsToAppend = ""; } } e.Body = NewBody + link + closingTagsToAppend; } /// /// Replaces the [more] string on the full post page. /// private static void PrepareFullPost(ServingEventArgs e) { HttpRequest request = HttpContext.Current.Request; if (request.UrlReferrer == null || request.UrlReferrer.Host != request.Url.Host) { e.Body = e.Body.Replace("[more]", string.Empty); } else { e.Body = e.Body.Replace("[more]", ""); } } }