Package org.moxie

Source Code of org.moxie.Docs

/*
* Copyright 2012 James Moger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.moxie;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;

import org.eclipse.mylyn.wikitext.confluence.core.ConfluenceLanguage;
import org.eclipse.mylyn.wikitext.core.parser.MarkupParser;
import org.eclipse.mylyn.wikitext.core.parser.builder.HtmlDocumentBuilder;
import org.eclipse.mylyn.wikitext.core.parser.markup.MarkupLanguage;
import org.eclipse.mylyn.wikitext.mediawiki.core.MediaWikiLanguage;
import org.eclipse.mylyn.wikitext.textile.core.TextileLanguage;
import org.eclipse.mylyn.wikitext.tracwiki.core.TracWikiLanguage;
import org.eclipse.mylyn.wikitext.twiki.core.TWikiLanguage;
import org.moxie.maxml.Maxml;
import org.moxie.maxml.MaxmlException;
import org.moxie.maxml.MaxmlMap;
import org.moxie.utils.FileUtils;
import org.moxie.utils.MarkdownUtils;
import org.moxie.utils.StringUtils;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.TemplateException;


/**
* Builds a web site or deployment documentation from Markdown source files.
*
* @author James Moger
*
*/
public class Docs {

  private static PrintStream out = System.out;
 
  public static void execute(Build build, Doc doc, boolean verbose) {   

    List<DocElement> revisedElements = new ArrayList<DocElement>();
   
    // prepare report links
    for (DocElement element : doc.structure.elements) {
      if (element instanceof DocReport) {
        // switch to menu
        DocMenu reportMenu = new DocMenu();
       
        // project report
        DocPage projectReport = reportMenu.createPage();
        projectReport.setName("project data");
        projectReport.setContent(new ProjectReport().report(build));
        projectReport.setSrc("moxie-project.html");
       
        // dependency report
        DocPage depReport = reportMenu.createPage();
        depReport.setName("dependencies");
        depReport.setContent(new DependencyReport().report(build));
        depReport.setSrc("moxie-dependencies.html");

        File testOutput = new File(build.getConfig().getReportsTargetDirectory(), "tests");
        File coverageOutput = new File(build.getConfig().getReportsTargetDirectory(), "coverage");
       
        boolean hasTests = testOutput.exists();
        boolean hasCoverage = coverageOutput.exists();
       
        if (hasTests || hasCoverage) {
          reportMenu.createDivider();

          if (hasTests) {
            // test report
            try {
              FileUtils.copy(new File(doc.outputDirectory, "tests"), testOutput);
            } catch (IOException e) {
              build.getConsole().error(e, "failed to copy test report");
            }
            DocPage testReport = reportMenu.createPage();
            testReport.setName("unit tests");
            testReport.setContent(iframe("tests/index.html"));
            testReport.setSrc("moxie-tests.html");
          }

          if (hasCoverage) {
            // code coverage report
            try {
              FileUtils.copy(new File(doc.outputDirectory, "coverage"), coverageOutput);
            } catch (IOException e) {
              build.getConsole().error(e, "failed to copy coverage report");
            }
            DocPage coverageReport = reportMenu.createPage();
            coverageReport.setName("code coverage");
            coverageReport.setContent(iframe("coverage/index.html"));
            coverageReport.setSrc("moxie-coverage.html");
          }
        }
       
        // add reports menu
        revisedElements.add(reportMenu);
      } else {
        // do not alter
        revisedElements.add(element);
      }
    }
   
    doc.structure.elements = revisedElements;
   
    if (verbose) {
      doc.describe(build.getConsole());
    }
   
    if (verbose) {
      build.getConsole().separator();
    }
   
    generatePages(build, doc, verbose);
  }
 
  private static String iframe(String src) {
    return MessageFormat.format("<iframe src=\"{0}\" style=\"border:1px solid #ccc;\" width=\"100%\" height=\"90%\"></iframe>", src);
  }

