protected override void WriteBlock( Block block, bool isOpening, bool isClosing, out bool ignoreChildNodes) { // NSAttributedString will end up with paragraph spacing at the // end of paragraph elements which leaves empty space at the end // of the NSAttributedString; prevent this by committing <p> tags // for the last paragraph. var renderTightParagraphs = block == block.Top.LastChild; if (renderTightParagraphs) { RenderTightParagraphs.Push(true); } base.WriteBlock(block, isOpening, isClosing, out ignoreChildNodes); if (renderTightParagraphs) { RenderTightParagraphs.Pop(); } // NSAttributedString lacks paragraph spacing between between // adjacent <ul> and <p> nodes, so insert a hard break. if (block.Tag == BlockTag.List && isClosing) { Write("<br>"); } }
protected override void WriteBlock(Block block, bool isOpening, bool isClosing, out bool ignoreChildNodes) { ignoreChildNodes = false; switch (block.Tag) { case BlockTag.ListItem: if (isOpening) { EnsureNewLine(); Write("<li"); if (block.ListData.ListType == ListType.Ordered) { Write(string.Format(" srn-priority=\"{0}\"", block.ListData.Start)); } Write(">"); } if (isClosing) { WriteLine("</li>"); } break; case BlockTag.List: if (isOpening) { EnsureNewLine(); Write("<ul"); if (block.ListData.ListType == ListType.Ordered) { Write(" class=\"srn-priorities\""); } Write(">"); RenderTightParagraphs.Push(block.ListData.IsTight); } if (isClosing) { WriteLine("</ul>"); RenderTightParagraphs.Pop(); } break; default: base.WriteBlock(block, isOpening, isClosing, out ignoreChildNodes); break; } }
/// <summary> /// Writes the specified block element to the output stream. Does not write the child nodes, instead /// the <paramref name="ignoreChildNodes"/> is used to notify the caller whether it should recurse /// into the child nodes. /// </summary> /// <param name="block">The block element to be written to the output stream.</param> /// <param name="isOpening">Specifies whether the block element is being opened (or started).</param> /// <param name="isClosing">Specifies whether the block element is being closed. If the block does not /// have child nodes, then both <paramref name="isClosing"/> and <paramref name="isOpening"/> can be /// <c>true</c> at the same time.</param> /// <param name="ignoreChildNodes">Instructs the caller whether to skip processing of child nodes or not.</param> protected virtual void WriteBlock(Block block, bool isOpening, bool isClosing, out bool ignoreChildNodes) { ignoreChildNodes = false; int x; switch (block.Tag) { case BlockTag.Document: break; case BlockTag.Paragraph: if (RenderTightParagraphs.Peek()) { break; } if (isOpening) { EnsureNewLine(); Write("<p"); if (Settings.TrackSourcePosition) { WritePositionAttribute(block); } Write('>'); } if (isClosing) { WriteLine("</p>"); } break; case BlockTag.BlockQuote: if (isOpening) { EnsureNewLine(); Write("<blockquote"); if (Settings.TrackSourcePosition) { WritePositionAttribute(block); } WriteLine(">"); RenderTightParagraphs.Push(false); } if (isClosing) { RenderTightParagraphs.Pop(); WriteLine("</blockquote>"); } break; case BlockTag.ListItem: if (isOpening) { EnsureNewLine(); Write("<li"); if (Settings.TrackSourcePosition) { WritePositionAttribute(block); } Write('>'); } if (isClosing) { WriteLine("</li>"); } break; case BlockTag.List: var data = block.ListData; if (isOpening) { EnsureNewLine(); Write(data.ListType == ListType.Bullet ? "<ul" : "<ol"); if (data.Start != 1) { Write(" start=\""); Write(data.Start.ToString(CultureInfo.InvariantCulture)); Write('\"'); } if (Settings.TrackSourcePosition) { WritePositionAttribute(block); } WriteLine(">"); RenderTightParagraphs.Push(data.IsTight); } if (isClosing) { WriteLine(data.ListType == ListType.Bullet ? "</ul>" : "</ol>"); RenderTightParagraphs.Pop(); } break; case BlockTag.AtxHeader: case BlockTag.SETextHeader: x = block.HeaderLevel; if (isOpening) { EnsureNewLine(); Write("<h" + x.ToString(CultureInfo.InvariantCulture)); if (Settings.TrackSourcePosition) { WritePositionAttribute(block); } Write('>'); } if (isClosing) { WriteLine("</h" + x.ToString(CultureInfo.InvariantCulture) + ">"); } break; case BlockTag.IndentedCode: case BlockTag.FencedCode: ignoreChildNodes = true; EnsureNewLine(); Write("<pre><code"); if (Settings.TrackSourcePosition) { WritePositionAttribute(block); } var info = block.FencedCodeData == null ? null : block.FencedCodeData.Info; if (info != null && info.Length > 0) { x = info.IndexOf(' '); if (x == -1) { x = info.Length; } Write(" class=\"language-"); WriteEncodedHtml(new StringPart(info, 0, x)); Write('\"'); } Write('>'); WriteEncodedHtml(block.StringContent); WriteLine("</code></pre>"); break; case BlockTag.HtmlBlock: ignoreChildNodes = true; // cannot output source position for HTML blocks Write(block.StringContent); break; case BlockTag.HorizontalRuler: ignoreChildNodes = true; if (Settings.TrackSourcePosition) { Write("<hr"); WritePositionAttribute(block); WriteLine(); } else { WriteLine("<hr />"); } break; case BlockTag.ReferenceDefinition: break; default: throw new CommonMarkException("Block type " + block.Tag + " is not supported.", block); } if (ignoreChildNodes && !isClosing) { throw new InvalidOperationException("Block of type " + block.Tag + " cannot contain child nodes."); } }