internal void RenderImg(Markdown m, StringBuilder b, string alt_text, List <string> specialAttributes) { HtmlTag tag = new HtmlTag("img"); // encode url StringBuilder sb = m.GetStringBuilder(); Utils.SmartHtmlEncodeAmpsAndAngles(sb, Url); tag.attributes["src"] = sb.ToString(); // encode alt text if (!String.IsNullOrEmpty(alt_text)) { sb.Length = 0; Utils.SmartHtmlEncodeAmpsAndAngles(sb, alt_text); tag.attributes["alt"] = sb.ToString(); } // encode title if (!String.IsNullOrEmpty(Title)) { sb.Length = 0; Utils.SmartHtmlEncodeAmpsAndAngles(sb, Title); tag.attributes["title"] = sb.ToString(); } if (specialAttributes.Any()) { LinkDefinition.HandleSpecialAttributes(specialAttributes, sb, tag); } tag.closed = true; m.OnPrepareImage(tag, m.RenderingTitledImage); tag.RenderOpening(b); }
public void DoubleQuoteTitle() { r = LinkDefinition.ParseLinkDefinition("[id]: url.com \"my title\"", false); Assert.IsNotNull(r); Assert.AreEqual(r.ID, "id"); Assert.AreEqual(r.Url, "url.com"); Assert.AreEqual(r.Title, "my title"); }
public void ParenthesizedTitle() { r = LinkDefinition.ParseLinkDefinition("[id]: url.com (my title)", false); Assert.IsNotNull(r); Assert.AreEqual(r.ID, "id"); Assert.AreEqual(r.Url, "url.com"); Assert.AreEqual(r.Title, "my title"); }
public void NoTitle() { r = LinkDefinition.ParseLinkDefinition("[id]: url.com", false); Assert.IsNotNull(r); Assert.AreEqual(r.ID, "id"); Assert.AreEqual(r.Url, "url.com"); Assert.AreEqual(r.Title, null); }
public void MultiLine() { r = LinkDefinition.ParseLinkDefinition("[id]:\n\t http://www.site.com \n\t (my title)", false); Assert.IsNotNull(r); Assert.AreEqual(r.ID, "id"); Assert.AreEqual(r.Url, "http://www.site.com"); Assert.AreEqual(r.Title, "my title"); }
public void AngleBracketedUrl() { r = LinkDefinition.ParseLinkDefinition("[id]: <url.com> (my title)", false); Assert.IsNotNull(r); Assert.AreEqual(r.ID, "id"); Assert.AreEqual(r.Url, "url.com"); Assert.AreEqual(r.Title, "my title"); }
public LinkInfo(LinkDefinition def, string link_text, List<string> specialAttributes ) { this.Definition = def; this.LinkText = link_text; this.SpecialAttributes = new List<string>(); if(specialAttributes != null) { this.SpecialAttributes.AddRange(specialAttributes); } }
public void AngleBracketedUrl() { string str = "[id]: <url.com> (my title)"; r = LinkDefinition.ParseLinkDefinition(str, false); Assert.IsNotNull(r); Assert.AreEqual(r.id, "id"); Assert.AreEqual(r.url, "url.com"); Assert.AreEqual(r.title, "my title"); }
public LinkInfo(LinkDefinition def, string link_text, List <string> specialAttributes) { this.Definition = def; this.LinkText = link_text; this.SpecialAttributes = new List <string>(); if (specialAttributes != null) { this.SpecialAttributes.AddRange(specialAttributes); } }
public void DoubleQuoteTitle() { string str = "[id]: url.com \"my title\""; r = LinkDefinition.ParseLinkDefinition(str, false); Assert.IsNotNull(r); Assert.AreEqual(r.id, "id"); Assert.AreEqual(r.url, "url.com"); Assert.AreEqual(r.title, "my title"); }
public void NoTitle() { string str = "[id]: url.com"; r = LinkDefinition.ParseLinkDefinition(str, false); Assert.IsNotNull(r); Assert.AreEqual(r.Id, "id"); Assert.AreEqual(r.Url, "url.com"); Assert.AreEqual(r.Title, string.Empty); }
public void MultiLine() { string str = "[id]:\n\t http://www.site.com \n\t (my title)"; r = LinkDefinition.ParseLinkDefinition(str, false); Assert.IsNotNull(r); Assert.AreEqual(r.id, "id"); Assert.AreEqual(r.url, "http://www.site.com"); Assert.AreEqual(r.title, "my title"); }
public void NoTitle() { string str = "[id]: url.com"; r = LinkDefinition.ParseLinkDefinition(str, false); Assert.IsNotNull(r); Assert.AreEqual(r.id, "id"); Assert.AreEqual(r.url, "url.com"); Assert.AreEqual(r.title, null); }
internal void RenderLink(Markdown m, StringBuilder b, string link_text, List <string> specialAttributes) { if (this.Url.StartsWith("mailto:")) { b.Append("<a href=\""); Utils.HtmlRandomize(b, this.Url); b.Append('\"'); if (!String.IsNullOrEmpty(this.Title)) { b.Append(" title=\""); Utils.SmartHtmlEncodeAmpsAndAngles(b, this.Title); b.Append('\"'); } b.Append('>'); Utils.HtmlRandomize(b, link_text); b.Append("</a>"); } else { HtmlTag tag = new HtmlTag("a"); // encode url StringBuilder sb = m.GetStringBuilder(); Utils.SmartHtmlEncodeAmpsAndAngles(sb, this.Url); tag.attributes["href"] = sb.ToString(); // encode title if (!String.IsNullOrEmpty(this.Title)) { sb.Length = 0; Utils.SmartHtmlEncodeAmpsAndAngles(sb, this.Title); tag.attributes["title"] = sb.ToString(); } if (specialAttributes.Any()) { LinkDefinition.HandleSpecialAttributes(specialAttributes, sb, tag); } // Do user processing m.OnPrepareLink(tag); // Render the opening tag tag.RenderOpening(b); b.Append(link_text); // Link text already escaped by SpanFormatter b.Append("</a>"); } }
// Parse just the link target // For reference link definition, this is the bit after "[id]: thisbit" // For inline link, this is the bit in the parens: [link text](thisbit) internal static LinkDefinition ParseLinkTarget(StringScanner p, string id, bool ExtraMode) { // Skip whitespace p.SkipWhitespace(); // End of string? if (p.eol) { return(null); } // Create the link definition var r = new LinkDefinition(id); // Is the url enclosed in angle brackets if (p.SkipChar('<')) { // Extract the url p.Mark(); // Find end of the url while (p.current != '>') { if (p.eof) { return(null); } p.SkipEscapableChar(ExtraMode); } string url = p.Extract(); if (!p.SkipChar('>')) { return(null); } // Unescape it r.url = Utils.UnescapeString(url.Trim(), ExtraMode); // Skip whitespace p.SkipWhitespace(); } else { // Find end of the url p.Mark(); int paren_depth = 1; while (!p.eol) { char ch = p.current; if (char.IsWhiteSpace(ch)) { break; } if (id == null) { if (ch == '(') { paren_depth++; } else if (ch == ')') { paren_depth--; if (paren_depth == 0) { break; } } } p.SkipEscapableChar(ExtraMode); } r.url = Utils.UnescapeString(p.Extract().Trim(), ExtraMode); } p.SkipLinespace(); // End of inline target if (p.DoesMatch(')')) { return(r); } bool bOnNewLine = p.eol; int posLineEnd = p.position; if (p.eol) { p.SkipEol(); p.SkipLinespace(); } // Work out what the title is delimited with char delim; switch (p.current) { case '\'': case '\"': delim = p.current; break; case '(': delim = ')'; break; default: if (bOnNewLine) { p.position = posLineEnd; return(r); } else { return(null); } } // Skip the opening title delimiter p.SkipForward(1); // Find the end of the title p.Mark(); while (true) { if (p.eol) { return(null); } if (p.current == delim) { if (delim != ')') { int savepos = p.position; // Check for embedded quotes in title // Skip the quote and any trailing whitespace p.SkipForward(1); p.SkipLinespace(); // Next we expect either the end of the line for a link definition // or the close bracket for an inline link if ((id == null && p.current != ')') || (id != null && !p.eol)) { continue; } p.position = savepos; } // End of title break; } p.SkipEscapableChar(ExtraMode); } // Store the title r.title = Utils.UnescapeString(p.Extract(), ExtraMode); // Skip closing quote p.SkipForward(1); // Done! return(r); }
// Process [link] and ![image] directives Token ProcessLinkOrImageOrFootnote() { // Link or image? TokenType token_type = SkipChar('!') ? TokenType.img : TokenType.link; // Opening '[' if (!SkipChar('[')) { return(null); } // Is it a foonote? var savepos = position; if (m_Markdown.ExtraMode && token_type == TokenType.link && SkipChar('^')) { SkipLinespace(); // Parse it string id; if (SkipFootnoteID(out id) && SkipChar(']')) { // Look it up and create footnote reference token int footnote_index = m_Markdown.ClaimFootnote(id); if (footnote_index >= 0) { // Yes it's a footnote return(CreateToken(TokenType.footnote, new FootnoteReference(footnote_index, id))); } } // Rewind position = savepos; } if (DisableLinks && token_type == TokenType.link) { return(null); } bool ExtraMode = m_Markdown.ExtraMode; // Find the closing square bracket, allowing for nesting, watching for // escapable characters Mark(); int depth = 1; while (!eof) { char ch = current; if (ch == '[') { depth++; } else if (ch == ']') { depth--; if (depth == 0) { break; } } this.SkipEscapableChar(ExtraMode); } // Quit if end if (eof) { return(null); } // Get the link text and unescape it string link_text = Utils.UnescapeString(Extract(), ExtraMode); // The closing ']' SkipForward(1); // Save position in case we need to rewind savepos = position; // Inline links must follow immediately if (SkipChar('(')) { // Extract the url and title var link_def = LinkDefinition.ParseLinkTarget(this, null, m_Markdown.ExtraMode); if (link_def == null) { return(null); } // Closing ')' SkipWhitespace(); if (!SkipChar(')')) { return(null); } // Create the token return(CreateToken(token_type, new LinkInfo(link_def, link_text))); } // Optional space or tab if (!SkipChar(' ')) { SkipChar('\t'); } // If there's line end, we're allow it and as must line space as we want // before the link id. if (eol) { SkipEol(); SkipLinespace(); } // Reference link? string link_id = null; if (current == '[') { // Skip the opening '[' SkipForward(1); // Find the start/end of the id Mark(); if (!Find(']')) { return(null); } // Extract the id link_id = Extract(); // Skip closing ']' SkipForward(1); } else { // Rewind to just after the closing ']' position = savepos; } // Link id not specified? if (string.IsNullOrEmpty(link_id)) { // Use the link text (implicit reference link) link_id = Utils.NormalizeLineEnds(link_text); // If the link text has carriage returns, normalize // to spaces if (!object.ReferenceEquals(link_id, link_text)) { while (link_id.Contains(" \n")) { link_id = link_id.Replace(" \n", "\n"); } link_id = link_id.Replace("\n", " "); } } // Find the link definition abort if not defined var def = m_Markdown.GetLinkDefinition(link_id); if (def == null) { return(null); } // Create a token return(CreateToken(token_type, new LinkInfo(def, link_text))); }
// Add a link definition internal void AddLinkDefinition(LinkDefinition link) { // Store it m_LinkDefinitions[link.id]=link; }
// Add a link definition public void AddLinkDefinition(LinkDefinition link) { // Store it m_LinkDefinitions[link.id]=link; }
public LinkInfo(LinkDefinition def, string link_text) { this.def = def; this.link_text = link_text; }
// Add a link definition internal void AddLinkDefinition(LinkDefinition link) { // Store it m_LinkDefinitions[link.id] = link; m_FoundLinks.Add(new LinkInfo(link, null)); }
// Add a link definition internal void AddLinkDefinition(LinkDefinition link) { // Store it _mLinkDefinitions[link.ID] = link; }
public void Setup() { r=null; }
// Add a link definition internal void AddLinkDefinition(LinkDefinition link) { // Store it m_LinkDefinitions[link.id] = link; }
// Add a link definition public void AddLinkDefinition(LinkDefinition link) { // Store it m_LinkDefinitions[link.id] = link; }
internal void RenderLink(Markdown m, StringBuilder b, string link_text, List <string> specialAttributes) { if (this.Url.StartsWith("mailto:")) { b.Append("<a href=\""); Utils.HtmlRandomize(b, this.Url); b.Append('\"'); if (!String.IsNullOrEmpty(this.Title)) { b.Append(" title=\""); Utils.SmartHtmlEncodeAmpsAndAngles(b, this.Title); b.Append('\"'); } b.Append('>'); Utils.HtmlRandomize(b, link_text); b.Append("</a>"); } else { HtmlTag tag = new HtmlTag("a"); var url = this.Url; if (m.DocNetMode && m.ConvertLocalLinks) { // A few requirements before we can convert local links: // 1. Link contains .md // 2. Link is relative // 3. Link is included in the index var index = url.LastIndexOf(".md", StringComparison.OrdinalIgnoreCase); if (index >= 0) { var linkProcessor = m.LocalLinkProcessor; if (linkProcessor != null) { url = linkProcessor(url); } else { Uri uri; if (Uri.TryCreate(url, UriKind.Relative, out uri)) { url = String.Concat(url.Substring(0, index), ".htm", url.Substring(index + ".md".Length)); } } } } // encode url StringBuilder sb = m.GetStringBuilder(); Utils.SmartHtmlEncodeAmpsAndAngles(sb, url); tag.attributes["href"] = sb.ToString(); // encode title if (!String.IsNullOrEmpty(this.Title)) { sb.Length = 0; Utils.SmartHtmlEncodeAmpsAndAngles(sb, this.Title); tag.attributes["title"] = sb.ToString(); } if (specialAttributes.Any()) { LinkDefinition.HandleSpecialAttributes(specialAttributes, sb, tag); } // Do user processing m.OnPrepareLink(tag); // Render the opening tag tag.RenderOpening(b); b.Append(link_text); // Link text already escaped by SpanFormatter b.Append("</a>"); } }
// Add a link definition internal void AddLinkDefinition(LinkDefinition link) { // Store it m_LinkDefinitions[link.id]=link; m_FoundLinks.Add(new LinkInfo(link, null)); }
public void SingleQuoteTitle() { string str = "[id]: url.com \'my title\'"; r = LinkDefinition.ParseLinkDefinition(str, false); Assert.IsNotNull(r); Assert.AreEqual(r.Id, "id"); Assert.AreEqual(r.Url, "url.com"); Assert.AreEqual(r.Title, "my title"); }
// Parse just the link target // For reference link definition, this is the bit after "[id]: thisbit" // For inline link, this is the bit in the parens: [link text](thisbit) internal static LinkDefinition ParseLinkTarget(StringScanner p, string id, bool ExtraMode) { // Skip whitespace p.SkipWhitespace(); // End of string? if (p.eol) return null; // Create the link definition var r = new LinkDefinition(id); // Is the url enclosed in angle brackets if (p.SkipChar('<')) { // Extract the url p.Mark(); // Find end of the url while (p.current != '>') { if (p.eof) return null; p.SkipEscapableChar(ExtraMode); } string url = p.Extract(); if (!p.SkipChar('>')) return null; // Unescape it r.url = Utils.UnescapeString(url.Trim(), ExtraMode); // Skip whitespace p.SkipWhitespace(); } else { // Find end of the url p.Mark(); int paren_depth = 1; while (!p.eol) { char ch=p.current; if (char.IsWhiteSpace(ch)) break; if (id == null) { if (ch == '(') paren_depth++; else if (ch == ')') { paren_depth--; if (paren_depth==0) break; } } p.SkipEscapableChar(ExtraMode); } r.url = Utils.UnescapeString(p.Extract().Trim(), ExtraMode); } p.SkipLinespace(); // End of inline target if (p.DoesMatch(')')) return r; bool bOnNewLine = p.eol; int posLineEnd = p.position; if (p.eol) { p.SkipEol(); p.SkipLinespace(); } // Work out what the title is delimited with char delim; switch (p.current) { case '\'': case '\"': delim = p.current; break; case '(': delim = ')'; break; default: if (bOnNewLine) { p.position = posLineEnd; return r; } else return null; } // Skip the opening title delimiter p.SkipForward(1); // Find the end of the title p.Mark(); while (true) { if (p.eol) return null; if (p.current == delim) { if (delim != ')') { int savepos = p.position; // Check for embedded quotes in title // Skip the quote and any trailing whitespace p.SkipForward(1); p.SkipLinespace(); // Next we expect either the end of the line for a link definition // or the close bracket for an inline link if ((id == null && p.current != ')') || (id != null && !p.eol)) { continue; } p.position = savepos; } // End of title break; } p.SkipEscapableChar(ExtraMode); } // Store the title r.title = Utils.UnescapeString(p.Extract(), ExtraMode); // Skip closing quote p.SkipForward(1); // Done! return r; }
public void ParenthesizedTitle() { string str = "[id]: url.com (my title)"; r = LinkDefinition.ParseLinkDefinition(str, false); Assert.IsNotNull(r); Assert.AreEqual(r.id, "id"); Assert.AreEqual(r.url, "url.com"); Assert.AreEqual(r.title, "my title"); }