/// <summary>
        /// Removes up to a number of newlines (and whitespace between them) that are found after the specified
        /// <paramref name="tagInstance"/>.
        /// </summary>
        /// <remarks>
        /// If <paramref name="numberOfNewlines"/> is higher than the actual number of newlines after the
        /// <paramref name="tagInstance"/>, only the actual number of newlines will be removed.
        /// </remarks>
        /// <param name="tagInstance">The tag instance to remove whitespace from after</param>
        /// <param name="numberOfNewlines">The number of newlines to remove</param>
        public void RemoveWhitespaceAfterTag(ITagInstance tagInstance, int numberOfNewlines)
        {
            if (numberOfNewlines <= 0)
            {
                throw new ArgumentOutOfRangeException("numberOfNewlines", "numberOfNewlines must be greater than 0.");
            }

            if (tagInstance.CharRange.StartAt >= _RenderString.Length)
            {
                return;
            }

            int   startAt = tagInstance.CharRange.StartAt + tagInstance.CharRange.Length;
            Match match   = _AfterTagWhitespaceRegex.Match(GetRenderString(), startAt);

            if (match.Success == false)
            {
                return;
            }

            CaptureCollection captures = match.Groups["nl"].Captures;

            if (captures.Count <= numberOfNewlines)
            {
                RenderNonTagRange(match.Index, match.Length, String.Empty, false);
            }
            else
            {
                int length = captures.Cast <Capture>().Take(numberOfNewlines).Sum(c => c.Length);
                RenderNonTagRange(startAt, length, String.Empty, false);
            }
        }
            /// <summary>
            /// Makes an assessment as to whether <paramref name="tagInstance"/> is a valid tag
            /// </summary>
            /// <param name="tagInstance">The <see cref="ITagInstance"/></param>
            /// <param name="context">The <see cref="ValidationContext"/></param>
            /// <returns>True if the tag is not valid should be vetoed, false otherwise</returns>
            public bool CheckForVeto(ITagInstance tagInstance, ValidationContext context)
            {
                int size = (int)tagInstance.Attributes["Size"];
                SizeTagDefinition sizeTagDef = (SizeTagDefinition)tagInstance.ParentDefinition;

                return(size > sizeTagDef._MaxSize || size < sizeTagDef._MinSize);
            }
Example #3
0
            /// <summary>
            /// Makes an assessment as to whether <paramref name="tagInstance"/> is a valid tag
            /// </summary>
            /// <param name="tagInstance">The <see cref="ITagInstance"/></param>
            /// <param name="context">The <see cref="ValidationContext"/></param>
            /// <returns>True if the tag is not valid should be vetoed, false otherwise</returns>
            public bool CheckForVeto(ITagInstance tagInstance, ValidationContext context)
            {
                if (tagInstance.Attributes.ContainsKey("Hex"))
                {
                    return(false);
                }

                return(_ColourNames.Contains(((string)tagInstance.Attributes["Name"]).ToLower()) == false);
            }
        /// <summary>
        /// Returns an <see cref="IEnumerable{T}"/> of the tags following the specified
        /// <paramref name="tagInstance"/> in the ordered sequence of tags defined by <see cref="IBbStringContext.Tags"/>.
        /// </summary>
        /// <param name="tagInstance">The <see cref="ITagInstance"/> to return the tags after</param>
        /// <returns>
        /// The <see cref="ITagInstance"/>s after (and not including) <paramref name="tagInstance"/>
        /// from the <see cref="IBbStringContext.Tags"/> list.
        /// </returns>
        public IEnumerable <ITagInstance> GetTagsAfter(ITagInstance tagInstance)
        {
            int index = _Tags.BinarySearch(tagInstance, TagInstanceComparer.Instance);

            if (index < 0)
            {
                throw new ArgumentException("tagInstance must be in the Tags enumeration", "tagInstance");
            }

            return(EnumerateFromIndex(_Tags, index + 1));
        }
