Browse Source

Changes

Ported @Tabs support over.
tags/0.9.0
Frans Bouma 10 years ago
parent
commit
6f18a19ad5
9 changed files with 239 additions and 21 deletions
  1. +56
    -3
      src/MarkdownDeep/Block.cs
  2. +100
    -17
      src/MarkdownDeep/BlockProcessor.cs
  3. +12
    -1
      src/MarkdownDeep/MardownDeep.cs
  4. +28
    -0
      src/MarkdownDeep/StringScanner.cs
  5. +6
    -0
      src/MarkdownDeepTests/MarkdownDeepTests.csproj
  6. +4
    -0
      src/MarkdownDeepTests/testfiles/docnetmode/Alert(DocNetMode).html
  7. +4
    -0
      src/MarkdownDeepTests/testfiles/docnetmode/Alert(DocNetMode).txt
  8. +14
    -0
      src/MarkdownDeepTests/testfiles/docnetmode/Tabs(DocNetMode).html
  9. +15
    -0
      src/MarkdownDeepTests/testfiles/docnetmode/Tabs(DocNetMode).txt

+ 56
- 3
src/MarkdownDeep/Block.cs View File

@@ -59,6 +59,8 @@ namespace MarkdownDeep
// DocNet extensions
font_awesome, // Data is icon name
alert, // Data is the alert type specified.
tab, // Data is the tab header text.
tabs, // children are the tabs.
}

class Block
@@ -385,7 +387,12 @@ namespace MarkdownDeep
RenderAlert(m, b);
}
break;

case BlockType.tabs:
if(m.DocNetMode)
{
RenderTabs(m, b);
}
break;
// End DocNet Extensions
default:
b.Append("<" + BlockType.ToString() + ">");
@@ -395,7 +402,6 @@ namespace MarkdownDeep
}
}


internal void RenderPlain(Markdown m, StringBuilder b)
{
switch (BlockType)
@@ -513,13 +519,60 @@ namespace MarkdownDeep
b.Append(alertType);
b.Append("\"><span class=\"alert-title\"><i class=\"fa fa-");
b.Append(faIconName);
b.Append("\"></i>");
b.Append("\"></i> ");
b.Append(title);
b.Append("</span>");
RenderChildren(m, b);
b.Append("</div>");
}


private void RenderTabs(Markdown m, StringBuilder b)
{
var tabId = m.GetNewTabId();
var headerSB = new StringBuilder();
var contentSB = new StringBuilder();
var tabCounter = 0;
var checkedAttribute = " checked";
foreach(var tabBlock in this.Children)
{
if(tabBlock.BlockType != BlockType.tab)
{
return;
}
var tabHeaderText = tabBlock.Data as string ?? "Tab";
// header
string tabIdSuffix = tabCounter + "_" + tabId;
headerSB.Append("<input type=\"radio\" id=\"tab");
headerSB.Append(tabIdSuffix);
headerSB.Append("\" name=\"tabGroup");
headerSB.Append(tabId);
headerSB.Append("\" class=\"tab\"");
headerSB.Append(checkedAttribute);
headerSB.Append("><label for=\"tab");
headerSB.Append(tabIdSuffix);
headerSB.Append("\">");
headerSB.Append(tabHeaderText);
headerSB.Append("</label>");

// content
var tabContentSB = new StringBuilder();
tabBlock.RenderChildren(m, tabContentSB);
contentSB.Append("<div class=\"tab-content\">");
contentSB.Append(tabContentSB.ToString());
contentSB.Append("</div>");

// done
checkedAttribute = string.Empty;
tabCounter++;
}
b.Append("<div class=\"tab-wrap\">");
b.Append(headerSB.ToString());
b.Append(contentSB.ToString());
b.Append("</div>");
}


#region Properties
public int ContentEnd
{


+ 100
- 17
src/MarkdownDeep/BlockProcessor.cs View File

@@ -1268,10 +1268,15 @@ namespace MarkdownDeep
{
return HandleFontAwesomeExtension(b);
}
// first match @tabs, and then @tab, as both are handled by this processor.
if(DoesMatch("@tabs"))
{
return HandleTabsExtension(b);
}
if(DoesMatch("@tab"))
{
return HandleTabForTabsExtension(b);
}
if(DoesMatch("@alert"))
{
return HandleAlertExtension(b);
@@ -1280,6 +1285,7 @@ namespace MarkdownDeep
}



/// <summary>
/// Handles the alert extension:
/// @alert type
@@ -1327,21 +1333,7 @@ namespace MarkdownDeep
}

