private void EndElement(ParserContext context, IDocumentElement element)
        {
            var linkElement = element as ILinkElement;

            switch (element.ElementType)
            {
            case ElementTypes.Container:
                context.IsPreFormatted = false;
                context.Template.AddElementClose();
                context.Template.AddLineBreak();
                break;

            case ElementTypes.InlineText:
                context.Template.AddElementClose();
                break;

            case ElementTypes.Heading:
            case ElementTypes.Paragraph:
                context.Template.AddElementClose();
                context.Template.AddLineBreak();
                break;

            case ElementTypes.Link:
                if (linkElement != null && linkElement.LinkType == LinkTypes.Reference)
                {
                    context.Template.AddElementClose();
                }
                break;
            }
        }
        public bool Write(IDocumentElement element)
        {
            switch (element.ElementType)
            {
            case ElementTypes.Document:
                return(WriteDocument(element));

            case ElementTypes.Break:
                return(WriteBreak(element));

            case ElementTypes.Container:
                return(WriteContainer(element));

            case ElementTypes.Heading:
                return(WriteHeading(element));

            case ElementTypes.InlineText:
                return(WriteInlineText(element));

            case ElementTypes.Link:
                return(WriteLink(element));

            case ElementTypes.Paragraph:
                return(WriteParagraph(element));
            }

            var textElement = element as ITextElement;

            if (textElement != null && !string.IsNullOrEmpty(textElement.Text))
            {
                _textWriter.Write(textElement.Text);
            }

            return(true);
        }
        private void CollapseLineBreaks(IDocumentElement element)
        {
            var nextIsLineBreak = false;

            for (var i = element.Children.Count - 2; i >= 0; i--)
            {
                var current = element.Children[i] as IBreakElement;
                if (current != null &&
                    current.BreakType == BreakTypes.LineBreak)
                {
                    if (nextIsLineBreak)
                    {
                        element.Children.RemoveAt(i + 1);
                    }
                    else
                    {
                        var next = element.Children[i + 1] as IBreakElement;
                        if (next != null &&
                            next.BreakType == BreakTypes.LineBreak)
                        {
                            element.Children.RemoveAt(i + 1);
                        }
                        nextIsLineBreak = true;
                    }
                }
                else
                {
                    i--;
                    nextIsLineBreak = false;
                }
            }
        }
        public void CleanDocument(IDocumentElement element, DocumentCleaning actions)
        {
            if (element == null || element.Children == null || element.Children.Count == 0)
            {
                return;
            }

            if ((actions & (DocumentCleaning.RemoveBlankLines | DocumentCleaning.MakeParagraphs)) != 0)
            {
                RemoveEmptyTextElements(element);
                CollapseLineBreaks(element);
            }

            if (actions.HasFlag(DocumentCleaning.MakeParagraphs))
            {
                MakeParagraphs(element);
            }

            foreach (var child in element.Children)
            {
                CleanDocument(child, actions);
            }

            if (actions.HasFlag(DocumentCleaning.RemoveBlankLines))
            {
                RemoveEmptyContainers(element);
            }
        }
        private bool WriteHeading(IDocumentElement element)
        {
            var nestedElement = element as INestedElement;

            var headingLevel = 1;

            if (nestedElement != null)
            {
                headingLevel = nestedElement.Level;
            }

            _characterStream.State = MarkdownStates.Heading;

            _textWriter.EnsureBlankLine();
            _textWriter.Write(new string('#', headingLevel));
            _textWriter.Write(' ');

            if (element.Children != null)
            {
                foreach (var child in element.Children)
                {
                    Write(child);
                }
            }

            _textWriter.EnsureNewLine();

            return(true);
        }
Пример #6
0
        public void AddToParagraph(IDocumentElement elementToAdd)
        {
            Contract.Requires(elementToAdd != null);
            Contract.Ensures(currentParagraph != null);

            CreateParagraphIfNoneIsAlreadyOpen();
            currentParagraph.AddChild(elementToAdd);
        }