Example #5
0
        /// <summary>
        /// Wraps text between <paramref name="afterTag"/> and <paramref name="untilTag"/> in paragraph
        /// XHTML tags
        /// </summary>
        /// <param name="afterTag">The tag after which the text follows</param>
        /// <param name="untilTag">The tag before which the text lies</param>
        /// <param name="context">The <see cref="RenderContext"/></param>
        private void WrapTextBetweenTagsInPTags(ITagInstance afterTag, ITagInstance untilTag, IRenderContext context)
        {
            Match whitespaceMatch = _WhitespaceRegex.Match(context.GetRenderString(afterTag, untilTag));

            if (whitespaceMatch.Success)
            {
                return;                 //No need to wrap whitespace in a P tag
            }
            context.RenderNonTagRange(afterTag.CharRange.StartAt + afterTag.CharRange.Length, 0, TEXT_WRAP_OPEN_TAG, true);
            context.RenderNonTagRange(untilTag.CharRange.StartAt, 0, TEXT_WRAP_CLOSE_TAG, true);
        }
Example #6
0
        /// <summary>
        /// Checks if the current tag's character range overlaps the previous tag's character range
        /// </summary>
        /// <remarks>
        /// Checking backwards for every tag previous the current is unnecessary because each previous
        /// tag is vetoed if it overlaps with the tag before it.
        /// </remarks>
        /// <param name="context">The <see cref="ValidationContext"/></param>
        /// <param name="tagIndex">The index of the current tag in <see cref="ValidationContext.Tags"/></param>
        /// <returns>True if it does overlap, false otherwise</returns>
        private bool CheckForPreviousTagOverlap(ValidationContext context, int tagIndex)
        {
            ITagInstance tagInstance = context.Tags[tagIndex];

            if (tagIndex == 0)
            {
                return(false);
            }

            ITagInstance previousTagInstance = context.Tags[tagIndex - 1];
            int          endIndex            = previousTagInstance.CharRange.StartAt + previousTagInstance.CharRange.Length - 1;

            return(tagInstance.CharRange.StartAt <= endIndex);
        }
            /// <summary>
            /// Makes an assessment as to whether <paramref name="tagInstance"/> is a valid tag
            /// </summary>
            /// <param name="tagInstance">The <see cref="ITagInstance"/></param>
            /// <param name="context">The <see cref="ValidationContext"/></param>
            /// <returns>True if the tag is not valid should be vetoed, false otherwise</returns>
            public bool CheckForVeto(ITagInstance tagInstance, ValidationContext context)
            {
                FlashTagDefinition flashTagDef = tagInstance.ParentDefinition as FlashTagDefinition;

                if (flashTagDef == null || tagInstance is IOpenTagInstance == false)
                {
                    throw new IllegalStateException("MustHaveValidSizesVetoRule did not receive an img open tag");
                }

                int width  = (int)tagInstance.Attributes["Width"];
                int height = (int)tagInstance.Attributes["Height"];

                return((width < flashTagDef._MinWidth || width > flashTagDef._MaxWidth) ||
                       (height < flashTagDef._MinHeight || height > flashTagDef._MaxHeight));
            }
Example #8
0
        /// <summary>
        /// Causes the <see cref="ITagDefinition"/> to render all of its <see cref="ITagInstance"/>s into XHTML.
        /// </summary>
        /// <remarks>
        /// This method is always called after <see cref="ITagDefinition.RemoveWhitespace"/> is called on any
        /// <see cref="ITagDefinition"/>. The order in which this method is called across the different
        /// <see cref="ITagDefinition"/>s is undefined.
        /// </remarks>
        /// <param name="context">
        /// The <see cref="IRenderContext"/> contains all the <see cref="ITagInstance"/>s, the input text,
        /// and methods that allow for the rendering of <see cref="ITagInstance"/>s.
        /// </param>
        public override void Render(IRenderContext context)
        {
            IEnumerable <IOpenTagInstance> tagInstances = context.Tags.Where(t => t.ParentDefinition == this)
                                                          .OfType <IOpenTagInstance>();

            foreach (IOpenTagInstance openTag in tagInstances)
            {
                ICloseTagInstance closeTag = openTag.CloseTag;

                string replacementOpenTag = REPLACEMENT_OPEN_TAG;
                if (openTag.Attributes.ContainsKey("Username"))
                {
                    replacementOpenTag += String.Format(AUTHOR_TAG_FORMAT_STRING, WebUtility.HtmlEncode((string)openTag.Attributes["Username"]));
                }
                context.RenderTag(openTag, replacementOpenTag, true);

                //Wrap all content that is not inside an block element tag in P tags
                ITagInstance afterTag = openTag;
                while (afterTag != null)
                {
                    //Find the next block element tag nested inside openTag
                    IOpenTagInstance untilTag = context.GetTagsAfter(afterTag)
                                                .TakeWhile(t => t != closeTag)                                                   //Take until the close tag
                                                .WhereStackDepthIs(0)                                                            //Only tags immediately nested inside openTag
                                                .Where(t => t.RendersToInlineElement == false)
                                                .OfType <IOpenTagInstance>()
                                                .FirstOrDefault();

                    if (untilTag != null)
                    {
                        WrapTextBetweenTagsInPTags(afterTag, untilTag, context);
                        afterTag = untilTag.CloseTag;
                    }
                    else
                    {
                        WrapTextBetweenTagsInPTags(afterTag, closeTag, context);
                        afterTag = null;
                    }
                }

                context.RenderTag(closeTag, REPLACEMENT_CLOSE_TAG, true);
            }

            context.RegisterRenderCacheability(true);
        }
