generator/AWSPSGeneratorLib/Writers/Help/BasePageWriter.cs (260 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Reflection;
using AWSPowerShellGenerator.Generators;
namespace AWSPowerShellGenerator.Writers.Help
{
/// <summary>
/// Base class for all web help page output writers
/// </summary>
internal abstract class BasePageWriter
{
protected GeneratorOptions Options { get; private set; }
protected string OutputFolder { get; private set; }
protected string RelativePathToRoot { get; private set; }
private const string FeedbackSection =
"<!-- BEGIN-FEEDBACK-SECTION --><span class=\"feedback\">{0}</span><!-- END-FEEDBACK-SECTION -->";
protected BasePageWriter(GeneratorOptions options, string outputFolder)
{
Options = options;
OutputFolder = outputFolder;
}
protected abstract string GetTitle();
protected abstract string GetService();
protected abstract string GetName();
protected abstract string GetMetaDescription();
public abstract string GenerateFilename();
public abstract string GetTOCID();
protected abstract void WriteContent(TextWriter writer);
public void Write()
{
var filename = Path.Combine(OutputFolder, "items", GenerateFilename());
RelativePathToRoot = ComputeRelativeRootPath(OutputFolder, filename);
var directory = new FileInfo(filename).Directory.FullName;
if (!Directory.Exists(directory))
{
Console.WriteLine("Creating Directory: {0}", directory);
Directory.CreateDirectory(directory);
}
using (var writer = new StringWriter())
{
writer.WriteLine("<html>");
writer.WriteLine("<head>");
writer.WriteLine("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"/>");
writer.WriteLine("<meta name=\"guide-name\" content=\"Cmdlet Reference\"/>");
writer.WriteLine("<meta name=\"service-name\" content=\"AWS Tools for PowerShell\"/>");
writer.WriteLine("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}/resources/style.css\"/>", RelativePathToRoot);
writer.WriteLine("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}/resources/syntaxhighlighter/shCore.css\">", RelativePathToRoot);
writer.WriteLine("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}/resources/syntaxhighlighter/shThemeDefault.css\">", RelativePathToRoot);
writer.WriteLine("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}/resources/psstyle.css\"/>", RelativePathToRoot);
// every page needs a title, meta description and canonical url to satisfy indexing
writer.WriteLine("<meta name=\"description\" content=\"{0}\">", GetMetaDescription());
writer.WriteLine("<title>{0} | AWS Tools for PowerShell</title>", GetTitle());
writer.WriteLine("<script type=\"text/javascript\" src=\"/assets/js/awsdocs-boot.js\"></script>");
writer.WriteLine("<link rel=\"canonical\" href=\"http://docs.aws.amazon.com/powershell/latest/reference/index.html?page={0}&tocid={1}\"/>",
this.GenerateFilename(),
this.GetTOCID());
writer.WriteLine("</head>");
writer.WriteLine("<body>");
// every page needs two hidden divs giving the search indexer the product title and guide name
writer.WriteLine("<div id=\"product_name\">AWS Tools for Windows PowerShell</div>");
writer.WriteLine("<div id=\"guide_name\">Command Reference</div>");
this.WriteRegionDisclaimer(writer);
this.WriteHeader(writer);
this.WriteToolbar(writer);
writer.WriteLine("<div id=\"pageContent\">");
this.WriteContent(writer);
writer.WriteLine("</div>");
this.WriteFooter(writer);
writer.WriteLine("</body>");
writer.WriteLine("</html>");
var content = writer.ToString();
using (var fileWriter = new StreamWriter(filename))
{
fileWriter.Write(content);
}
}
}
protected virtual void WriteRegionDisclaimer(TextWriter writer)
{
// comment disclaimer is used by DCA pipeline only at present
writer.WriteLine("<!--REGION_DISCLAIMER_DO_NOT_REMOVE-->");
// The BJS disclaimer is handled using js/css, and is not (yet)
// injected via a pipeline. It must not be present in the docs we
// deploy to dca.
writer.WriteLine("<!-- BEGIN-SECTION -->");
writer.WriteLine("<div id=\"regionDisclaimer\">");
writer.WriteLine("<p>{0}</p>", string.Format(WebHelpGenerator.CNNorth1RegionDisclaimerTemplate, Options.CNNorth1RegionDocsDomain));
writer.WriteLine("</div>");
writer.WriteLine("<!-- END-SECTION -->");
}
protected virtual void WriteHeader(TextWriter writer)
{
writer.WriteLine("<div id=\"pageHeader\">");
writer.WriteLine("<div id=\"titles\">");
writer.WriteLine("<h1>{0}</h1>", this.GetName());
if (this.GetService() != null)
writer.WriteLine("<h2>{0}</h2>", this.GetService());
writer.WriteLine("</div>");
writer.WriteLine("</div>");
}
protected virtual void WriteToolbar(TextWriter writer)
{
writer.WriteLine("<div id=\"pageToolbar\">");
writer.WriteLine("<!-- BEGIN-SECTION -->");
writer.WriteLine("<div id=\"search\">");
writer.WriteLine("<form action=\"/search/doc-search.html\" target=\"_blank\" onsubmit=\"return AWSHelpObj.searchFormSubmit(this);\" method=\"get\">");
writer.WriteLine("<div id=\"sfrm\">");
writer.WriteLine("<span id=\"lbl\">");
writer.WriteLine("<label>Search: </label>");
writer.WriteLine("</span>");
writer.WriteLine("<select name=\"searchPath\" id=\"sel\">");
writer.WriteLine("<option value=\"all\">Entire Site</option>");
writer.WriteLine("<option value=\"articles\">Articles & Tutorials</option>");
writer.WriteLine("<option value=\"documentation\">Documentation</option>");
writer.WriteLine("<option value=\"documentation-product\">Documentation - This Product</option>");
writer.WriteLine("<option selected=\"\" value=\"documentation-guide\">Documentation - This Guide</option>");
writer.WriteLine("<option value=\"releasenotes\">Release Notes</option>");
writer.WriteLine("<option value=\"code\">Sample Code & Libraries</option>");
writer.WriteLine("</select>");
writer.WriteLine("<input type=\"text\" name=\"searchQuery\" id=\"sq\">");
writer.WriteLine("<input type=\"image\" alt=\"Go\" src=\"{0}/resources/search-button.png\" id=\"sb\">", RelativePathToRoot);
writer.WriteLine("</div>");
writer.WriteLine("<input id=\"this_doc_product\" type=\"hidden\" value=\"AWS Tools for Windows PowerShell\" name=\"this_doc_product\">");
writer.WriteLine("<input id=\"this_doc_guide\" type=\"hidden\" value=\"Command Reference\" name=\"this_doc_guide\">");
writer.WriteLine("<input type=\"hidden\" value=\"en_us\" name=\"doc_locale\">");
writer.WriteLine("</form>");
writer.WriteLine("</div>");
writer.WriteLine("<!-- END-SECTION -->");
writer.WriteLine("</div>");
}
protected virtual void WriteFooter(TextWriter writer)
{
writer.WriteLine("<div id=\"pageFooter\">");
writer.WriteLine("<span class=\"newline linkto\"><a href=\"javascript:void(0)\" onclick=\"AWSHelpObj.displayLink('{0}', '{1}')\">Link to this page</a></span>",
this.GenerateFilename(),
this.GetTOCID());
writer.WriteLine("<span class=\"divider\"> </span>");
writer.WriteLine(FeedbackSection, GenerateFeedbackHTML());
writer.WriteLine("<div id=\"awsdocs-legal-zone-copyright\"></div>");
writer.WriteLine("</div>");
WriteScriptFiles(writer);
}
private string GenerateFeedbackHTML()
{
string filename = Path.GetFileNameWithoutExtension(GenerateFilename());
string baseUrl = "https://docs.aws.amazon.com/forms/aws-doc-feedback";
string queryString = string.Format("?service_name={0}&topic_url=https://docs.aws.amazon.com/powershell/latest/reference/items/{1}.html",
"PowerShell-Ref", // service_name
filename // guide_name
);
string fullUrl = baseUrl + queryString;
string feedbackContentFormat = "<span class=\"feedbackLinks\">" +
"<!-- BEGIN-FEEDBACK-SECTION -->" +
"Did this page help you? " +
"<a href=\"http://docs.aws.amazon.com/powershell/latest/reference/feedbackyes.html?topic_id={0}\" target=\"_parent\">Yes</a> " +
"<a href=\"http://docs.aws.amazon.com/powershell/latest/reference/feedbackno.html?topic_id={0}\" target=\"_parent\">No</a> " +
"<a href=\"{1}\" target=\"_parent\">Tell us about it...</a>" +
"<!-- END-FEEDBACK-SECTION -->" +
"</span>";
string feedbackContent = string.Format(feedbackContentFormat, filename, fullUrl);
return feedbackContent;
}
protected virtual void WriteScriptFiles(TextWriter writer)
{
writer.WriteLine("<script type=\"text/javascript\" src=\"{0}/resources/jquery.min.js\"></script>", RelativePathToRoot);
writer.WriteLine("<script type=\"text/javascript\">jQuery.noConflict();</script>");
writer.WriteLine("<script type=\"text/javascript\" src=\"{0}/resources/parseuri.js\"></script>", RelativePathToRoot);
writer.WriteLine("<script type=\"text/javascript\" src=\"{0}/resources/pagescript.js\"></script>", RelativePathToRoot);
writer.WriteLine("<!-- BEGIN-SECTION -->");
writer.WriteLine("<script type=\"text/javascript\">");
writer.WriteLine("jQuery(function ($) {");
writer.WriteLine("var host = parseUri($(window.parent.location).attr('href')).host;");
writer.WriteLine("if (AWSHelpObj.showRegionalDisclaimer(host)) {");
writer.WriteLine("$(\"div#regionDisclaimer\").css(\"display\", \"block\");");
writer.WriteLine("} else {");
writer.WriteLine("$(\"div#regionDisclaimer\").remove();");
writer.WriteLine("}");
writer.WriteLine("AWSHelpObj.setAssemblyVersion();");
writer.WriteLine("});");
writer.WriteLine("</script>");
writer.WriteLine("<!-- END-SECTION -->");
writer.WriteLine("<script type=\"text/javascript\" src=\"{0}/resources/syntaxhighlighter/shCore.js\"></script>", RelativePathToRoot);
writer.WriteLine("<script type=\"text/javascript\" src=\"{0}/resources/syntaxhighlighter/shBrushCSharp.js\"></script>", RelativePathToRoot);
writer.WriteLine("<script type=\"text/javascript\" src=\"{0}/resources/syntaxhighlighter/shBrushPlain.js\"></script>", RelativePathToRoot);
writer.WriteLine("<script type=\"text/javascript\" src=\"{0}/resources/syntaxhighlighter/shBrushXml.js\"></script>", RelativePathToRoot);
writer.WriteLine("<script type=\"text/javascript\">SyntaxHighlighter.all()</script>");
}
protected void AddMemberTableSectionHeader(TextWriter writer, string name, bool showIconColumn = true)
{
AddMemberTableSectionHeader(writer, name, showIconColumn, "Name", "Description");
}
protected void AddMemberTableSectionHeader(TextWriter writer, string name, bool showIconColumn, string nameColumnName, string descriptionColumnName)
{
writer.WriteLine("<div>");
writer.WriteLine("<div>");
writer.WriteLine("<div class=\"collapsibleSection\">");
writer.WriteLine("<h2 id=\"{1}\" class=\"title\">{0}</h2>", name, name.ToLower());
writer.WriteLine("</div>");
writer.WriteLine("</div>");
writer.WriteLine("<div class=\"sectionbody\">");
writer.WriteLine("<table class=\"members\">");
writer.WriteLine("<tbody>");
writer.WriteLine("<tr>");
if(showIconColumn)
writer.WriteLine("<th class=\"iconColumn\"> </th>");
writer.WriteLine("<th class=\"nameColumn\">{0}</th>", nameColumnName);
writer.WriteLine("<th class=\"descriptionColumn\">{0}</th>", descriptionColumnName);
writer.WriteLine("</tr>");
}
protected void AddMemberTableSectionClosing(TextWriter writer)
{
writer.WriteLine("</tbody>");
writer.WriteLine("</table>");
writer.WriteLine("</div>");
writer.WriteLine("</div>");
}
protected void AddSectionHeader(TextWriter writer, string name)
{
writer.WriteLine("<div>");
writer.WriteLine("<div>");
writer.WriteLine("<div class=\"collapsibleSection\">");
writer.WriteLine("<h2 id=\"{1}\" class=\"title\">{0}</h2>", name, name.ToLower());
writer.WriteLine("</div>");
writer.WriteLine("</div>");
writer.WriteLine("<div class=\"sectionbody\">");
}
protected void AddSectionClosing(TextWriter writer)
{
writer.WriteLine("</div>");
writer.WriteLine("</div>");
}
protected string GetModuleAvailability(string moduleName)
{
var inMonolithic = moduleName != TOCWriter.InstallerModuleName;
var inModular = !WebHelpGenerator.NonModularizedServices.Contains(moduleName);
var text = new StringBuilder("Available in ");
if (inModular)
{
text.Append($"<a href=\"https://www.powershellgallery.com/packages/AWS.Tools.{moduleName}/\" target=\"_blank\" rel=\"noopener noreferrer\">AWS.Tools.{moduleName}</a>");
}
if (inMonolithic)
{
text.Append(inModular ? ", " : string.Empty);
text.Append($"<a href=\"https://www.powershellgallery.com/packages/AWSPowerShell.NetCore/\" target=\"_blank\" rel=\"noopener noreferrer\">AWSPowerShell.NetCore</a>");
text.Append(" and ");
text.Append($"<a href=\"https://www.powershellgallery.com/packages/AWSPowerShell/\" target=\"_blank\" rel=\"noopener noreferrer\">AWSPowerShell</a>");
}
return text.ToString();
}
// computes the relative distance from root of a filename and returns a ../ sequence
// that can step back far enough to get to root
private static string ComputeRelativeRootPath(string rootFolder, string filename)
{
var relativePath = new StringBuilder();
var filepath = Path.GetDirectoryName(filename);
while (!filepath.Equals(rootFolder, StringComparison.OrdinalIgnoreCase))
{
if (relativePath.Length > 0)
relativePath.Append("/");
relativePath.Append("..");
filepath = Path.GetDirectoryName(filepath);
}
return relativePath.ToString();
}
}
}