diff --git a/src/butterfly/generator/HtmlGenerator.hx b/src/butterfly/generator/HtmlGenerator.hx index 13b55e9..5192fb8 100644 --- a/src/butterfly/generator/HtmlGenerator.hx +++ b/src/butterfly/generator/HtmlGenerator.hx @@ -12,161 +12,176 @@ import butterfly.html.HtmlTag; class HtmlGenerator { - public static inline var CONTENT_PLACEHOLDER:String = ''; - - private var layoutHtml:String; - private var posts:Array; - private var pages:Array; - - private static inline var TITLE_PLACEHOLDER:String = ''; - private static inline var POST_DATE_PLACEHOLDER:String = ''; - private static inline var COMMENTS_PLACEHOLDER:String = ''; - - private static inline var DISQUS_HTML_FILE:String = 'templates/disqus.html'; - private static inline var DISQUS_PAGE_URL:String = 'PAGE_URL'; - private static inline var DISQUS_PAGE_IDENTIFIER = 'PAGE_IDENTIFIER'; - - public function new(layoutHtml:String, posts:Array, pages:Array) - { - this.layoutHtml = layoutHtml; - this.posts = posts; - this.pages = pages; - } - - public function generatePageHtml(page:Page, config:ButterflyConfig) : String - { - var html:String = generateCommonHtml(page, config); - var content = generateIntraSiteLinks(page.content); - html = html.replace(CONTENT_PLACEHOLDER, content); - return html; - } - - /** - Generates the HTML for a post, using values from config (like the site URL). - Returns the fully-formed, final HTML (after rendering to Markdown, adding - the HTML with the post's tags, etc.). - */ - public function generatePostHtml(post:Post, config:ButterflyConfig) : String - { - var tagsHtml = ""; - var postDateHtml = ""; - - // substitute in content - if (post.tags.length > 0) { - tagsHtml = "

Tagged with: "; - for (tag in post.tags) { - tagsHtml += '${HtmlGenerator.tagLink(tag)}, '; - } - tagsHtml = tagsHtml.substr(0, tagsHtml.length - 2) + "

"; // trim final ", " + public static inline var CONTENT_PLACEHOLDER:String = ''; + + private var layoutHtml:String; + private var posts:Array; + private var pages:Array; + + private static inline var TITLE_PLACEHOLDER:String = ''; + private static inline var POST_DATE_PLACEHOLDER:String = ''; + private static inline var COMMENTS_PLACEHOLDER:String = ''; + + private static inline var DISQUS_HTML_FILE:String = 'templates/disqus.html'; + private static inline var DISQUS_PAGE_URL:String = 'PAGE_URL'; + private static inline var DISQUS_PAGE_IDENTIFIER = 'PAGE_IDENTIFIER'; + + public function new(layoutHtml:String, posts:Array, pages:Array) + { + this.layoutHtml = layoutHtml; + this.posts = posts; + this.pages = pages; } - var html = generateCommonHtml(post, config); - var content = generateIntraSiteLinks(post.content); - - // Substitute in posted-on date if the tag exists - // If not, lump it into the content text. - postDateHtml = '${post.createdOn.format("%Y-%m-%d")}'; - var postDateTag:HtmlTag = TagFinder.findTag(POST_DATE_PLACEHOLDER, html); - if (postDateTag != null) { - var prefix:String = postDateTag.attribute("prefix"); - var cssClass:String = ${postDateTag.attribute("class")} - postDateHtml = '

${prefix}${postDateHtml}

'; - html = html.replace(postDateTag.html, postDateHtml); - } else { - postDateHtml = '

Posted on ${postDateHtml}

'; - content = '${postDateHtml}\n${content}'; + public function generatePageHtml(page:Page, config:ButterflyConfig) : String + { + var html:String = generateCommonHtml(page, config); + var content = generateIntraSiteLinks(page.content); + html = html.replace(CONTENT_PLACEHOLDER, content); + return html; } - var finalHtml = '${tagsHtml}\n${content}\n'; - finalHtml = html.replace(CONTENT_PLACEHOLDER, finalHtml); - return finalHtml; - } - - // Precondition: posts are sorted in the order we want to list them on the home page. - public function generateTagPageHtml(tag:String, posts:Array):String - { - var count = 0; - var html = "
    "; - for (post in posts) { - if (post.tags.indexOf(tag) > -1) { - html += '
  • ${post.title}
  • '; - count++; - } + /** + Generates the HTML for a post, using values from config (like the site URL). + Returns the fully-formed, final HTML (after rendering to Markdown, adding + the HTML with the post's tags, etc.). + */ + public function generatePostHtml(post:Post, config:ButterflyConfig):String + { + var tagsHtml = ""; + var postDateHtml = ""; + + // substitute in content + if (post.tags.length > 0) + { + tagsHtml = "

    Tagged with: "; + for (tag in post.tags) + { + tagsHtml += '${HtmlGenerator.tagLink(tag)}, '; + } + tagsHtml = tagsHtml.substr(0, tagsHtml.length - 2) + "

    "; // trim final ", " + } + + var html = generateCommonHtml(post, config); + var content = generateIntraSiteLinks(post.content); + + // Substitute in posted-on date if the tag exists + // If not, lump it into the content text. + postDateHtml = '${post.createdOn.format("%Y-%m-%d")}'; + var postDateTag:HtmlTag = TagFinder.findTag(POST_DATE_PLACEHOLDER, html); + if (postDateTag != null) + { + var prefix:String = postDateTag.attribute("prefix"); + var cssClass:String = ${postDateTag.attribute("class")} + postDateHtml = '

    ${prefix}${postDateHtml}

    '; + html = html.replace(postDateTag.html, postDateHtml); + } + else + { + postDateHtml = '

    Posted on ${postDateHtml}

    '; + content = '${postDateHtml}\n${content}'; + } + + var finalHtml = '${tagsHtml}\n${content}\n'; + finalHtml = html.replace(CONTENT_PLACEHOLDER, finalHtml); + return finalHtml; } - html += "
"; - html = '

${count} posts tagged with ${tag}:

\n${html}'; - return this.layoutHtml.replace(CONTENT_PLACEHOLDER, html); - } - - public function generateHomePageHtml() : String - { - var html = "
    "; - for (post in posts) { - html += '
  • ${post.title} (${post.createdOn.format("%Y-%m-%d")})
  • '; + + // Precondition: posts are sorted in the order we want to list them on the home page. + public function generateTagPageHtml(tag:String, posts:Array):String + { + var count = 0; + var html = "
      "; + for (post in posts) + { + if (post.tags.indexOf(tag) > -1) + { + html += '
    • ${post.title}
    • '; + count++; + } + } + html += "
    "; + html = '

    ${count} posts tagged with ${tag}:

    \n${html}'; + return this.layoutHtml.replace(CONTENT_PLACEHOLDER, html); } - html += "
"; - return this.layoutHtml.replace(CONTENT_PLACEHOLDER, html); - } - - public static function tagLink(tag:String):String - { - return '${tag}'; - } - - /** - Generates the HTML for a page, using values from config (like the site URL). - Returns the fully-formed, final HTML (after rendering to Markdown). - */ - private function generateCommonHtml(content:Content, config:ButterflyConfig):String - { - var finalContent = this.layoutHtml; - - // replace with the title, if it exists - finalContent = finalContent.replace(TITLE_PLACEHOLDER, content.title); - - // comments (disqus snippet) - var disqusHtml = getDisqusHtml(content, config); - finalContent = finalContent.replace(COMMENTS_PLACEHOLDER, disqusHtml); - - // prefix the post name to the title tag - finalContent = finalContent.replace("", '<title>${content.title} | '); - return finalContent; - } - - private function getDisqusHtml(content:Content, config:ButterflyConfig):String - { - var template = sys.io.File.getContent(DISQUS_HTML_FILE); - var url = '${config.siteUrl}/${content.url}'; - template = template.replace(DISQUS_PAGE_URL, '"${url}"'); - template = template.replace(DISQUS_PAGE_IDENTIFIER, '"${content.id}"'); - return template; - } - - private function generateIntraSiteLinks(content:String) : String - { - var toReturn = content; - - // Don't bother scanning if there are no links (syntax: [[title]]) - if (toReturn.indexOf("[[") > -1) { - var titlesToUrls:Map<String, String> = new Map<String, String>(); - - for (post in posts) { - titlesToUrls.set(post.title, post.url); - } - for (page in pages) { - titlesToUrls.set(page.title, page.url); - } - - for (title in titlesToUrls.keys()) { - var titlePlaceholder = new EReg('\\[\\[${title}]]', "i"); - if (titlePlaceholder.match(toReturn)) { - var titleLink = '<a href="${titlesToUrls.get(title)}.html">${title}</a>'; - toReturn = titlePlaceholder.replace(toReturn, titleLink); - } else { + + public function generateHomePageHtml() : String + { + var html = "<ul>"; + for (post in posts) + { + html += '<li><a href="${post.url}.html">${post.title}</a> (${post.createdOn.format("%Y-%m-%d")})</li>'; } - } + html += "</ul>"; + return this.layoutHtml.replace(CONTENT_PLACEHOLDER, html); } - return toReturn; - } + public static function tagLink(tag:String):String + { + return '<a href="tag-${tag}.html">${tag}</a>'; + } + + /** + Generates the HTML for a page, using values from config (like the site URL). + Returns the fully-formed, final HTML (after rendering to Markdown). + */ + private function generateCommonHtml(content:Content, config:ButterflyConfig):String + { + var finalContent = this.layoutHtml; + + // replace <butterfly-title /> with the title, if it exists + finalContent = finalContent.replace(TITLE_PLACEHOLDER, content.title); + + // comments (disqus snippet) + var disqusHtml = getDisqusHtml(content, config); + finalContent = finalContent.replace(COMMENTS_PLACEHOLDER, disqusHtml); + + // prefix the post name to the title tag + finalContent = finalContent.replace("<title>", '<title>${content.title} | '); + return finalContent; + } + + private function getDisqusHtml(content:Content, config:ButterflyConfig):String + { + var template = sys.io.File.getContent(DISQUS_HTML_FILE); + var url = '${config.siteUrl}/${content.url}'; + template = template.replace(DISQUS_PAGE_URL, '"${url}"'); + template = template.replace(DISQUS_PAGE_IDENTIFIER, '"${content.id}"'); + return template; + } + + private function generateIntraSiteLinks(content:String) : String + { + var toReturn = content; + + // Don't bother scanning if there are no links (syntax: [[title]]) + if (toReturn.indexOf("[[") > -1) + { + var titlesToUrls:Map<String, String> = new Map<String, String>(); + + for (post in posts) + { + titlesToUrls.set(post.title, post.url); + } + for (page in pages) + { + titlesToUrls.set(page.title, page.url); + } + + for (title in titlesToUrls.keys()) + { + var titlePlaceholder = new EReg('\\[\\[${title}]]', "i"); + if (titlePlaceholder.match(toReturn)) + { + var titleLink = '<a href="${titlesToUrls.get(title)}.html">${title}</a>'; + toReturn = titlePlaceholder.replace(toReturn, titleLink); + } + else + { + } + } + } + + return toReturn; + } } diff --git a/test/butterfly/generator/HtmlGeneratorTest.hx b/test/butterfly/generator/HtmlGeneratorTest.hx index 37c4ad2..7180721 100644 --- a/test/butterfly/generator/HtmlGeneratorTest.hx +++ b/test/butterfly/generator/HtmlGeneratorTest.hx @@ -47,11 +47,11 @@ class HtmlGeneratorTest { var layout = "<butterfly-pages /><h2><butterfly-title /></h2>\n<butterfly-content /><butterfly-tags />"; var gen = Factory.createHtmlGenerator(layout); - var post = new Post(); + var post = new Post(); post.title = "Regex Replacement in Haxe"; - var actual = gen.generatePostHtml(post, new ButterflyConfig()); - Assert.isTrue(actual.indexOf('<h2>${post.title}</h2>') > -1); + var actual = gen.generatePostHtml(post, new ButterflyConfig()); + Assert.isTrue(actual.indexOf('<h2>${post.title}</h2>') > -1); } @Test @@ -60,11 +60,11 @@ class HtmlGeneratorTest { var layout = "<butterfly-pages /><h2><butterfly-title /></h2>\n<butterfly-content /><butterfly-tags />"; var gen = Factory.createHtmlGenerator(layout); - var post = new Post(); + var post = new Post(); post.createdOn = Date.now(); - var actual = gen.generatePostHtml(post, new ButterflyConfig()); - Assert.isTrue(actual.indexOf('Posted on ${post.createdOn.format("%Y-%m-%d")}') > -1); + var actual = gen.generatePostHtml(post, new ButterflyConfig()); + Assert.isTrue(actual.indexOf('Posted on ${post.createdOn.format("%Y-%m-%d")}') > -1); } @Test @@ -73,11 +73,11 @@ class HtmlGeneratorTest var layout = "<butterfly-pages /><h2><butterfly-title /></h2>\n<butterfly-content /><butterfly-tags />" + 'Published <butterfly-post-date class="post-meta" prefix="Crafted on " />'; var gen = Factory.createHtmlGenerator(layout); - var post = new Post(); - post.createdOn = Date.now(); + var post = new Post(); + post.createdOn = Date.now(); - var actual = gen.generatePostHtml(post, new ButterflyConfig()); - Assert.isTrue(actual.indexOf('<p class="post-meta">Crafted on ${post.createdOn.format("%Y-%m-%d")}') > -1); + var actual = gen.generatePostHtml(post, new ButterflyConfig()); + Assert.isTrue(actual.indexOf('<p class="post-meta">Crafted on ${post.createdOn.format("%Y-%m-%d")}') > -1); } @Test @@ -95,13 +95,31 @@ class HtmlGeneratorTest @Test public function generatePostHtmlReplacesCommentTagWithDisqusHtml() { - Assert.isTrue(true); + var post:Post = makePost("Unicorns", "http://unicorns.com"); + post.content = "We love unicorns."; + + var actual = new HtmlGenerator("<butterfly-comments />", [post], []) + .generatePostHtml(post, new ButterflyConfig()); + + // Don't directly read the template, because it contains placeholders + // Instead, look for the word "disqus" + Assert.isTrue(actual.indexOf("disqus") > -1); } @Test - public function GeneratePostHtmlAppendsPostTitleToHtmlTitleTag() + public function generatePostHtmlAppendsPostTitleToHtmlTitleTag() { - Assert.isTrue(true); + var postTitle:String = "Bananas"; + var siteTitle:String = "V R Bananas"; + var post:Post = makePost(postTitle, "http://wearebananas.com"); + post.content = "We really are bananas. And sell bananas."; + + var actual = new HtmlGenerator('<head><title>${siteTitle}', [post], []) + .generatePostHtml(post, new ButterflyConfig()); + + // Don't directly read the template, because it contains placeholders + // Instead, look for the word "disqus" + Assert.isTrue(actual.indexOf('${postTitle} | ${siteTitle}') > -1); } @Test @@ -115,15 +133,13 @@ class HtmlGeneratorTest var content = 'Do not ask [[${page.title}]]; just read this: [[${post.title}]]'; - var generator = new HtmlGenerator("", - [post], [page]); - - var config = new ButterflyConfig(); + var generator = new HtmlGenerator + ("", [post], [page]); var postWithLinks = new Post(); postWithLinks.content = content; - var actual = generator.generatePostHtml(postWithLinks, config); + var actual = generator.generatePostHtml(postWithLinks, new ButterflyConfig()); Assert.isTrue(actual.indexOf(post.url) > -1); Assert.isTrue(actual.indexOf(page.url) > -1); } @@ -131,25 +147,51 @@ class HtmlGeneratorTest @Test public function generatePageHtmlReplacesContentTagWithContent() { - Assert.isTrue(true); + var page = makePage("Blueberry Smoothies", "Blueberry smoothies are very healthy."); + + var generator = new HtmlGenerator + ("

Fake.com


", [], [page]); + + var actual = generator.generatePageHtml(page, new ButterflyConfig()); + Assert.isTrue(actual.indexOf(page.content) > -1); } @Test public function generatePageHtmlReplacesButterflyTitleTagWithTitle() { - Assert.isTrue(true); + var page = makePage("Raspberry Smoothies", "Raspberry smoothies are very healthy."); + + var generator = new HtmlGenerator + ("


", [], [page]); + + var actual = generator.generatePageHtml(page, new ButterflyConfig()); + Assert.isTrue(actual.indexOf('

${page.title}

') > -1); } @Test public function generatePageHtmlReplacesCommentTagWithDisqusHtml() { - Assert.isTrue(true); + var page = makePage("Strawberry Smoothies", "Strawberry smoothies are very healthy."); + + var generator = new HtmlGenerator + ("
", [], [page]); + + var actual = generator.generatePageHtml(page, new ButterflyConfig()); + var divIndex = actual.indexOf("
") + 19; // 19 = length of opening div tag + Assert.isTrue(actual.indexOf("disqus") > divIndex); } @Test - public function GeneratePageHtmlAppendsPostTitleToHtmlTitleTag() + public function generatePageHtmlAppendsPageTitleToHtmlTitleTag() { - Assert.isTrue(true); + var pageTitle:String = "About"; + var siteTitle:String = "Monkeys R Us"; + var page:Page = makePage(pageTitle, "We love monkeys. And bananas."); + + var actual = new HtmlGenerator('${siteTitle}', [], [page]) + .generatePageHtml(page, new ButterflyConfig()); + + Assert.isTrue(actual.indexOf('${pageTitle} | ${siteTitle}') > -1); } @Test @@ -240,4 +282,12 @@ class HtmlGeneratorTest post.url = url; return post; } + + private function makePage(title:String, content:String):Page + { + var page = new Page(); + page.title = title; + page.content = content; + return page; + } }