Example #9
0
            /// <summary>
            /// Makes an assessment as to whether <paramref name="tagInstance"/> is a valid tag
            /// </summary>
            /// <param name="tagInstance">The <see cref="ITagInstance"/></param>
            /// <param name="context">The <see cref="ValidationContext"/></param>
            /// <returns>True if the tag is not valid should be vetoed, false otherwise</returns>
            public bool CheckForVeto(ITagInstance tagInstance, ValidationContext context)
            {
                ImageTagDefinition imgTagDef = tagInstance.ParentDefinition as ImageTagDefinition;

                if (imgTagDef == null || tagInstance is IOpenTagInstance == false)
                {
                    throw new IllegalStateException("MustHaveValidSizesVetoRule did not receive an img open tag");
                }

                if (tagInstance.Attributes.ContainsKey("Width") == false)
                {
                    return(false);                    //No sizes specified
                }
                int width  = (int)tagInstance.Attributes["Width"];
                int height = (int)tagInstance.Attributes["Height"];

                return((width < imgTagDef._MinWidth || width > imgTagDef._MaxWidth) ||
                       (height < imgTagDef._MinHeight || height > imgTagDef._MaxHeight));
            }
Example #10
0
        /// <summary>
        /// Validates the BBCode tags and ensures they respect the rules they define. For example, some tags
        /// disallow other tags inside them. This is where those rules are enforced and errant tags
        /// (<see cref="ITagInstance"/>s) are removed.
        /// </summary>
        /// <param name="context">The <see cref="ValidationContext"/></param>
        private void ValidateAndRepairSyntax(ValidationContext context)
        {
            for (int i = 0; i < context.Tags.Count; i++)
            {
                ITagInstance tagInstance = context.Tags[i];
                bool         vetoed      = CheckForPreviousTagOverlap(context, i);

                if (vetoed == false && tagInstance is IOpenTagInstance)
                {
                    IOpenTagInstance openTagInstance = (IOpenTagInstance)tagInstance;

                    //If any other tag vetoes this one, OR this tag vetoes itself
                    vetoed = context.OpenTagStack.Any(t => t.CheckForVetoAgainstAnotherTag(openTagInstance, context)) ||
                             openTagInstance.CheckForSelfVeto(context);

                    if (vetoed == false)
                    {
                        context.OpenTagStack.Push(openTagInstance);
                    }
                }

                if (vetoed == false && tagInstance is ICloseTagInstance)
                {
                    //If we find a close tag without any open tag, OR
                    //if the current innermost tag (top of the stack) is not the open tag for this close tag
                    vetoed = context.OpenTagStack.Any() == false ||
                             context.OpenTagStack.Peek().ParentDefinition != tagInstance.ParentDefinition;

                    if (vetoed == false)
                    {
                        IOpenTagInstance openTagInstance = context.OpenTagStack.Pop();
                        openTagInstance.CloseTag = (ICloseTagInstance)tagInstance;
                    }
                }

                if (vetoed)
                {
                    context.Tags.RemoveAt(i);
                    i--;
                }
            }

            //Close any tags that were left open
            while (context.OpenTagStack.Any())
            {
                IOpenTagInstance openTagInstance = context.OpenTagStack.Peek();

                string            tagText;
                ICloseTagInstance closeTag = openTagInstance.ParentDefinition.MakeCloseTagFor(openTagInstance, context.InputString.Length, out tagText);
                if (closeTag.CheckIfValidClose(context))
                {
                    context.InputString.Append(tagText);
                    context.Tags.Add(closeTag);
                    openTagInstance.CloseTag = closeTag;
                }
                else
                {
                    context.Tags.Remove(openTagInstance);
                }

                context.OpenTagStack.Pop();
            }
        }
 /// <summary>
 /// Makes an assessment as to whether <paramref name="tagInstance"/> is a valid tag
 /// </summary>
 /// <param name="tagInstance">The <see cref="ITagInstance"/></param>
 /// <param name="context">The <see cref="ValidationContext"/></param>
 /// <returns>True if the tag is not valid should be vetoed, false otherwise</returns>
 public bool CheckForVeto(ITagInstance tagInstance, ValidationContext context)
 {
     return(tagInstance.ParentDefinition is T);
 }
 /// <summary>
 /// Replaces the range of characters defined by the <paramref name="tagInstance"/> with the specified
 /// <paramref name="replacementText"/>.
 /// </summary>
 /// <remarks>
 /// If the <paramref name="replacementText"/> is longer or shorter than the range of characters defined by
 /// the <paramref name="tagInstance"/>, the <see cref="IBbStringContext.Tags"/> and
 /// <see cref="IRenderContext.HtmlEscapedRanges"/> are automatically shifted to reflect the changes.
 /// </remarks>
 /// <param name="tagInstance">The <see cref="ITagInstance"/> whose character range will be replaced</param>
 /// <param name="replacementText">The replacement text</param>
 /// <param name="registerAsHtmlEscaped">
 /// Whether or not to register the rendered character range as an escaped character range (see
 /// <see cref="IRenderContext.HtmlEscapedRanges"/>).
 /// </param>
 public void RenderTag(ITagInstance tagInstance, string replacementText, bool registerAsHtmlEscaped)
 {
     Render(tagInstance.CharRange.StartAt, tagInstance.CharRange.Length, replacementText, registerAsHtmlEscaped);
     tagInstance.Rendered = true;
 }
        /// <summary>
        /// Gets the subset of the render string that is between the specified <see cref="ITagInstance"/>s as it
        /// looks at this point in time. This means i may be in a partially rendering (or not rendered at all) form.
        /// </summary>
        /// <param name="afterTag">The first <see cref="ITagInstance"/></param>
        /// <param name="untilTag">The second <see cref="ITagInstance"/></param>
        /// <returns>The subset of the render string</returns>
        public string GetRenderString(ITagInstance afterTag, ITagInstance untilTag)
        {
            int startIndex = afterTag.CharRange.StartAt + afterTag.CharRange.Length;

            return(GetRenderString(startIndex, untilTag.CharRange.StartAt - startIndex));
        }
 /// <summary>
 /// Makes an assessment as to whether <paramref name="tagInstance"/> is a valid tag
 /// </summary>
 /// <param name="tagInstance">The <see cref="ITagInstance"/></param>
 /// <param name="context">The <see cref="ValidationContext"/></param>
 /// <returns>True if the tag is not valid should be vetoed, false otherwise</returns>
 public bool CheckForVeto(ITagInstance tagInstance, ValidationContext context)
 {
     return(context.OpenTagStack.Any() && context.OpenTagStack.Peek().RendersToInlineElement);
 }
Example #15
0
 public bool CheckForVeto(ITagInstance tagInstance, ValidationContext context)
 {
     return(context.OpenTagStack.Any() == false || context.OpenTagStack.Peek().ParentDefinition != tagInstance.ParentDefinition);
 }
Example #16
0
 /// <summary>
 /// Makes an assessment as to whether <paramref name="tagInstance"/> is a valid tag
 /// </summary>
 /// <param name="tagInstance">The <see cref="ITagInstance"/></param>
 /// <param name="context">The <see cref="ValidationContext"/></param>
 /// <returns>True if the tag is not valid should be vetoed, false otherwise</returns>
 public bool CheckForVeto(ITagInstance tagInstance, ValidationContext context)
 {
     return(_AllowableTagDefinitionTypes.Any(t => t == tagInstance.ParentDefinition.GetType()) == false);
 }