// Remove the trailing line end
if(Input[endContent - 1] == '\r' && Input[endContent - 2] == '\n')
{
endContent -= 2;
}
else
{
if(Input[endContent - 1] == '\n' && Input[endContent - 2] == '\r')
{
endContent -= 2;
}
else
{
endContent--;
}
}
endContent = UnskipCRLFBeforePos(endContent);
b.BlockType = BlockType.alert;
b.Data = alertType;
// scan the content, as it can contain markdown statements.
@@ -1350,10 +1342,101 @@ namespace MarkdownDeep
return true;
}


private bool HandleTabsExtension(Block b)
{
#warning IMPLEMENT
return false;
// skip '@tabs'
if(!SkipString("@tabs"))
{
return false;
}
// ignore what's specified behind @tabs
SkipToNextLine();
int startContent = this.Position;
// find @end.
if(!Find("@endtabs"))
{
return false;
}
// Character before must be a eol char
if(!IsLineEnd(CharAtOffset(-1)))
{
return false;
}
int endContent = Position;
// skip @end
SkipString("@endtabs");
SkipLinespace();
if(!Eol)
{
return false;
}
// Remove the trailing line end
endContent = UnskipCRLFBeforePos(endContent);
b.BlockType = BlockType.tabs;
// scan the content, as it can contain markdown statements.
var contentProcessor = new BlockProcessor(m_markdown, m_markdown.MarkdownInHtml);
var scanLines = contentProcessor.ScanLines(this.Input, startContent, endContent - startContent);
// check whether the content is solely tab blocks. If not, we ignore this tabs specification.
if(scanLines.Any(x=>x.BlockType != BlockType.tab))
{
return false;
}
b.Children = scanLines;
return true;
}


/// <summary>
/// Handles the tab for tabs extension. This is a docnet extension and it handles:
/// @tab tab head text
/// tab content
/// @end
/// </summary>
/// <param name="b">The current block.</param>
/// <returns></returns>
private bool HandleTabForTabsExtension(Block b)
{
// skip '@tab'
if(!SkipString("@tab"))
{
return false;
}
SkipLinespace();
var tabHeaderTextStart = this.Position;
// skip to eol, then grab the content between positions.
SkipToEol();
var tabHeaderText = this.Input.Substring(tabHeaderTextStart, this.Position - tabHeaderTextStart);
SkipToNextLine();
int startContent = this.Position;

// find @end.
if(!Find("@end"))
{
return false;
}
// Character before must be a eol char
if(!IsLineEnd(CharAtOffset(-1)))
{
return false;
}
int endContent = Position;
// skip @end
SkipString("@end");
SkipLinespace();
if(!Eol)
{
return false;
}

// Remove the trailing line end
endContent = UnskipCRLFBeforePos(endContent);
b.BlockType = BlockType.tab;
b.Data = tabHeaderText;
// scan the content, as it can contain markdown statements.
var contentProcessor = new BlockProcessor(m_markdown, m_markdown.MarkdownInHtml);
b.Children = contentProcessor.ScanLines(Input, startContent, endContent - startContent);
return true;
}




+ 12
- 1
src/MarkdownDeep/MardownDeep.cs View File

@@ -42,6 +42,7 @@ namespace MarkdownDeep
private Dictionary<string, bool> m_UsedHeaderIDs;
private Dictionary<string, Abbreviation> m_AbbreviationMap;
private List<Abbreviation> m_AbbreviationList;
private int _tabIdCounter;
#endregion

// Constructor
@@ -57,6 +58,7 @@ namespace MarkdownDeep
m_UsedFootnotes = new List<Block>();
m_UsedHeaderIDs = new Dictionary<string, bool>();
this.CreatedH2IdCollector = new List<Tuple<string, string>>();
_tabIdCounter = 0;
}

