| @@ -324,9 +324,9 @@ img { | |||||
| border: 0; | border: 0; | ||||
| -ms-interpolation-mode: bicubic; | -ms-interpolation-mode: bicubic; | ||||
| vertical-align: middle; | vertical-align: middle; | ||||
| box-shadow: 0px 0px 10px rgba(10,10,10,0.3); | |||||
| } | } | ||||
| input { | input { | ||||
| line-height: normal; | line-height: normal; | ||||
| font-size: 100%; | font-size: 100%; | ||||
| @@ -476,8 +476,9 @@ div.figure { | |||||
| text-align: center; | text-align: center; | ||||
| } | } | ||||
| div.figure img { | |||||
| img.shadowed, div.figure img { | |||||
| margin: 0 auto; | margin: 0 auto; | ||||
| box-shadow: 0px 0px 10px rgba(10,10,10,0.3); | |||||
| } | } | ||||
| div.figure p { | div.figure p { | ||||
| @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; | |||||
| // You can specify all the values or you can default the Build and Revision Numbers | // You can specify all the values or you can default the Build and Revision Numbers | ||||
| // by using the '*' as shown below: | // by using the '*' as shown below: | ||||
| // [assembly: AssemblyVersion("1.0.*")] | // [assembly: AssemblyVersion("1.0.*")] | ||||
| [assembly: AssemblyVersion("0.9.2.0")] | |||||
| [assembly: AssemblyFileVersion("0.9.2")] | |||||
| [assembly: AssemblyVersion("0.10.0.0")] | |||||
| [assembly: AssemblyFileVersion("0.10.0")] | |||||
| @@ -21,54 +21,33 @@ namespace MarkdownDeep | |||||
| { | { | ||||
| public class LinkDefinition | public class LinkDefinition | ||||
| { | { | ||||
| public LinkDefinition(string id) | |||||
| public LinkDefinition(string id) : this(id, string.Empty, string.Empty) | |||||
| { | { | ||||
| this.id= id; | |||||
| } | } | ||||
| public LinkDefinition(string id, string url) | |||||
| public LinkDefinition(string id, string url) : this(id, url, string.Empty) | |||||
| { | { | ||||
| this.id = id; | |||||
| this.url = url; | |||||
| } | } | ||||
| public LinkDefinition(string id, string url, string title) | public LinkDefinition(string id, string url, string title) | ||||
| { | { | ||||
| this.id = id; | |||||
| this.url = url; | |||||
| this.title = title; | |||||
| } | |||||
| public string id | |||||
| { | |||||
| get; | |||||
| set; | |||||
| } | |||||
| public string url | |||||
| { | |||||
| get; | |||||
| set; | |||||
| } | |||||
| public string title | |||||
| { | |||||
| get; | |||||
| set; | |||||
| this.Id = id; | |||||
| this.Url = url; | |||||
| this.Title = title; | |||||
| } | } | ||||
| internal void RenderLink(Markdown m, StringBuilder b, string link_text) | |||||
| internal void RenderLink(Markdown m, StringBuilder b, string link_text, List<string> specialAttributes) | |||||
| { | { | ||||
| if (url.StartsWith("mailto:")) | |||||
| if (this.Url.StartsWith("mailto:")) | |||||
| { | { | ||||
| b.Append("<a href=\""); | b.Append("<a href=\""); | ||||
| Utils.HtmlRandomize(b, url); | |||||
| Utils.HtmlRandomize(b, this.Url); | |||||
| b.Append('\"'); | b.Append('\"'); | ||||
| if (!String.IsNullOrEmpty(title)) | |||||
| if (!String.IsNullOrEmpty(this.Title)) | |||||
| { | { | ||||
| b.Append(" title=\""); | b.Append(" title=\""); | ||||
| Utils.SmartHtmlEncodeAmpsAndAngles(b, title); | |||||
| Utils.SmartHtmlEncodeAmpsAndAngles(b, this.Title); | |||||
| b.Append('\"'); | b.Append('\"'); | ||||
| } | } | ||||
| b.Append('>'); | b.Append('>'); | ||||
| @@ -81,17 +60,22 @@ namespace MarkdownDeep | |||||
| // encode url | // encode url | ||||
| StringBuilder sb = m.GetStringBuilder(); | StringBuilder sb = m.GetStringBuilder(); | ||||
| Utils.SmartHtmlEncodeAmpsAndAngles(sb, url); | |||||
| Utils.SmartHtmlEncodeAmpsAndAngles(sb, this.Url); | |||||
| tag.attributes["href"] = sb.ToString(); | tag.attributes["href"] = sb.ToString(); | ||||
| // encode title | // encode title | ||||
| if (!String.IsNullOrEmpty(title )) | |||||
| if (!String.IsNullOrEmpty(this.Title )) | |||||
| { | { | ||||
| sb.Length = 0; | sb.Length = 0; | ||||
| Utils.SmartHtmlEncodeAmpsAndAngles(sb, title); | |||||
| Utils.SmartHtmlEncodeAmpsAndAngles(sb, this.Title); | |||||
| tag.attributes["title"] = sb.ToString(); | tag.attributes["title"] = sb.ToString(); | ||||
| } | } | ||||
| if(specialAttributes.Any()) | |||||
| { | |||||
| LinkDefinition.HandleSpecialAttributes(specialAttributes, sb, tag); | |||||
| } | |||||
| // Do user processing | // Do user processing | ||||
| m.OnPrepareLink(tag); | m.OnPrepareLink(tag); | ||||
| @@ -103,13 +87,14 @@ namespace MarkdownDeep | |||||
| } | } | ||||
| } | } | ||||
| internal void RenderImg(Markdown m, StringBuilder b, string alt_text) | |||||
| internal void RenderImg(Markdown m, StringBuilder b, string alt_text, List<string> specialAttributes) | |||||
| { | { | ||||
| HtmlTag tag = new HtmlTag("img"); | HtmlTag tag = new HtmlTag("img"); | ||||
| // encode url | // encode url | ||||
| StringBuilder sb = m.GetStringBuilder(); | StringBuilder sb = m.GetStringBuilder(); | ||||
| Utils.SmartHtmlEncodeAmpsAndAngles(sb, url); | |||||
| Utils.SmartHtmlEncodeAmpsAndAngles(sb, Url); | |||||
| tag.attributes["src"] = sb.ToString(); | tag.attributes["src"] = sb.ToString(); | ||||
| // encode alt text | // encode alt text | ||||
| @@ -121,13 +106,16 @@ namespace MarkdownDeep | |||||
| } | } | ||||
| // encode title | // encode title | ||||
| if (!String.IsNullOrEmpty(title)) | |||||
| if (!String.IsNullOrEmpty(Title)) | |||||
| { | { | ||||
| sb.Length = 0; | sb.Length = 0; | ||||
| Utils.SmartHtmlEncodeAmpsAndAngles(sb, title); | |||||
| Utils.SmartHtmlEncodeAmpsAndAngles(sb, Title); | |||||
| tag.attributes["title"] = sb.ToString(); | tag.attributes["title"] = sb.ToString(); | ||||
| } | } | ||||
| if(specialAttributes.Any()) | |||||
| { | |||||
| LinkDefinition.HandleSpecialAttributes(specialAttributes, sb, tag); | |||||
| } | |||||
| tag.closed = true; | tag.closed = true; | ||||
| m.OnPrepareImage(tag, m.RenderingTitledImage); | m.OnPrepareImage(tag, m.RenderingTitledImage); | ||||
| @@ -220,7 +208,7 @@ namespace MarkdownDeep | |||||
| return null; | return null; | ||||
| // Unescape it | // Unescape it | ||||
| r.url = Utils.UnescapeString(url.Trim(), ExtraMode); | |||||
| r.Url = Utils.UnescapeString(url.Trim(), ExtraMode); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -247,7 +235,7 @@ namespace MarkdownDeep | |||||
| p.SkipEscapableChar(ExtraMode); | p.SkipEscapableChar(ExtraMode); | ||||
| } | } | ||||
| r.url = Utils.UnescapeString(p.Extract().Trim(), ExtraMode); | |||||
| r.Url = Utils.UnescapeString(p.Extract().Trim(), ExtraMode); | |||||
| } | } | ||||
| p.SkipLinespace(); | p.SkipLinespace(); | ||||
| @@ -329,7 +317,7 @@ namespace MarkdownDeep | |||||
| } | } | ||||
| // Store the title | // Store the title | ||||
| r.title = Utils.UnescapeString(p.Extract(), ExtraMode); | |||||
| r.Title = Utils.UnescapeString(p.Extract(), ExtraMode); | |||||
| // Skip closing quote | // Skip closing quote | ||||
| p.SkipForward(1); | p.SkipForward(1); | ||||
| @@ -337,5 +325,49 @@ namespace MarkdownDeep | |||||
| // Done! | // Done! | ||||
| return r; | return r; | ||||
| } | } | ||||
| private static void HandleSpecialAttributes(List<string> specialAttributes, StringBuilder sb, HtmlTag tag) | |||||
| { | |||||
| string id = specialAttributes.FirstOrDefault(s => s.StartsWith("#")); | |||||
| if(id != null && id.Length > 1) | |||||
| { | |||||
| sb.Length = 0; | |||||
| Utils.SmartHtmlEncodeAmpsAndAngles(sb, id.Substring(1)); | |||||
| tag.attributes["id"] = sb.ToString(); | |||||
| } | |||||
| var cssClasses = new List<string>(); | |||||
| foreach(var cssClass in specialAttributes.Where(s => s.StartsWith(".") && s.Length > 1)) | |||||
| { | |||||
| sb.Length = 0; | |||||
| Utils.SmartHtmlEncodeAmpsAndAngles(sb, cssClass.Substring(1)); | |||||
| cssClasses.Add(sb.ToString()); | |||||
| } | |||||
| if(cssClasses.Any()) | |||||
| { | |||||
| tag.attributes["class"] = string.Join(" ", cssClasses.ToArray()); | |||||
| } | |||||
| foreach(var nameValuePair in specialAttributes.Where(s => s.Contains("=") && s.Length > 2 && !s.StartsWith(".") && !s.StartsWith("#"))) | |||||
| { | |||||
| var pair = nameValuePair.Split('='); | |||||
| if(pair.Length == 2) | |||||
| { | |||||
| sb.Length = 0; | |||||
| Utils.SmartHtmlEncodeAmpsAndAngles(sb, pair[0]); | |||||
| var key = sb.ToString(); | |||||
| sb.Length = 0; | |||||
| Utils.SmartHtmlEncodeAmpsAndAngles(sb, pair[1]); | |||||
| var value = sb.ToString(); | |||||
| tag.attributes[key] = value; | |||||
| } | |||||
| } | |||||
| } | |||||
| #region Properties | |||||
| public string Id { get; set; } | |||||
| public string Url { get; set; } | |||||
| public string Title { get; set; } | |||||
| #endregion | |||||
| } | } | ||||
| } | } | ||||
| @@ -21,14 +21,36 @@ namespace MarkdownDeep | |||||
| { | { | ||||
| internal class LinkInfo | internal class LinkInfo | ||||
| { | { | ||||
| public LinkInfo(LinkDefinition def, string link_text) | |||||
| public LinkInfo(LinkDefinition def, string link_text, List<string> specialAttributes ) | |||||
| { | { | ||||
| this.def = def; | |||||
| this.link_text = link_text; | |||||
| this.Definition = def; | |||||
| this.LinkText = link_text; | |||||
| this.SpecialAttributes = new List<string>(); | |||||
| if(specialAttributes != null) | |||||
| { | |||||
| this.SpecialAttributes.AddRange(specialAttributes); | |||||
| } | |||||
| } | } | ||||
| public LinkDefinition def; | |||||
| public string link_text; | |||||
| public void RenderLink(Markdown m, StringBuilder sb) | |||||
| { | |||||
| var sf = new SpanFormatter(m); | |||||
| sf.DisableLinks = true; | |||||
| this.Definition.RenderLink(m, sb, sf.Format(this.LinkText), this.SpecialAttributes); | |||||
| } | |||||
| public void RenderImage(Markdown m, StringBuilder sb) | |||||
| { | |||||
| this.Definition.RenderImg(m, sb, this.LinkText, this.SpecialAttributes); | |||||
| } | |||||
| public LinkDefinition Definition { get; set; } | |||||
| public string LinkText { get; set; } | |||||
| public List<string> SpecialAttributes { get; private set; } | |||||
| } | } | ||||
| } | } | ||||
| @@ -568,7 +568,7 @@ namespace MarkdownDeep | |||||
| internal void AddLinkDefinition(LinkDefinition link) | internal void AddLinkDefinition(LinkDefinition link) | ||||
| { | { | ||||
| // Store it | // Store it | ||||
| m_LinkDefinitions[link.id]=link; | |||||
| m_LinkDefinitions[link.Id]=link; | |||||
| } | } | ||||
| internal void AddFootnote(Block footnote) | internal void AddFootnote(Block footnote) | ||||
| @@ -38,7 +38,7 @@ namespace MarkdownDeep | |||||
| // If the image is a titled image and there's a class defined for titled images, we'll render it using special markup, otherwise we'll render | // If the image is a titled image and there's a class defined for titled images, we'll render it using special markup, otherwise we'll render | ||||
| // the image as-is. | // the image as-is. | ||||
| if (m_Tokens.Count == 1 && !string.IsNullOrWhiteSpace(m_Markdown.HtmlClassTitledImages) && m_Tokens[0].type == TokenType.img && | if (m_Tokens.Count == 1 && !string.IsNullOrWhiteSpace(m_Markdown.HtmlClassTitledImages) && m_Tokens[0].type == TokenType.img && | ||||
| m_Tokens[0].data is LinkInfo && !string.IsNullOrWhiteSpace(((LinkInfo)m_Tokens[0].data).def.title)) | |||||
| m_Tokens[0].data is LinkInfo && !string.IsNullOrWhiteSpace(((LinkInfo)m_Tokens[0].data).Definition.Title)) | |||||
| { | { | ||||
| // Grab the link info | // Grab the link info | ||||
| LinkInfo li = (LinkInfo)m_Tokens[0].data; | LinkInfo li = (LinkInfo)m_Tokens[0].data; | ||||
| @@ -55,10 +55,10 @@ namespace MarkdownDeep | |||||
| dest.Append("\n"); | dest.Append("\n"); | ||||
| // Render the title | // Render the title | ||||
| if (!String.IsNullOrEmpty(li.def.title)) | |||||
| if (!String.IsNullOrEmpty(li.Definition.Title)) | |||||
| { | { | ||||
| dest.Append("<p>"); | dest.Append("<p>"); | ||||
| Utils.SmartHtmlEncodeAmpsAndAngles(dest, li.def.title); | |||||
| Utils.SmartHtmlEncodeAmpsAndAngles(dest, li.Definition.Title); | |||||
| dest.Append("</p>\n"); | dest.Append("</p>\n"); | ||||
| } | } | ||||
| @@ -128,7 +128,7 @@ namespace MarkdownDeep | |||||
| case TokenType.link: | case TokenType.link: | ||||
| LinkInfo li = (LinkInfo)t.data; | LinkInfo li = (LinkInfo)t.data; | ||||
| sb.Append(li.link_text); | |||||
| sb.Append(li.LinkText); | |||||
| break; | break; | ||||
| } | } | ||||
| @@ -222,17 +222,14 @@ namespace MarkdownDeep | |||||
| case TokenType.link: | case TokenType.link: | ||||
| { | { | ||||
| LinkInfo li = (LinkInfo)t.data; | LinkInfo li = (LinkInfo)t.data; | ||||
| var sf = new SpanFormatter(m_Markdown); | |||||
| sf.DisableLinks = true; | |||||
| li.def.RenderLink(m_Markdown, sb, sf.Format(li.link_text)); | |||||
| li.RenderLink(m_Markdown, sb); | |||||
| break; | break; | ||||
| } | } | ||||
| case TokenType.img: | case TokenType.img: | ||||
| { | { | ||||
| LinkInfo li = (LinkInfo)t.data; | LinkInfo li = (LinkInfo)t.data; | ||||
| li.def.RenderImg(m_Markdown, sb, li.link_text); | |||||
| li.RenderImage(m_Markdown, sb); | |||||
| break; | break; | ||||
| } | } | ||||
| @@ -312,14 +309,14 @@ namespace MarkdownDeep | |||||
| case TokenType.link: | case TokenType.link: | ||||
| { | { | ||||
| LinkInfo li = (LinkInfo)t.data; | LinkInfo li = (LinkInfo)t.data; | ||||
| sb.Append(li.link_text); | |||||
| sb.Append(li.LinkText); | |||||
| break; | break; | ||||
| } | } | ||||
| case TokenType.img: | case TokenType.img: | ||||
| { | { | ||||
| LinkInfo li = (LinkInfo)t.data; | LinkInfo li = (LinkInfo)t.data; | ||||
| sb.Append(li.link_text); | |||||
| sb.Append(li.LinkText); | |||||
| break; | break; | ||||
| } | } | ||||
| @@ -922,11 +919,11 @@ namespace MarkdownDeep | |||||
| url = "mailto:" + url; | url = "mailto:" + url; | ||||
| } | } | ||||
| li = new LinkInfo(new LinkDefinition("auto", url, null), link_text); | |||||
| li = new LinkInfo(new LinkDefinition("auto", url, null), link_text, null); | |||||
| } | } | ||||
| else if (Utils.IsWebAddress(url)) | else if (Utils.IsWebAddress(url)) | ||||
| { | { | ||||
| li=new LinkInfo(new LinkDefinition("auto", url, null), url); | |||||
| li=new LinkInfo(new LinkDefinition("auto", url, null), url, null); | |||||
| } | } | ||||
| if (li!=null) | if (li!=null) | ||||
| @@ -981,7 +978,7 @@ namespace MarkdownDeep | |||||
| if (DisableLinks && token_type==TokenType.link) | if (DisableLinks && token_type==TokenType.link) | ||||
| return null; | return null; | ||||
| bool ExtraMode = m_Markdown.ExtraMode; | |||||
| bool extraMode = m_Markdown.ExtraMode; | |||||
| // Find the closing square bracket, allowing for nesting, watching for | // Find the closing square bracket, allowing for nesting, watching for | ||||
| // escapable characters | // escapable characters | ||||
| @@ -1001,7 +998,7 @@ namespace MarkdownDeep | |||||
| break; | break; | ||||
| } | } | ||||
| this.SkipEscapableChar(ExtraMode); | |||||
| this.SkipEscapableChar(extraMode); | |||||
| } | } | ||||
| // Quit if end | // Quit if end | ||||
| @@ -1009,7 +1006,7 @@ namespace MarkdownDeep | |||||
| return null; | return null; | ||||
| // Get the link text and unescape it | // Get the link text and unescape it | ||||
| string link_text = Utils.UnescapeString(Extract(), ExtraMode); | |||||
| string link_text = Utils.UnescapeString(Extract(), extraMode); | |||||
| // The closing ']' | // The closing ']' | ||||
| SkipForward(1); | SkipForward(1); | ||||
| @@ -1030,8 +1027,19 @@ namespace MarkdownDeep | |||||
| if (!SkipChar(')')) | if (!SkipChar(')')) | ||||
| return null; | return null; | ||||
| List<string> specialAttributes = null; | |||||
| if(extraMode && DoesMatch('{')) | |||||
| { | |||||
| int end; | |||||
| specialAttributes = Utils.StripSpecialAttributes(this.Input, this.Position, out end); | |||||
| if(specialAttributes != null) | |||||
| { | |||||
| Position = end; | |||||
| } | |||||
| } | |||||
| // Create the token | // Create the token | ||||
| return CreateToken(token_type, new LinkInfo(link_def, link_text)); | |||||
| return CreateToken(token_type, new LinkInfo(link_def, link_text, specialAttributes)); | |||||
| } | } | ||||
| // Optional space or tab | // Optional space or tab | ||||
| @@ -1091,8 +1099,9 @@ namespace MarkdownDeep | |||||
| if (def == null) | if (def == null) | ||||
| return null; | return null; | ||||
| // Create a token | |||||
| return CreateToken(token_type, new LinkInfo(def, link_text)); | |||||
| // Create a token. | |||||
| // [FB]: Currently not supported: special attributes on reference links. | |||||
| return CreateToken(token_type, new LinkInfo(def, link_text, null)); | |||||
| } | } | ||||
| // Process a ``` code span ``` | // Process a ``` code span ``` | ||||
| @@ -1175,7 +1184,7 @@ namespace MarkdownDeep | |||||
| #endregion | #endregion | ||||
| Markdown m_Markdown; | |||||
| private Markdown m_Markdown; | |||||
| internal bool DisableLinks; | internal bool DisableLinks; | ||||
| List<Token> m_Tokens=new List<Token>(); | List<Token> m_Tokens=new List<Token>(); | ||||
| } | } | ||||
| @@ -486,6 +486,50 @@ namespace MarkdownDeep | |||||
| return strID; | return strID; | ||||
| } | } | ||||
| /// <summary> | |||||
| /// Strips the special attributes specified at the location of start. Special attributes are a php markdown extension | |||||
| /// and specified between {}. Attributes are separated with spaces. It recognizes the following attributes: | |||||
| /// id, which start with a '#'. Only the first one is used | |||||
| /// css classes, which start with a'.'. All specified are used | |||||
| /// name=value pairs, which will end up as attributes on the element. | |||||
| /// </summary> | |||||
| /// <param name="str">The string we're scanning.</param> | |||||
| /// <param name="start">The start (current) position.</param> | |||||
| /// <param name="end">The end position. Is only valid if returned list contains at least one value.</param> | |||||
| /// <returns>list of special attributes found, or null if none found or error in string format.</returns> | |||||
| public static List<string> StripSpecialAttributes(string str, int start, out int end) | |||||
| { | |||||
| end = start; | |||||
| var scanner = new StringScanner(str, start); | |||||
| if(!scanner.DoesMatch('{')) | |||||
| { | |||||
| // not a start of a special attribute block | |||||
| return null; | |||||
| } | |||||
| // first find the end of the block, | |||||
| scanner.SkipForward(1); | |||||
| var startOfAttributes = scanner.Position; | |||||
| // first find the next EOL, as the closing } has to be on this line. | |||||
| scanner.SkipToEol(); | |||||
| var nextEolPos = scanner.Position; | |||||
| scanner.Position = startOfAttributes; | |||||
| scanner.Mark(); | |||||
| if(!scanner.Find('}') || scanner.Position >= nextEolPos) | |||||
| { | |||||
| // not enclosed properly. | |||||
| return null; | |||||
| } | |||||
| var attributesString = scanner.Extract(); | |||||
| if(string.IsNullOrWhiteSpace(attributesString)) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| // Position is on enclosing '}' (due to the Find('}'), so we have to skip 1 character | |||||
| end = scanner.Position + 1; | |||||
| return attributesString.Split(' ').Where(s=>!string.IsNullOrWhiteSpace(s)).ToList(); | |||||
| } | |||||
| public static bool IsUrlFullyQualified(string url) | public static bool IsUrlFullyQualified(string url) | ||||
| { | { | ||||
| return url.Contains("://") || url.StartsWith("mailto:"); | return url.Contains("://") || url.StartsWith("mailto:"); | ||||
| @@ -10,85 +10,104 @@ namespace MarkdownDeepTests | |||||
| [TestFixture] | [TestFixture] | ||||
| class LinkAndImgTests | class LinkAndImgTests | ||||
| { | { | ||||
| SpanFormatter _formatter; | |||||
| [SetUp] | [SetUp] | ||||
| public void SetUp() | public void SetUp() | ||||
| { | { | ||||
| m = new Markdown(); | |||||
| m.AddLinkDefinition(new LinkDefinition("link1", "url.com", "title")); | |||||
| m.AddLinkDefinition(new LinkDefinition("link2", "url.com")); | |||||
| m.AddLinkDefinition(new LinkDefinition("img1", "url.com/image.png", "title")); | |||||
| m.AddLinkDefinition(new LinkDefinition("img2", "url.com/image.png")); | |||||
| _formatter = new SpanFormatter(GetSetupMarkdown()); | |||||
| } | |||||
| [Test] | |||||
| public void InlineLinkWithoutTitleWithSpecialAttributes() | |||||
| { | |||||
| var m = GetSetupMarkdown(); | |||||
| m.ExtraMode = true; | |||||
| var s = new SpanFormatter(m); | |||||
| Assert.AreEqual("pre <a href=\"url.com\" id=\"foo\" class=\"a b cl\" lang=\"nl\">link text</a> post", | |||||
| s.Format("pre [link text](url.com){#foo .a .b .cl lang=nl} post")); | |||||
| } | |||||
| s = new SpanFormatter(m); | |||||
| [Test] | |||||
| public void InlineImgWithoutTitleWithSpecialAttributes() | |||||
| { | |||||
| var m = GetSetupMarkdown(); | |||||
| m.ExtraMode = true; | |||||
| var s = new SpanFormatter(m); | |||||
| Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" id=\"foo\" class=\"a b cl\" lang=\"nl\" /> post", | |||||
| s.Format("pre {#foo .a .b .cl lang=nl} post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void ReferenceLinkWithTitle() | public void ReferenceLinkWithTitle() | ||||
| { | { | ||||
| Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link text</a> post", | Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link text</a> post", | ||||
| s.Format("pre [link text][link1] post")); | |||||
| _formatter.Format("pre [link text][link1] post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void ReferenceLinkIdsAreCaseInsensitive() | public void ReferenceLinkIdsAreCaseInsensitive() | ||||
| { | { | ||||
| Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link text</a> post", | Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link text</a> post", | ||||
| s.Format("pre [link text][LINK1] post")); | |||||
| _formatter.Format("pre [link text][LINK1] post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void ImplicitReferenceLinkWithoutTitle() | public void ImplicitReferenceLinkWithoutTitle() | ||||
| { | { | ||||
| Assert.AreEqual("pre <a href=\"url.com\">link2</a> post", | Assert.AreEqual("pre <a href=\"url.com\">link2</a> post", | ||||
| s.Format("pre [link2] post")); | |||||
| _formatter.Format("pre [link2] post")); | |||||
| Assert.AreEqual("pre <a href=\"url.com\">link2</a> post", | Assert.AreEqual("pre <a href=\"url.com\">link2</a> post", | ||||
| s.Format("pre [link2][] post")); | |||||
| _formatter.Format("pre [link2][] post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void ImplicitReferenceLinkWithTitle() | public void ImplicitReferenceLinkWithTitle() | ||||
| { | { | ||||
| Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link1</a> post", | Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link1</a> post", | ||||
| s.Format("pre [link1] post")); | |||||
| _formatter.Format("pre [link1] post")); | |||||
| Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link1</a> post", | Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link1</a> post", | ||||
| s.Format("pre [link1][] post")); | |||||
| _formatter.Format("pre [link1][] post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void ReferenceLinkWithoutTitle() | public void ReferenceLinkWithoutTitle() | ||||
| { | { | ||||
| Assert.AreEqual("pre <a href=\"url.com\">link text</a> post", | Assert.AreEqual("pre <a href=\"url.com\">link text</a> post", | ||||
| s.Format("pre [link text][link2] post")); | |||||
| _formatter.Format("pre [link text][link2] post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void MissingReferenceLink() | public void MissingReferenceLink() | ||||
| { | { | ||||
| Assert.AreEqual("pre [link text][missing] post", | Assert.AreEqual("pre [link text][missing] post", | ||||
| s.Format("pre [link text][missing] post")); | |||||
| _formatter.Format("pre [link text][missing] post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void InlineLinkWithTitle() | public void InlineLinkWithTitle() | ||||
| { | { | ||||
| Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link text</a> post", | Assert.AreEqual("pre <a href=\"url.com\" title=\"title\">link text</a> post", | ||||
| s.Format("pre [link text](url.com \"title\") post")); | |||||
| _formatter.Format("pre [link text](url.com \"title\") post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void InlineLinkWithoutTitle() | public void InlineLinkWithoutTitle() | ||||
| { | { | ||||
| Assert.AreEqual("pre <a href=\"url.com\">link text</a> post", | Assert.AreEqual("pre <a href=\"url.com\">link text</a> post", | ||||
| s.Format("pre [link text](url.com) post")); | |||||
| _formatter.Format("pre [link text](url.com) post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void Boundaries() | public void Boundaries() | ||||
| { | { | ||||
| Assert.AreEqual("<a href=\"url.com\">link text</a>", | Assert.AreEqual("<a href=\"url.com\">link text</a>", | ||||
| s.Format("[link text](url.com)")); | |||||
| _formatter.Format("[link text](url.com)")); | |||||
| Assert.AreEqual("<a href=\"url.com\" title=\"title\">link text</a>", | Assert.AreEqual("<a href=\"url.com\" title=\"title\">link text</a>", | ||||
| s.Format("[link text][link1]")); | |||||
| _formatter.Format("[link text][link1]")); | |||||
| } | } | ||||
| @@ -96,53 +115,53 @@ namespace MarkdownDeepTests | |||||
| public void ReferenceImgWithTitle() | public void ReferenceImgWithTitle() | ||||
| { | { | ||||
| Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" title=\"title\" /> post", | Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" title=\"title\" /> post", | ||||
| s.Format("pre ![alt text][img1] post")); | |||||
| _formatter.Format("pre ![alt text][img1] post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void ImplicitReferenceImgWithoutTitle() | public void ImplicitReferenceImgWithoutTitle() | ||||
| { | { | ||||
| Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"img2\" /> post", | Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"img2\" /> post", | ||||
| s.Format("pre ![img2] post")); | |||||
| _formatter.Format("pre ![img2] post")); | |||||
| Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"img2\" /> post", | Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"img2\" /> post", | ||||
| s.Format("pre ![img2][] post")); | |||||
| _formatter.Format("pre ![img2][] post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void ImplicitReferenceImgWithTitle() | public void ImplicitReferenceImgWithTitle() | ||||
| { | { | ||||
| Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"img1\" title=\"title\" /> post", | Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"img1\" title=\"title\" /> post", | ||||
| s.Format("pre ![img1] post")); | |||||
| _formatter.Format("pre ![img1] post")); | |||||
| Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"img1\" title=\"title\" /> post", | Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"img1\" title=\"title\" /> post", | ||||
| s.Format("pre ![img1][] post")); | |||||
| _formatter.Format("pre ![img1][] post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void ReferenceImgWithoutTitle() | public void ReferenceImgWithoutTitle() | ||||
| { | { | ||||
| Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" /> post", | Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" /> post", | ||||
| s.Format("pre ![alt text][img2] post")); | |||||
| _formatter.Format("pre ![alt text][img2] post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void MissingReferenceImg() | public void MissingReferenceImg() | ||||
| { | { | ||||
| Assert.AreEqual("pre ![alt text][missing] post", | Assert.AreEqual("pre ![alt text][missing] post", | ||||
| s.Format("pre ![alt text][missing] post")); | |||||
| _formatter.Format("pre ![alt text][missing] post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void InlineImgWithTitle() | public void InlineImgWithTitle() | ||||
| { | { | ||||
| Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" title=\"title\" /> post", | Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" title=\"title\" /> post", | ||||
| s.Format("pre  post")); | |||||
| _formatter.Format("pre  post")); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| public void InlineImgWithoutTitle() | public void InlineImgWithoutTitle() | ||||
| { | { | ||||
| Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" /> post", | Assert.AreEqual("pre <img src=\"url.com/image.png\" alt=\"alt text\" /> post", | ||||
| s.Format("pre  post")); | |||||
| _formatter.Format("pre  post")); | |||||
| } | } | ||||
| @@ -150,10 +169,19 @@ namespace MarkdownDeepTests | |||||
| public void ImageLink() | public void ImageLink() | ||||
| { | { | ||||
| Assert.AreEqual("pre <a href=\"url.com\"><img src=\"url.com/image.png\" alt=\"alt text\" /></a> post", | Assert.AreEqual("pre <a href=\"url.com\"><img src=\"url.com/image.png\" alt=\"alt text\" /></a> post", | ||||
| s.Format("pre [](url.com) post")); | |||||
| _formatter.Format("pre [](url.com) post")); | |||||
| } | |||||
| private Markdown GetSetupMarkdown() | |||||
| { | |||||
| var toReturn = new Markdown(); | |||||
| toReturn.AddLinkDefinition(new LinkDefinition("link1", "url.com", "title")); | |||||
| toReturn.AddLinkDefinition(new LinkDefinition("link2", "url.com")); | |||||
| toReturn.AddLinkDefinition(new LinkDefinition("img1", "url.com/image.png", "title")); | |||||
| toReturn.AddLinkDefinition(new LinkDefinition("img2", "url.com/image.png")); | |||||
| return toReturn; | |||||
| } | } | ||||
| Markdown m; | |||||
| SpanFormatter s; | |||||
| } | } | ||||
| } | } | ||||
| @@ -23,9 +23,9 @@ namespace MarkdownDeepTests | |||||
| r = LinkDefinition.ParseLinkDefinition(str, false); | r = LinkDefinition.ParseLinkDefinition(str, false); | ||||
| Assert.IsNotNull(r); | Assert.IsNotNull(r); | ||||
| Assert.AreEqual(r.id, "id"); | |||||
| Assert.AreEqual(r.url, "url.com"); | |||||
| Assert.AreEqual(r.title, null); | |||||
| Assert.AreEqual(r.Id, "id"); | |||||
| Assert.AreEqual(r.Url, "url.com"); | |||||
| Assert.AreEqual(r.Title, string.Empty); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| @@ -35,9 +35,9 @@ namespace MarkdownDeepTests | |||||
| r = LinkDefinition.ParseLinkDefinition(str, false); | r = LinkDefinition.ParseLinkDefinition(str, false); | ||||
| Assert.IsNotNull(r); | Assert.IsNotNull(r); | ||||
| Assert.AreEqual(r.id, "id"); | |||||
| Assert.AreEqual(r.url, "url.com"); | |||||
| Assert.AreEqual(r.title, "my title"); | |||||
| Assert.AreEqual(r.Id, "id"); | |||||
| Assert.AreEqual(r.Url, "url.com"); | |||||
| Assert.AreEqual(r.Title, "my title"); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| @@ -47,9 +47,9 @@ namespace MarkdownDeepTests | |||||
| r = LinkDefinition.ParseLinkDefinition(str, false); | r = LinkDefinition.ParseLinkDefinition(str, false); | ||||
| Assert.IsNotNull(r); | Assert.IsNotNull(r); | ||||
| Assert.AreEqual(r.id, "id"); | |||||
| Assert.AreEqual(r.url, "url.com"); | |||||
| Assert.AreEqual(r.title, "my title"); | |||||
| Assert.AreEqual(r.Id, "id"); | |||||
| Assert.AreEqual(r.Url, "url.com"); | |||||
| Assert.AreEqual(r.Title, "my title"); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| @@ -59,9 +59,9 @@ namespace MarkdownDeepTests | |||||
| r = LinkDefinition.ParseLinkDefinition(str, false); | r = LinkDefinition.ParseLinkDefinition(str, false); | ||||
| Assert.IsNotNull(r); | Assert.IsNotNull(r); | ||||
| Assert.AreEqual(r.id, "id"); | |||||
| Assert.AreEqual(r.url, "url.com"); | |||||
| Assert.AreEqual(r.title, "my title"); | |||||
| Assert.AreEqual(r.Id, "id"); | |||||
| Assert.AreEqual(r.Url, "url.com"); | |||||
| Assert.AreEqual(r.Title, "my title"); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| @@ -71,9 +71,9 @@ namespace MarkdownDeepTests | |||||
| r = LinkDefinition.ParseLinkDefinition(str, false); | r = LinkDefinition.ParseLinkDefinition(str, false); | ||||
| Assert.IsNotNull(r); | Assert.IsNotNull(r); | ||||
| Assert.AreEqual(r.id, "id"); | |||||
| Assert.AreEqual(r.url, "url.com"); | |||||
| Assert.AreEqual(r.title, "my title"); | |||||
| Assert.AreEqual(r.Id, "id"); | |||||
| Assert.AreEqual(r.Url, "url.com"); | |||||
| Assert.AreEqual(r.Title, "my title"); | |||||
| } | } | ||||
| [Test] | [Test] | ||||
| @@ -83,9 +83,9 @@ namespace MarkdownDeepTests | |||||
| r = LinkDefinition.ParseLinkDefinition(str, false); | r = LinkDefinition.ParseLinkDefinition(str, false); | ||||
| Assert.IsNotNull(r); | Assert.IsNotNull(r); | ||||
| Assert.AreEqual(r.id, "id"); | |||||
| Assert.AreEqual(r.url, "http://www.site.com"); | |||||
| Assert.AreEqual(r.title, "my title"); | |||||
| Assert.AreEqual(r.Id, "id"); | |||||
| Assert.AreEqual(r.Url, "http://www.site.com"); | |||||
| Assert.AreEqual(r.Title, "my title"); | |||||
| } | } | ||||
| [Test] | [Test] | ||||