Пример #7
0
        private string RenderMarkdown(IDocumentElement document)
        {
            var output = new StringBuilder();

            using (var textWriter = new StringWriter(output))
            {
                _documentTransformer.FormatDocument("text/x-markdown", textWriter, document);
            }
            return(output.ToString());
        }
        private void MakeParagraphs(IDocumentElement element)
        {
            for (var i = element.Children.Count - 1; i >= 0; i--)
            {
                var lineBreak = element.Children[i] as IBreakElement;
                {
                    if (lineBreak != null && lineBreak.BreakType == BreakTypes.LineBreak)
                    {
                        var first = i;

                        while (first > 0)
                        {
                            var textElement = element.Children[first - 1];
                            var linkElement = textElement as ILinkElement;

                            if (textElement.ElementType == ElementTypes.RawText ||
                                textElement.ElementType == ElementTypes.InlineText ||
                                (textElement.ElementType == ElementTypes.Link &&
                                 linkElement != null &&
                                 (linkElement.LinkType == LinkTypes.Reference || linkElement.LinkType == LinkTypes.Image))
                                )
                            {
                                first--;
                            }
                            else
                            {
                                break;
                            }
                        }

                        if (first == i)
                        {
                            continue;
                        }

                        var paragraph = new ParagraphElement
                        {
                            Parent   = element,
                            Children = new List <IDocumentElement>()
                        };
                        element.Children[i] = paragraph;

                        for (var j = first; j < i; j++)
                        {
                            var childToMove = element.Children[first];
                            paragraph.Children.Add(childToMove);
                            childToMove.Parent = paragraph;
                            element.Children.RemoveAt(first);
                        }

                        i = first;
                    }
                }
            }
        }
 private void FixupChildren(IDocumentElement element)
 {
     if (element.Children != null)
     {
         foreach (var child in element.Children)
         {
             child.Parent = element;
             FixupChildren(child);
         }
     }
 }
        private bool WriteDocument(IDocumentElement element)
        {
            if (element.Children != null)
            {
                foreach (var child in element.Children)
                {
                    Write(child);
                }
            }

            return(true);
        }
        private bool WriteLink(IDocumentElement element)
        {
            var linkElement = element as ILinkElement;

            if (linkElement == null)
            {
                return(false);
            }

            _textWriter.Write(linkElement.LinkAddress);

            return(true);
        }
 private T FindPriorElement <T>(IDocumentElement start, Func <T, bool> predicate) where T : Element
 {
     while (start != null)
     {
         var t = start as T;
         if (t != null && predicate(t))
         {
             return(t);
         }
         start = start.Parent;
     }
     return(null);
 }
        private void Write(ParserContext context, IDocumentElement element)
        {
            BeginElement(context, element);

            if (element.Children != null)
            {
                foreach (var child in element.Children)
                {
                    Write(context, child);
                }
            }

            EndElement(context, element);
        }
Пример #14
0
        public void Write(IDocumentElement element)
        {
            WriteElementBegin(element);

            if (element.Children != null)
            {
                foreach (var child in element.Children)
                {
                    Write(child);
                }
            }

            WriteElementEnd(element);
        }
        public void CleanAttributes(IDocumentElement element, Func <IDocumentElement, string, string, bool> attributeFilter)
        {
            if (element == null || attributeFilter == null)
            {
                return;
            }

            if (element.Children != null)
            {
                foreach (var child in element.Children)
                {
                    CleanAttributes(child, attributeFilter);
                }
            }
        }
Пример #16
0
        public TElement AssertElement <TElement> (int index, Action <TElement> assertAction = null)
            where TElement : IDocumentElement
        {
            Contract.Requires(index >= 0);
            Contract.Ensures(Contract.Result <TElement>() != null);

            IDocumentElement element = doc.Children[index];

            Assert.IsInstanceOf <TElement> (element);
            if (assertAction != null)
            {
                assertAction((TElement)element);
            }

            return((TElement)element);
        }
        private bool WriteHeading(IDocumentElement element)
        {
            _textWriter.EnsureBlankLine();

            if (element.Children != null)
            {
                foreach (var child in element.Children)
                {
                    Write(child);
                }
            }

            _textWriter.EnsureNewLine();

            return(true);
        }
 private void RemoveEmptyContainers(IDocumentElement element)
 {
     for (var i = element.Children.Count - 1; i >= 0; i--)
     {
         var child = element.Children[i];
         if (child != null &&
             (child.ElementType == ElementTypes.Container || child.ElementType == ElementTypes.Paragraph) &&
             (child.Children == null || child.Children.Count == 0))
         {
             var container = child as IContainerElement;
             if (container != null && container.ContainerType == ContainerTypes.TableDataCell)
             {
                 continue; // Empty cells in tables are valid, deleting them moves all the other columns to the left
             }
             element.Children.RemoveAt(i);
         }
     }
 }
        private bool WriteInlineText(IDocumentElement element)
        {
            var textElement = element as ITextElement;

            if (textElement != null)
            {
                _textWriter.Write(textElement.Text);
            }

            if (element.Children != null)
            {
                foreach (var child in element.Children)
                {
                    Write(child);
                }
            }

            return(true);
        }
        private bool WriteParagraph(IDocumentElement element)
        {
            var textElement = element as ITextElement;

            if (textElement != null && !string.IsNullOrEmpty(textElement.Text))
            {
                _textWriter.Write(textElement.Text);
            }

            if (element.Children != null)
            {
                foreach (var child in element.Children)
                {
                    Write(child);
                }
            }

            return(true);
        }