internal List<Block> ProcessBlocks(string str)
@@ -551,6 +553,16 @@ namespace MarkdownDeep
return sb.ToString();
}

/// <summary>
/// Gets the new tab identifier, which is a unique number within the markdown parsing pass.
/// </summary>
/// <returns></returns>
internal int GetNewTabId()
{
_tabIdCounter++;
return _tabIdCounter;
}

// Add a link definition
internal void AddLinkDefinition(LinkDefinition link)
{
@@ -1019,7 +1031,6 @@ namespace MarkdownDeep
get;
set;
}

#endregion

}


+ 28
- 0
src/MarkdownDeep/StringScanner.cs View File

@@ -537,5 +537,33 @@ namespace MarkdownDeep
int pos;
int end;
int mark;


/// <summary>
/// Unskips the CRLF before position. This simply means it returns the new position calculated from the specified position if before the specified
/// position a CRLF is present.
/// </summary>
/// <param name="position">The position.</param>
/// <returns>position minus 0, 1 or 2 depending on whether a CRLF is present right before position: if so, it returns position - the length of the CRLF
/// which can be 1 or 2 depending on the fact whether it's \r or \n or both.</returns>
protected int UnskipCRLFBeforePos(int position)
{
if(this.Input[position - 1] == '\r' && this.Input[position - 2] == '\n')
{
position -= 2;
}
else
{
if(this.Input[position - 1] == '\n' && this.Input[position - 2] == '\r')
{
position -= 2;
}
else
{
position--;
}
}
return position;
}
}
}

+ 6
- 0
src/MarkdownDeepTests/MarkdownDeepTests.csproj View File

@@ -467,6 +467,12 @@
<ItemGroup>
<EmbeddedResource Include="testfiles\docnetmode\Alert%28DocNetMode%29.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\docnetmode\Tabs%28DocNetMode%29.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="testfiles\docnetmode\Tabs%28DocNetMode%29.txt" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.


+ 4
- 0
src/MarkdownDeepTests/testfiles/docnetmode/Alert(DocNetMode).html View File

@@ -18,6 +18,10 @@
<span class="alert-title"><i class="fa fa-info-circle"></i>Info</span><p>This is an info text, it will be displayed in an info alert box!</p>
</div>

<div class="alert alert-info">
<span class="alert-title"><i class="fa fa-info-circle"></i>Info</span><p>This is an <strong>info text</strong>, it will be displayed in an info alert box!</p>
</div>

<p>@alert
This is an info text, it will be displayed in an info alert box!
@end</p>


+ 4
- 0
src/MarkdownDeepTests/testfiles/docnetmode/Alert(DocNetMode).txt View File

@@ -17,6 +17,10 @@ This is an info text, it will be displayed in an info alert box!
This is an info text, it will be displayed in an info alert box!
@end

@alert info
This is an **info text**, it will be displayed in an info alert box!
@end

@alert
This is an info text, it will be displayed in an info alert box!
@end


+ 14
- 0
src/MarkdownDeepTests/testfiles/docnetmode/Tabs(DocNetMode).html View File

@@ -0,0 +1,14 @@
<p>pre</p>

<p>This is some text</p>

<div class="tab-wrap">
<input type="radio" id="tab0_1" name="tabGroup1" class="tab" checked><label for="tab0_1">First Tab</label><input type="radio" id="tab1_1" name="tabGroup1" class="tab"><label for="tab1_1">Second Tab</label><div class="tab-content">
<p>This is the text for the first tab. It's nothing special</p>
<p>As you can see, it can deal with newlines as well. </p>
</div><div class="tab-content">
<p>Now, the second tab however is very interesting. At least let's pretend it is!</p>
</div>
</div>

<p>post</p>

+ 15
- 0
src/MarkdownDeepTests/testfiles/docnetmode/Tabs(DocNetMode).txt View File

@@ -0,0 +1,15 @@
pre

This is some text
@tabs
@tab First Tab
This is the text for the first tab. It's nothing special

As you can see, it can deal with newlines as well.
@end
@tab Second Tab
Now, the second tab however is very interesting. At least let's pretend it is!
@end
@endtabs

post

Loading…
Cancel
Save