  private static void generatePages(Build build, Doc doc, boolean verbose) {
    String projectName = build.getPom().name;
    if (StringUtils.isEmpty(projectName) && !StringUtils.isEmpty(doc.name)) {
      projectName = doc.name;
    }
    List<DocElement> allElements = new ArrayList<DocElement>();
    for (DocElement element : doc.structure.elements) {
      allElements.add(element);
      if (element instanceof DocMenu) {
        for (DocElement subElement : ((DocMenu) element).elements) {
          if (subElement instanceof DocMenu) {
            // add all submenu elements
            allElements.addAll(((DocMenu) subElement).elements);
          } else {
            allElements.add(subElement);
          }
        }
      }
    }

    String header = generateHeader(projectName, build.getConfig().getProjectConfig(), doc);
    String footer = generateFooter(doc);

    if (!doc.structure.elements.isEmpty()) {
      build.getConsole().log("Generating Structured Documentation from source files... ");
    }

    // read references
    if (doc.references == null) {
      doc.references = new References();     
    } else {
      String content = FileUtils.readContent(new File(doc.sourceDirectory, doc.references.src), "\n");
      doc.references.content = "\n\n" + content;
    }
   
    for (DocElement element : allElements) {
      if (!(element instanceof DocPage)) {
        // nothing to generate
        continue;
      }
      DocPage page = (DocPage) element;
      try {
        String fileName = getHref(page);
        if (StringUtils.isEmpty(page.src)) {
          // template page
          build.getConsole().log(1, "{0} => {1}", page.templates.get(0).src, fileName);
        } else {
          // markdown page
          build.getConsole().log(1, "{0} => {1}", page.src, fileName);
        }
        String content;
        List<Section> sections = new ArrayList<Section>();
        String pager = "";

        if (page.content != null) {
          // generated content
          content = page.content;
         
          processTemplates(doc, page);
         
          for (Substitute sub : doc.substitutions) {
            if (page.processSubstitutions || sub.isTemplate) {
              content = content.replace(sub.token, sub.value.toString());
            }
          }
          for (Regex regex : doc.regexes) {
            content = content.replaceAll(regex.searchPattern, regex.replacePattern);
          }
        } else if (page.src.endsWith(".html") || page.src.endsWith(".htm")) {
          // static html content
          content = FileUtils.readContent(new File(doc.sourceDirectory, page.src), "\n");
        } else {
          // begin markdown
          String markdownContent = FileUtils.readContent(new File(doc.sourceDirectory, page.src), "\n");
         
          // append references, if specified
          if (!StringUtils.isEmpty(doc.references.content)) {
            markdownContent += doc.references.content;
          }

          Map<String, String> nomarkdownMap = new HashMap<String, String>();

          // extract sections marked as no-markdown
          int nmd = 0;
          for (NoMarkdown nomarkdown : doc.nomarkdowns) {
            List<String> lines = Arrays.asList(markdownContent.split("\n"));
            StringBuilder strippedContent = new StringBuilder();
            for (int i = 0; i < lines.size(); i++) {
              String line = lines.get(i);

              if (line.trim().startsWith(nomarkdown.startToken)) {
                // found start token, look for end token
                int beginCode = i + 1;
                int endCode = beginCode;
                for (int j = beginCode; j < lines.size(); j++) {
                  String endLine = lines.get(j);
                  if (endLine.trim().startsWith(nomarkdown.endToken)) {
                    endCode = j;
                    break;
                  }
                }

                if (endCode > beginCode) {
                  // append a placeholder for extracted content
                  String nomarkdownKey = "%NOMARKDOWN" + nmd + "%";
                  strippedContent.append(nomarkdownKey).append( '\n');
                  nmd++;

                  // build the hunk from lines
                  StringBuilder sb = new StringBuilder();
                  for (String nl : lines.subList(beginCode, endCode)) {
                    sb.append(nl).append('\n');
                  }
                  String hunk = sb.toString();

                  if (nomarkdown instanceof ExcludeText) {
                    // exclude this hunk from the output html
                    nomarkdownMap.put(nomarkdownKey, "");
                  } else if (nomarkdown instanceof WikiText) {
                    // convert this hunk to html from a wiki format
                    StringWriter writer = new StringWriter();

                    HtmlDocumentBuilder builder = new HtmlDocumentBuilder(writer);
                    // avoid the <html> and <body> tags
                    builder.setEmitAsDocument(false);
                   
                    WikiText wikitext = (WikiText) nomarkdown;
                    MarkupLanguage lang;
                    switch (wikitext.syntax){
                    case TWIKI:
                      lang = new TWikiLanguage();
                      break;
                    case TEXTILE:
                      lang = new TextileLanguage();
                      break;
                    case TRACWIKI:
                      lang = new TracWikiLanguage();
                      break;
                    case MEDIAWIKI:
                      lang = new MediaWikiLanguage();
                      break;
                    case CONFLUENCE:
                      lang = new ConfluenceLanguage();
                      break;
                    default:
                      throw new MoxieException("Unrecognized wiki syntax!");
                    }

                    MarkupParser parser = new MarkupParser(lang);
                    parser.setBuilder(builder);
                    parser.parse(hunk);

                    String htmlContent = writer.toString();

                    nomarkdownMap.put(nomarkdownKey, htmlContent);
                  } else if (nomarkdown.prettify) {
                    //
                    // Syntax highlighting
                    //
                    StringBuilder ppclass = new StringBuilder();
                    ppclass.append("prettyprint");
                    if (nomarkdown.linenums) {
                      ppclass.append(" linenums");
                    }
                    if (!StringUtils.isEmpty(nomarkdown.lang)) {
                      ppclass.append(" ");
                      ppclass.append(nomarkdown.lang);
                    }
                    StringBuilder code = new StringBuilder();
                    code.append(MessageFormat.format("<pre class=''{0}''>\n", ppclass.toString()));
                    code.append(StringUtils.escapeForHtml(hunk, false));
                    code.append("</pre>");
                    nomarkdownMap.put(nomarkdownKey, code.toString());
                  } else if (nomarkdown.escape) {
                    //
                    // escape the hunk, optionally wrap with pre
                    //
                    StringBuilder code = new StringBuilder();
                    if (nomarkdown.pre) {
                      code.append("<pre>")
                    }
                    String val = StringUtils.escapeForHtml(hunk, false);
                    if (!nomarkdown.pre) {
                      val = StringUtils.breakLinesForHtml(val);
                    }
                    code.append(val);
                    if (nomarkdown.pre) {
                      code.append("</pre>")
                    }
                    nomarkdownMap.put(nomarkdownKey, code.toString());
                  } else {
                    //
                    // leave the hunk as-is
                    //
                    nomarkdownMap.put(nomarkdownKey, hunk);
                  }

                  // advance the i counter to endCode so we do not
                  // include the lines within the hunk
                  i = endCode;
                } else {
                  // could not find closing token
                  strippedContent.append(line);
                  strippedContent.append('\n');
                }
              } else {
                // regular line
                strippedContent.append(line);
                strippedContent.append('\n');
              }
            }

            // replace markdown content with the stripped content
            markdownContent = strippedContent.toString();
          }

          // prev/next pager links
          if (page.showPager) {
            String prev;
            if (page.prevPage == null) {
              prev = "";
            } else {
              prev = MessageFormat.format("<li class=\"previous\"><a href=\"{0}\">&larr; {1}</a></li>", getHref(page.prevPage), page.prevPage.name);
            }
            String next;
            if (page.nextPage == null) {
              next = "";
            } else {
              next = MessageFormat.format("<li class=\"next\"><a href=\"{0}\">{1} &rarr;</a></li>", getHref(page.nextPage), page.nextPage.name);
            }
            String divClass = "";
            String pagerClass = "";
            if (!StringUtils.isEmpty(page.pagerLayout)) {
              if ("right".equals(page.pagerLayout)) {
                divClass = "class=\"pull-right\"";
                pagerClass = "class=\"pager\"";
              } else if ("justified".equals(page.pagerLayout)) {
                pagerClass = "class=\"pager\"";
              }
            }
            pager = MessageFormat.format("<div {0}><ul {1}>{2} {3}</ul></div>", divClass, pagerClass, prev, next);
          }

          // header links
          AtomicInteger sectionCounter = new AtomicInteger();
          StringBuilder sb = new StringBuilder();
          for (String line : Arrays.asList(markdownContent.split("\n"))) {
            if (line.length() == 0) {
              sb.append('\n');
              continue;
            }
            if (line.charAt(0) == '#') {
              String section = line.substring(0, line.indexOf(' '));
              String name = line.substring(line.indexOf(' ') + 1) .trim();
              if (name.endsWith(section)) {
                name = name.substring(0, name.indexOf(section)) .trim();
              }
              String h = "h" + section.length();
              String id = "H" + sectionCounter.addAndGet(1);
              sections.add(new Section(id, name));
              if (page.showHeaderLinks) {
                sb.append(MessageFormat.format("<{0} class=\"section\" id=''{2}''><a href=\"#{2}\" class=\"sectionlink\"><i class=\"icon-share-alt\"> </i></a>{1}</{0}>\n", h, name, id));
              } else {
                sb.append(MessageFormat.format("<{0} id=''{2}''>{1}</{0}>\n", h, name, id));
              }
            } else {
              // preserve line
              sb.append(line);
              sb.append('\n');
            }
          }

          // replace markdown content with the navigable content
          markdownContent = sb.toString();

          // transform markdown to html
          content = transformMarkdown(markdownContent.toString());

          // reinsert nomarkdown chunks
          for (Map.Entry<String, String> nomarkdown : nomarkdownMap .entrySet()) {
            content = content.replaceFirst(nomarkdown.getKey(), Matcher.quoteReplacement(nomarkdown.getValue()));
          }
         
          // templates
          processTemplates(doc, page);

          for (Substitute sub : doc.substitutions) {
            if (page.processSubstitutions || sub.isTemplate) {
              content = content.replace(sub.token, sub.value.toString());
            }
          }
         
          for (Regex regex : doc.regexes) {
            content = content.replaceAll(regex.searchPattern, regex.replacePattern);
          }
          for (Prop prop : doc.props) {
            String loadedContent = generatePropertiesContent(prop);
            content = content.replace(prop.token, loadedContent);
          }
          for (Load load : doc.loads) {
            String loadedContent = FileUtils.readContent(new File( load.file), "\n");
            loadedContent = StringUtils.escapeForHtml(loadedContent, false);
            loadedContent = StringUtils.breakLinesForHtml(loadedContent);
            content = content.replace(load.token, loadedContent);
          }
          // end markdown
        }
       
        // Create the topbar links for this page
        String links = createLinks(page, doc.structure.elements);

        if (!StringUtils.isEmpty(doc.googlePlusId)) {
          links += "<li><a href='https://plus.google.com/"
              + doc.googlePlusId
              + "?prsrc=3' class='gpluspage'><img src='https://ssl.gstatic.com/images/icons/gplus-16.png' width='16' height='16 style='order: 0;'/></a></li>";
        }

        // add Google+1 link
        if (doc.googlePlusOne && !StringUtils.isEmpty(build.getPom().url)) {
          links += "<li><div class='gplusone'><g:plusone size='small' href='"
              + build.getPom().url + "'></g:plusone></div></li>";
        }
        String linksHtml = readResource(doc, "links.html");
        linksHtml = linksHtml.replace("%PROJECTNAME%", projectName);
        linksHtml = linksHtml.replace("%PROJECTLINKS%", links);
        if (doc.logo != null) {
          linksHtml = linksHtml.replace("%PROJECTLOGO%", doc.logo.getName());
        }
        links = linksHtml;

        // write final document
        OutputStreamWriter writer = new OutputStreamWriter(
            new FileOutputStream(new File(doc.outputDirectory,
                fileName)), Charset.forName("UTF-8"));
        writer.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n<html>\n<head>\n");
        writer.write(header);

        writer.append("\n<script src=\"./prettify/prettify.js\"></script>");

        writer.append("\n<script src=\"./bootstrap/js/jquery.js\"></script>");
        writer.append("\n<script src=\"./bootstrap/js/bootstrap.min.js\"></script>");
       
        writer.write("\n</head>");
        writer.write("\n<body onload='prettyPrint()'>");
        writer.write(links);
        if (page.showToc) {
          if (page.isFluidLayout) {
            writer.write("\n<div class='container-fluid'>");
            writer.write("\n<div class='row-fluid'>");
          } else {
            writer.write("\n<div class='container'>");
            writer.write("\n<div class='row'>");
          }
          writer.write("\n<!-- sidebar -->");
          writer.write("\n<div class='span3'>");
          writer.write("\n<div class='well sidebar-nav'>");
          writer.write("\n<ul class='nav nav-list'>");
          writer.write("\n<li class='nav-header'>Table of Contents</li>");
          for (Section section : sections) {
            writer.write(MessageFormat.format("\n<li><a href=''#{0}''>{1}</a></li>\n", section.id, section.name))
          }
          writer.write("\n</ul>");
          writer.write("\n</div>");
          writer.write("\n</div>");
          writer.write("\n<div class='span9'>");
        } else {
          if (page.isFluidLayout) {
            writer.write("\n<div class='container-fluid'>");
          } else {
            writer.write("\n<div class='container'>");
          }
        }
       
        boolean manualPagerPlacement = false;
        // replace %PAGER%
        if (content.contains("%PAGER%")) {
          manualPagerPlacement = true;
          content = content.replace("%PAGER%", pager);
        }
       
        if (!manualPagerPlacement) {
          if (!StringUtils.isEmpty(page.pagerPlacement) && page.pagerPlacement.contains("top")) {
            // top pager
            writer.write(pager);
          }
        }
       
        writer.write("\n<!-- Begin Markdown -->\n");
        writer.write(content);
        writer.write("\n<!-- End Markdown -->\n");
               
        if (!manualPagerPlacement) {
          if (!StringUtils.isEmpty(page.pagerPlacement) && page.pagerPlacement.contains("bottom")) {
            // bottom pager
            writer.write(pager);
          }
        }

        writer.write("<footer class=\"footer\">");
        writer.write(footer);
        writer.write("\n</footer>\n</div>");
        if (page.showToc) {
          writer.write("\n</div></div>");
        }
       
        if (!StringUtils.isEmpty(doc.googleAnalyticsId)) {
          String analytics = readResource(doc, "analytics.html");
          analytics = analytics.replace("%ANALYTICSID%", doc.googleAnalyticsId);
          writer.append('\n');
          writer.append(analytics);
          writer.append('\n');
        }

        writer.write("\n</body>");
        writer.write("\n</html>");
        writer.close();
      } catch (Throwable t) {
        build.getConsole().error(t, "Failed to transform " + page.src);
      }
    }
   
    // process pages which are not part of the normal structure
    if (!doc.freeformPages.isEmpty()) {
      build.getConsole().log("Generating content from Freemarker templates...");
      for (DocPage page : doc.freeformPages) {
        try {
          // template pages
          String fileName = getHref(page);
          build.getConsole().log(1, "{0} => {1}", page.templates.get(0).src, fileName);

          String content = page.content;
          processTemplates(doc, page);
          for (Substitute sub : doc.substitutions) {
            if (page.processSubstitutions || sub.isTemplate) {
              content = content.replace(sub.token, sub.value.toString());
            }
          }
          for (Regex regex : doc.regexes) {
            content = content.replaceAll(regex.searchPattern, regex.replacePattern);
          }

          File output = new File(doc.outputDirectory, page.as);
          FileUtils.writeContent(output, content);
        } catch (Throwable t) {
          build.getConsole().error(t, "Failed to transform " + page.src);
        }
      }
    }
  }