Пример #21
0
        public void AddTextToParagraph(string text, bool isFirstElementOfContinuedLine)
        {
            Contract.Requires(text != null);

            CreateParagraphIfNoneIsAlreadyOpen();

            int childrenCount = currentParagraph.ChildrenCount;

            if (childrenCount > 0)
            {
                IDocumentElement lastChild = currentParagraph.Children[childrenCount - 1];
                TextElement      textChild = lastChild as TextElement;
                if (textChild != null)
                {
                    // ReSharper disable once PossibleInvalidOperationException
                    if (textChild.Style == currentParagraphTextStyle.Value)
                    {
                        textChild.AppendText(text);
                    }
                    else
                    {
                        AddTextElementToParagraph(
                            currentParagraph, text, currentParagraphTextStyle.Value, isFirstElementOfContinuedLine);
                    }
                }
                else if (lastChild is InternalLinkElement || lastChild is ExternalLinkElement)
                {
                    // ReSharper disable once PossibleInvalidOperationException
                    AddTextElementToParagraph(
                        currentParagraph, text, currentParagraphTextStyle.Value, isFirstElementOfContinuedLine);
                }
                else
                {
                    throw new InvalidOperationException("BUG: is this possible?");
                }
            }
            else
            {
                // ReSharper disable once PossibleInvalidOperationException
                AddToParagraph(CreateTextElement(text, currentParagraphTextStyle.Value));
            }
        }
        public void CleanElements(IDocumentElement element, Func <IDocumentElement, bool> elementFilter)
        {
            if (element == null || elementFilter == null || element.Children == null)
            {
                return;
            }

            for (var i = element.Children.Count - 1; i >= 0; i--)
            {
                var child = element.Children[i];
                if (elementFilter(child))
                {
                    CleanElements(child, elementFilter);
                }
                else
                {
                    element.Children.RemoveAt(i);
                }
            }
        }
        private void RemoveEmptyTextElements(IDocumentElement element)
        {
            for (var i = element.Children.Count - 1; i >= 0; i--)
            {
                var child = element.Children[i];
                if (child != null &&
                    (child.ElementType == ElementTypes.RawText ||
                     child.ElementType == ElementTypes.InlineText) &&
                    (child.Children == null || child.Children.Count == 0))
                {
                    var text = child as ITextElement;
                    if (text != null && !string.IsNullOrEmpty(text.Text))
                    {
                        continue;
                    }

                    element.Children.RemoveAt(i);
                }
            }
        }
