/// <summary> /// Gets the next node after the start index /// </summary> /// <param name="code">The code.</param> /// <param name="startIndex">The index from which to start searching.</param> /// <param name="tagType">Returns next tag type</param> /// <param name="previousTag">The previous tag in the stack.</param> /// <param name="isParseContent">If the content of the last opening node should be parsed. In Html all the content is parsed.</param> protected override SyntaxNode GetNextNode(string code, ref int startIndex, out TagType tagType, Tag previousTag, bool isParseContent) { string currentSubstring = code.Substring(startIndex); //in the regex I won't work with h1, h2... and such tags! string regexPattern = previousTag == null || isParseContent ? @"</?[a-zA-Z]+[^<>]*/?>" : @"<" + previousTag.CloseTag + @">"; Match tag = Regex.Match(currentSubstring, regexPattern); Tag registeredTag = null; tagType = TagType.Open; //we just set it here and when needed will do it later while (tag.Success && (registeredTag = GetTagByValue(tag.Value)) == null)//getting tags, but they are not registered. { tag = tag.NextMatch(); } if (!tag.Success) //didn't find a registered tag until the end - return everything left as a text node { startIndex += currentSubstring.Length; return new TextSyntaxNode(currentSubstring); } if (tag.Index == 0) //if the string given to the matcher was something like '<strong>...' { if (tag.Value.StartsWith("</")) { tagType = TagType.Close; } else if (tag.Value.EndsWith("/>")) { tagType = TagType.SelfClose; } startIndex += tag.Value.Length; return new HtmlSyntaxNode(registeredTag as HtmlTag, tag.Value); } //there has been some text before the tag that I found... startIndex += tag.Index; //move the start index for the other iterations return new TextSyntaxNode(currentSubstring.Substring(0, tag.Index)); }
/// <summary> /// Gets the next node after the start index. /// </summary> /// <param name="code">The code.</param> /// <param name="startIndex">The index from which to start searching.</param> /// <param name="tagType">Returns the next tag type</param> /// <param name="previousTag">The previous tag in the stack.</param> /// <param name="isParseContent">If the content of the last opening node should be parsed.</param> /// <returns></returns> protected override SyntaxNode GetNextNode(string code, ref int startIndex, out TagType tagType, Tag previousTag, bool isParseContent) { string currentSubstring = code.Substring(startIndex); string regexPattern = previousTag == null || isParseContent ? @"\[/?[a-z*][a-z0-9]*(=[^\[\]\n\r\v\f]+)?\]" : @"\[" + previousTag.CloseTag + @"\]"; //the close tag has / Match tag = Regex.Match(currentSubstring, regexPattern); Tag registeredTag = null; tagType = TagType.Open; //we just set it here and when needed will do it later while (tag.Success && (registeredTag = GetTagByValue(tag.Value)) == null)//getting tags, but they are not registered. { tag = tag.NextMatch(); } if (!tag.Success) //didn't find a registered tag until the end - return everything left as a text node { startIndex += currentSubstring.Length; return new TextSyntaxNode(currentSubstring); } if (tag.Index == 0) //if the string given to the matcher was something like '[b]...' { if (tag.Value.StartsWith("[/")) tagType = TagType.Close; startIndex += tag.Value.Length; return new BBCodeSyntaxNode(registeredTag as BBTag, tag.Value); } //there has been some text before the tag that I found... startIndex += tag.Index; //move the start index for the other iterations return new TextSyntaxNode(currentSubstring.Substring(0, tag.Index)); }
/// <summary> /// Creates a syntax node with children /// </summary> /// <param name="tag">The tag used...</param> /// <param name="tagRepresentation">The representation of the tag.</param> /// <param name="children">The children</param> protected SyntaxNode(Tag tag, string tagRepresentation, List<SyntaxNode> children) { if (children == null) throw new ArgumentNullException("children"); this.Tag = tag; Children = children; NewlineRepresentation = tag == null ? null : tag.GetNewlineRepresentation(tagRepresentation); Initialize(tagRepresentation); }
/// <summary> /// Checks if the tags are distinct. /// </summary> /// <param name="tags">List of tags from which to check</param> private bool IsTagsDistinct(Tag[] tags) { HashSet<string> openTags = new HashSet<string>(); HashSet<string> closeTags = new HashSet<string>(); foreach (Tag tag in tags) { openTags.Add(tag.OpenTag); closeTags.Add(tag.CloseTag); } return openTags.Count == tags.Length && closeTags.Count == tags.Length; }
/// <summary> /// Gets the next node after the start index. /// </summary> /// <param name="code">The code.</param> /// <param name="startIndex">The index from which to start searching.</param> /// <param name="tagType">Returns the next tag type</param> /// <param name="previousTag">The previous tag in the stack.</param> /// <param name="isParseContent">If the content of the last opening node should be parsed.</param> protected abstract SyntaxNode GetNextNode(string code, ref int startIndex, out TagType tagType, Tag previousTag, bool isParseContent);
/// <summary> /// Gets the option from the representation of the tag representation. /// </summary> /// <param name="tag">The defined bbtag</param> /// <param name="representation">The way it was represented in the text (with [])</param> protected override void GetTagOptionFromRepresentation(Tag tag, string representation) { Option = (tag as BBTag).GetOptionValue(representation); }
/// <summary> /// Gets the value of the option of the tag. Also, if the tag content is encoded in some of its attributes, /// adds the content as a child. /// </summary> /// <param name="tag">The tag.</param> /// <param name="tagRepresentation">The representation of the tag.</param> protected override void GetTagOptionFromRepresentation(Tag tag, string tagRepresentation) { TagOption = (tag as HtmlTag).GetOptionFromRepresentation(tagRepresentation); //get the option that best describes the tag if (TagOption == null) return; //this is when it's a closing tag... if (TagOption.OptionHtmlAttribute != null) { Option = HtmlAttribute.GetAttributeValue(tagRepresentation, TagOption.OptionHtmlAttribute); } if (TagOption.ContentHtmlAttribute != null) { AddChild(new TextSyntaxNode(HtmlAttribute.GetAttributeValue(tagRepresentation, TagOption.ContentHtmlAttribute))); } }
/// <summary> /// Creates an empty syntax node /// </summary> /// <param name="tag">The tag used...</param> /// <param name="tagRepresentation">The representation of the tag.</param> protected SyntaxNode(Tag tag, string tagRepresentation) : this(tag, tagRepresentation, new List<SyntaxNode>()) { }
/// <summary> /// Returns the tag option from its string representation /// </summary> protected abstract void GetTagOptionFromRepresentation(Tag tag, string representation);
protected override void GetTagOptionFromRepresentation(Tag tag, string representation) { throw new NotSupportedException("You can't call this method from a text syntax node."); }