  static String extractResource(Doc doc, String folder, String resource) {
    String content = "";
    try {
      InputStream is = doc.getClass().getResourceAsStream("/" + resource);
      ByteArrayOutputStream os = new ByteArrayOutputStream();
      byte[] buffer = new byte[32767];
      int len = 0;
      while ((len = is.read(buffer)) > -1) {
        os.write(buffer, 0, len);
      }
      content = os.toString("UTF-8");
      os.close();
      is.close();
      File outputFile;
      if (StringUtils.isEmpty(folder)) {
        outputFile = new File(doc.outputDirectory, resource);
      } else {
        outputFile = new File(new File(doc.outputDirectory, folder),
            resource);
      }
      FileUtils.writeContent(outputFile, content);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return content;
  }

  static String readResource(Doc doc, String resource) {
    String content = "";
    try {
      InputStream is = doc.getClass().getResourceAsStream("/" + resource);
      ByteArrayOutputStream os = new ByteArrayOutputStream();
      byte[] buffer = new byte[32767];
      int len = 0;
      while ((len = is.read(buffer)) > -1) {
        os.write(buffer, 0, len);
      }
      content = os.toString("UTF-8");
      os.close();
      is.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return content;
  }

  static String readContent(File file) {
    String content = "";
    if (file.exists()) {
      content = FileUtils.readContent(file, "\n");
    }
    return content;
  }

  private static String createLinks(DocElement currentElement, List<DocElement> elements) {
    String linkPattern = "<li><a href=''{0}''>{1}</a></li>\n";
    String currentLinkPattern = "<li class=''active''><a href=''{0}''>{1}</a></li>\n";

    StringBuilder sb = new StringBuilder();
    for (DocElement element : elements) {
      if (element instanceof DocPage) {
        DocPage page = (DocPage) element;
        if (!page.showNavbarLink) {
          continue;
        }
        String href = getHref(page);
        boolean active = currentElement.equals(page);
        if (active) {
          // current page
          sb.append(MessageFormat.format(currentLinkPattern, href, page.name));
        } else {
          // page link
          sb.append(MessageFormat.format(linkPattern, href, page.name));
        }
      } else if (element instanceof DocLink) {
        // ext link
        DocLink link = (DocLink) element;
        String href = getHref(link);
        sb.append(MessageFormat.format(linkPattern, href, link.name));
      } else if (element instanceof DocDivider) {
        if (currentElement instanceof DocMenu) {
          // menu divider
          sb.append("<li class='divider'></li>\n");
        } else {
          // nav bar divider
          sb.append("<li class='divider-vertical'></li>\n");
        }
      } else if (element instanceof DocMenu) {
        // drop down menu
        DocMenu menu = (DocMenu) element;
        if (currentElement instanceof DocMenu) {
          // menu submenu
          sb.append("<li class='dropdown-submenu'> <!-- Submenu -->\n");
          sb.append(MessageFormat
              .format("<a tabindex=''-1'' href=''#''>{0}</a>\n",
                  menu.name));
          sb.append("<ul class='dropdown-menu'>\n");
          sb.append(createLinks(menu, menu.elements));
          sb.append("</ul></li> <!-- End Submenu -->\n");
        } else {
          // navbar menu
          sb.append("<li class='dropdown'> <!-- Menu -->\n");
          sb.append(MessageFormat
              .format("<a class=''dropdown-toggle'' href=''#'' data-toggle=''dropdown''>{0}<b class=''caret''></b></a>\n",
                  menu.name));
          sb.append("<ul class='dropdown-menu'>\n");
          sb.append(createLinks(menu, menu.elements));
          sb.append("</ul></li> <!-- End Menu -->\n");
        }
      }
    }
    sb.trimToSize();
    return sb.toString();
  }

  private static String getHref(DocElement element) {
    if (element instanceof DocLink) {
      // external link
      return ((DocLink) element).src;
    } else if (element instanceof DocPage) {
      // page link
      DocPage page = (DocPage) element;
      if (StringUtils.isEmpty(page.as)) {
        String html = page.src.substring(0, page.src.lastIndexOf('.'))
          + ".html";
        return html;
      }
      return page.as;
    }
    return null;
  }

  private static String transformMarkdown(String comment) throws ParseException {
    String md = MarkdownUtils.transformMarkdown(comment);
    if (md.startsWith("<p>")) {
      md = md.substring(3);
    }
    if (md.endsWith("</p>")) {
      md = md.substring(0, md.length() - 4);
    }
    return md;
  }

  private static String generateHeader(String projectName, ToolkitConfig conf, Doc doc) {
    out.println("Generating HTML header...");
    StringBuilder sb = new StringBuilder();
    String header = readResource(doc, "header.html");
    header = header.replace("%PROJECTNAME%", projectName);
    sb.append(header);
   
    if (doc.isResponsiveLayout) {
      sb.append("<!-- Responsive CSS must be included after the above body css! -->\n");
      sb.append("<link rel='stylesheet' href='./bootstrap/css/bootstrap-responsive.min.css'>\n");
    }

    if (doc.keywords != null && doc.keywords.size() > 0) {
      String keywords = StringUtils.flattenStrings(doc.keywords);
      sb.append(MessageFormat.format(
          "<meta name=\"keywords\" content=\"{0}\" />\n", keywords));
    }

    if (doc.favicon != null) {
      sb.append("\n<link rel='shortcut icon' type='image/png' href='./"
          + doc.favicon.getName() + "' />");
    }

    if (StringUtils.isEmpty(doc.prettifyTheme)) {
      // default theme
      sb.append("\n<link rel=\"stylesheet\" href=\"./prettify/prettify.css\" />");
    } else {
      // custom theme
      sb.append(MessageFormat.format("\n<link rel=\"stylesheet\" href=\"./prettify/{0}\" />",
          doc.prettifyTheme + (doc.prettifyTheme.toLowerCase().endsWith(".css") ? "" : ".css")));
    }
   
    if (!StringUtils.isEmpty(doc.rssFeed)) {
      sb.append(MessageFormat.format(
          "<link rel=\"alternate\" type=\"application/rss+xml\" title=\"{0} RSS 2.0\" href=\"./{1}\" />\n", doc.name, doc.rssFeed));
    }

    if (!StringUtils.isEmpty(doc.atomFeed)) {
      sb.append(MessageFormat.format(
          "<link rel=\"alternate\" type=\"application/atom+xml\" title=\"{0} Atom\" href=\"./{1}\" />\n", doc.name, doc.atomFeed));
    }

    if (!StringUtils.isEmpty(doc.googlePlusId)) {
      String content = readResource(doc, "pluspage.html");
      content = content.replace("%PLUSID%", doc.googlePlusId);
      sb.append('\n');
      sb.append(content);
      sb.append('\n');
    }

    if (doc.googlePlusOne && !StringUtils.isEmpty(conf.pom.url)) {
      String content = readResource(doc, "plusone.html");
      content = content.replace("%URL%", conf.pom.url);
      sb.append('\n');
      sb.append(content);
      sb.append('\n');
    }

    if (doc.header != null && doc.header.exists()) {
      String content = FileUtils.readContent(doc.header, "\n");
      if (!StringUtils.isEmpty(content)) {
        sb.append("\n<!-- Header Contribution -->\n");
        sb.append(content);
        sb.append('\n');
      }
    }
    return sb.toString();
  }

  private static String generateFooter(Doc doc) {
    out.println("Generating HTML footer...");
    final String date = new SimpleDateFormat("yyyy-MM-dd")
        .format(new Date());
    String footer = readResource(doc, "footer.html");
    if (doc.footer != null && doc.footer.exists()) {
      String custom = FileUtils.readContent(doc.footer, "\n");
      if (!StringUtils.isEmpty(custom)) {
        footer = custom;
      }
    }
    footer = footer.replace("%PAGEDATE%", date);
    footer = footer
        .replace(
            "%PAGELICENSE%",
            "The content of this page is licensed under the <a href=\"http://creativecommons.org/licenses/by/3.0\">Creative Commons Attribution 3.0 License</a>.");
    return footer;
  }

  private static String generatePropertiesContent(Prop prop) throws Exception {
    BufferedReader propertiesReader = new BufferedReader(new FileReader(
        new File(prop.file)));

    Vector<Setting> settings = new Vector<Setting>();
    List<String> comments = new ArrayList<String>();
    String line = null;
    while ((line = propertiesReader.readLine()) != null) {
      if (line.length() == 0) {
        Setting s = new Setting("", "", comments);
        settings.add(s);
        comments.clear();
      } else {
        if (line.charAt(0) == '#') {
          comments.add(line.substring(1).trim());
        } else {
          String[] kvp = line.split("=", 2);
          String key = kvp[0].trim();
          Setting s = new Setting(key, kvp[1].trim(), comments);
          settings.add(s);
          comments.clear();
        }
      }
    }
    propertiesReader.close();

    StringBuilder sb = new StringBuilder();
    for (Setting setting : settings) {
      for (String comment : setting.comments) {
        if (prop.containsKeyword(comment)) {
          sb.append(MessageFormat
              .format("<span style=\"color:#004000;\"># <i>{0}</i></span>",
                  transformMarkdown(comment)));
        } else {
          sb.append(MessageFormat.format(
              "<span style=\"color:#004000;\"># {0}</span>",
              transformMarkdown(comment)));
        }
        sb.append("<br/>\n");
      }
      if (!StringUtils.isEmpty(setting.name)) {
        sb.append(MessageFormat
            .format("<span style=\"color:#000080;\">{0}</span> = <span style=\"color:#800000;\">{1}</span>",
                setting.name,
                StringUtils.escapeForHtml(setting.value, false)));
      }
      sb.append("<br/>\n");
    }

    return sb.toString();
  }
 
  protected static void processTemplates(Doc doc, DocPage page) throws TemplateException, MaxmlException, IOException {
    // templates
    if (page.templates != null && !page.templates.isEmpty()) {
      // Freemarker engine
      Configuration fm = new Configuration();
      fm.setObjectWrapper(new DefaultObjectWrapper());
      if (doc.templateDirectory != null && doc.templateDirectory.exists()) {
        fm.setDirectoryForTemplateLoading(doc.templateDirectory);
      } else {
        fm.setDirectoryForTemplateLoading(doc.sourceDirectory);
      }
     
      for (Template template : page.templates) {
        File data = new File(template.data);
        if (!data.exists()) {
          data = new File(doc.sourceDirectory, template.data);
        }
        MaxmlMap dataMap = Maxml.parse(data);
       
        // populate map with build properties by splitting them into maps
        for (Substitute sub : doc.substitutions) {
          if (sub.isProperty()) {
            String prop = sub.getPropertyName();
            MaxmlMap keyMap = dataMap;
            // recursively create/find the destination map
            while (prop.indexOf('.') > -1) {
              String m = prop.substring(0, prop.indexOf('.'));
              if (!keyMap.containsKey(m)) {
                keyMap.put(m, new MaxmlMap());
              }
              keyMap = keyMap.getMap(m);
              prop = prop.substring(m.length() + 1);
            }
           
            // inject property into map
            keyMap.put(prop, sub.value);
          }
        }
       
        // load and process the Freemarker template
        freemarker.template.Template ftl = fm.getTemplate(template.src);
        StringWriter writer = new StringWriter();
        ftl.process(dataMap, writer);
       
        // create a substitution token
        Substitute sub = new Substitute();
        sub.isTemplate = true;
        sub.token = template.token;
        sub.value = writer.toString();
        doc.substitutions.add(sub);
      }
    }
  }
 
  /**
   * Setting represents a setting with its comments from the properties file.
   */
  private static class Setting {
    final String name;
    final String value;
    final List<String> comments;

    Setting(String name, String value, List<String> comments) {
      this.name = name;
      this.value = value;
      this.comments = new ArrayList<String>(comments);
    }
  }
 
  private static class Section {
    String name;
    String id;
   
    Section(String id, String name) {
      this.id = id;
      this.name = name;
    }
  }
}
TOP

Related Classes of org.moxie.Docs

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.