Пример #24
0
        public ParsingFixture AssertText(
            IDocumentElementContainer container, int index, string expectedText, TextElement.TextStyle?expectedStyle = null)
        {
            Contract.Requires(container != null);
            Contract.Requires(expectedText != null);
            Contract.Requires(index >= 0);

            IDocumentElement element = container.Children[index];

            Assert.IsInstanceOf <TextElement> (element);
            TextElement tel = (TextElement)element;

            Assert.AreEqual(expectedText, tel.Text);
            if (expectedStyle.HasValue)
            {
                Assert.AreEqual(expectedStyle.Value, tel.Style);
            }

            return(this);
        }
        private bool WriteInlineText(IDocumentElement element)
        {
            var textElement  = element as ITextElement;
            var styleElement = element as IStyleElement;

            Action close = null;

            if (styleElement != null && styleElement.Styles != null)
            {
                if (styleElement.Styles.ContainsKey("font-weight") && styleElement.Styles["font-weight"] == "bold")
                {
                    _textWriter.Write("**");
                    close = () => _textWriter.Write("**");
                }
                else if (styleElement.Styles.ContainsKey("font-style") && styleElement.Styles["font-style"] == "italic")
                {
                    _textWriter.Write("_");
                    close = () => _textWriter.Write("_");
                }
            }

            if (textElement != null)
            {
                _textWriter.Write(textElement.Text);
            }

            if (element.Children != null)
            {
                foreach (var child in element.Children)
                {
                    Write(child);
                }
            }

            if (close != null)
            {
                close();
            }

            return(true);
        }
        public void FormatDocument(string mimeType, System.IO.TextWriter writer, IDocumentElement rootElement, bool fragment)
        {
            if (string.Equals(mimeType, "text/html", StringComparison.OrdinalIgnoreCase))
            {
                FormatHtml(writer, rootElement, fragment);
            }

            else if (string.Equals(mimeType, "text/x-markdown", StringComparison.OrdinalIgnoreCase))
            {
                FormatMarkdown(writer, rootElement, fragment);
            }

            else if (string.Equals(mimeType, "text/plain", StringComparison.OrdinalIgnoreCase))
            {
                FormatPlainText(writer, rootElement, fragment);
            }

            else
            {
                throw new NotImplementedException();
            }
        }
 private static void BeginParagraphElement(ParserContext context, IDocumentElement element,
                                           string[] attributeParams)
 {
     if (element.Parent.ElementType == ElementTypes.Container)
     {
         var parentContainer = element.Parent as IContainerElement;
         if (parentContainer != null &&
             (parentContainer.ContainerType == ContainerTypes.BareList ||
              parentContainer.ContainerType == ContainerTypes.BulletList ||
              parentContainer.ContainerType == ContainerTypes.NumberedList))
         {
             context.Template.AddElementOpen("li", attributeParams);
         }
         else
         {
             context.Template.AddElementOpen("p", attributeParams);
         }
     }
     else
     {
         context.Template.AddElementOpen("p", attributeParams);
     }
 }
        public void AdjustHeadings(IDocumentElement element, int minimumHeadingLevel)
        {
            Action <IDocumentElement, List <INestedElement> > addHeadings = null;

            addHeadings = (e, hl) =>
            {
                var h = e as INestedElement;
                if (e.ElementType == ElementTypes.Heading && h != null)
                {
                    hl.Add(h);
                }

                if (e.Children != null)
                {
                    foreach (var child in e.Children)
                    {
                        addHeadings(child, hl);
                    }
                }
            };

            var headings = new List <INestedElement>();

            addHeadings(element, headings);

            if (headings.Count > 0)
            {
                var lowestHeading = headings.Min(h => h.Level);
                if (lowestHeading > 1)
                {
                    foreach (var heading in headings)
                    {
                        heading.Level = heading.Level - lowestHeading + minimumHeadingLevel;
                    }
                }
            }
        }
        private bool WriteBreak(IDocumentElement element)
        {
            var breakElement = element as IBreakElement;

            var breakType = BreakTypes.LineBreak;

            if (breakElement != null)
            {
                breakType = breakElement.BreakType;
            }

            _textWriter.EnsureBlankLine();

            switch (breakType)
            {
            case BreakTypes.HorizontalRule:
                _characterStream.State = MarkdownStates.HorizontalRule;
                _textWriter.Write("---");
                _textWriter.EnsureBlankLine();
                break;
            }

            return(true);
        }
        private bool WriteContainer(IDocumentElement element)
        {
            var containerElement    = element as IContainerElement;
            var configurableElement = element as IConfigurableElement;

            if (containerElement == null)
            {
                return(false);
            }

            Action close = null;

            switch (containerElement.ContainerType)
            {
            case ContainerTypes.BlockQuote:
                _textWriter.EnsureBlankLine();
                _characterStream.State = MarkdownStates.BlockQuote;
                close = () => _textWriter.EnsureBlankLine();
                break;

            case ContainerTypes.BulletList:
                _listLevel++;
                if (_listLevel == 0)
                {
                    _textWriter.EnsureBlankLine();
                }

                _characterStream.State = MarkdownStates.UnorderedList;

                close = () =>
                {
                    if (_listLevel == 0)
                    {
                        _textWriter.EnsureBlankLine();
                    }
                    _listLevel--;
                };
                break;

            case ContainerTypes.NumberedList:
                _listLevel++;
                while (_listItemNumber.Count <= _listLevel)
                {
                    _listItemNumber.Add(0);
                }
                _listItemNumber[_listLevel] = 1;

                if (_listLevel == 0)
                {
                    _textWriter.EnsureBlankLine();
                }

                _characterStream.State = MarkdownStates.NumberedList;

                close = () =>
                {
                    if (_listLevel == 0)
                    {
                        _textWriter.EnsureBlankLine();
                    }
                    _listLevel--;
                };
                break;

            case ContainerTypes.PreFormatted:
                _textWriter.EnsureBlankLine();
                _characterStream.State = MarkdownStates.SourceCode;
                _textWriter.Write("```");
                _textWriter.WriteLineBreak();
                close = () =>
                {
                    _textWriter.EnsureNewLine();
                    _textWriter.Write("```");
                    _textWriter.EnsureBlankLine();
                };
                break;

            case ContainerTypes.Table:
                containerElement.ChildLayout = new TableLayout();
                _textWriter.EnsureBlankLine();
                _characterStream.State = MarkdownStates.TableHeadings;
                close = () => _textWriter.EnsureBlankLine();
                break;

            case ContainerTypes.TableHeader:
                close = () =>
                {
                    var table = FindPriorElement <ContainerElement>(element, c => c.ContainerType == ContainerTypes.Table);
                    if (table == null)
                    {
                        return;
                    }

                    var tableLayout = table.ChildLayout as TableLayout;
                    if (tableLayout == null)
                    {
                        return;
                    }

                    var tableBody = table.Children
                                    .Where(e => e.ElementType == ElementTypes.Container)
                                    .Cast <IContainerElement>()
                                    .FirstOrDefault(c => c.ContainerType == ContainerTypes.TableBody);

                    if (tableBody != null)
                    {
                        var tableBodyChildren = ((IDocumentElement)tableBody).Children;
                        if (tableBodyChildren != null)
                        {
                            foreach (var tableRow in tableBodyChildren
                                     .Where(c => c.ElementType == ElementTypes.Container && c.Children != null)
                                     .Cast <IContainerElement>()
                                     .Where(c => c.ContainerType == ContainerTypes.TableDataRow)
                                     .Cast <IDocumentElement>())
                            {
                                var columnIndex = 0;
                                foreach (var dataCell in tableRow.Children
                                         .Where(c => c.ElementType == ElementTypes.Container && c.Children != null)
                                         .Cast <IContainerElement>()
                                         .Where(c => c.ContainerType == ContainerTypes.TableDataCell)
                                         .Cast <IConfigurableElement>())
                                {
                                    string alignment = null;
                                    if (dataCell != null && dataCell.Attributes != null && dataCell.Attributes.ContainsKey("align"))
                                    {
                                        alignment = dataCell.Attributes["align"];
                                    }
                                    tableLayout.SetColumn(columnIndex++, alignment, null);
                                }
                            }
                        }
                    }

                    _textWriter.EnsureNewLine();
                    _textWriter.Write('|');

                    foreach (var tableColumn in tableLayout.Columns)
                    {
                        var padding = new string('-', tableColumn.Width);

                        switch (tableColumn.Alignment)
                        {
                        case "left":
                            _textWriter.Write(':');
                            _textWriter.Write(padding);
                            _textWriter.Write(' ');
                            break;

                        case "right":
                            _textWriter.Write(' ');
                            _textWriter.Write(padding);
                            _textWriter.Write(':');
                            break;

                        case "center":
                            _textWriter.Write(':');
                            _textWriter.Write(padding);
                            _textWriter.Write(':');
                            break;

                        default:
                            _textWriter.Write(' ');
                            _textWriter.Write(padding);
                            _textWriter.Write(' ');
                            break;
                        }
                        _textWriter.Write('|');
                    }
                };
                break;

            case ContainerTypes.TableHeaderRow:
            case ContainerTypes.TableDataRow:
            case ContainerTypes.TableFooterRow:
                _textWriter.EnsureNewLine();
                _characterStream.State = MarkdownStates.TableRow;
                _textWriter.Write("|");
                _tableColumnIndex = 0;
                break;

            case ContainerTypes.TableDataCell:
            {
                var align = string.Empty;
                if (configurableElement != null && configurableElement.Attributes != null)
                {
                    if (configurableElement.Attributes.ContainsKey("align"))
                    {
                        align = configurableElement.Attributes["align"];
                    }
                }

                var table       = FindPriorElement <ContainerElement>(element, c => c.ContainerType == ContainerTypes.Table);
                var tableLayout = (TableLayout)table.ChildLayout;
                tableLayout.SetColumn(_tableColumnIndex, align, null);
                _tableColumnIndex++;

                _characterStream.State = MarkdownStates.TableRow;
                _textWriter.Write(" ");
                close = () => _textWriter.Write(" |");
                break;
            }
            }

            if (element.Children != null)
            {
                foreach (var child in element.Children)
                {
                    Write(child);
                }
            }

            if (close != null)
            {
                close();
            }

            return(true);
        }