예제 #1
0
        // Handles closing of FlexiSectionBlocks. A FlexiSectionBlock is closed when another FlexiSectionBlock in the same tree with the same or
        // lower level opens.
        internal virtual void UpdateOpenFlexiSectionBlocks(BlockProcessor processor, FlexiSectionBlock flexiSectionBlock)
        {
            // Since sectioning content roots like blockquotes have their own discrete section trees,
            // we maintain a stack of stacks. Each stack represents the open branch of a tree.
            Stack <Stack <FlexiSectionBlock> > openFlexiSectionBlocks = GetOrCreateOpenFlexiSectionBlocks(processor.Document);

            // Discard stacks for closed branches
            while (openFlexiSectionBlocks.Count > 0)
            {
                // When a sectioning content root is closed, all of its children are closed, so the last section in its branch
                // will be closed. Under no circumstance will the section at the tip of a branch be closed without its ancestors
                // being closed as well.
                if (openFlexiSectionBlocks.Peek().Peek().IsOpen)
                {
                    break;
                }

                openFlexiSectionBlocks.Pop();
            }

            // Find parent container block - processor.CurrentContainer may be closed. processor.CurrentContainer is only updated when
            // BlockProcessor.ProcessNewBlocks calls BlockProcessor.CloseAll, so at this point, processor.CurrentContainer may not be the eventual
            // parent of our new FlexiSectionBlock.
            ContainerBlock parentContainerBlock = processor.CurrentContainer;

            while (!parentContainerBlock.IsOpen) // We will eventually reach the root MarkdownDocument (gauranteed to be open) if all other containers aren't open
            {
                parentContainerBlock = parentContainerBlock.Parent;
            }

            if (!(parentContainerBlock is FlexiSectionBlock)) // parentContainerBlock is a sectioning content root, for example, a blockquote. Create a new stack for a new tree
            {
                var newStack = new Stack <FlexiSectionBlock>();
                newStack.Push(flexiSectionBlock);
                openFlexiSectionBlocks.Push(newStack);
            }
            else
            {
                Stack <FlexiSectionBlock> currentBranch = openFlexiSectionBlocks.Peek(); // If parentContainerBlock is a FlexiSectionBlock, at least 1 branch of open FlexiSectionBlocks exists
                // Close open FlexiSectionBlocks that have the same or higher levels
                FlexiSectionBlock flexiSectionBlockToClose = null;
                while (currentBranch.Count > 0)
                {
                    if (currentBranch.Peek().Level < flexiSectionBlock.Level)
                    {
                        break;
                    }

                    flexiSectionBlockToClose = currentBranch.Pop();
                }
                if (flexiSectionBlockToClose != null)
                {
                    processor.Close(flexiSectionBlockToClose);
                }

                // Add new FlexiSectionBlock to current stack
                currentBranch.Push(flexiSectionBlock);
            }
        }
예제 #2
0
        /// <inheritdoc />
        public FlexiSectionBlock Create(int level, BlockProcessor blockProcessor, BlockParser blockParser)
        {
            (IFlexiSectionBlockOptions flexiSectionBlockOptions, IFlexiSectionBlocksExtensionOptions _) = _optionsService.CreateOptions(blockProcessor);

            // Level
            ValidateLevel(level);

            // Block name
            string blockName = ResolveBlockName(flexiSectionBlockOptions.BlockName);

            // Element
            SectioningContentElement element = flexiSectionBlockOptions.Element;

            ValidateElement(element);

            // Rendering mode
            FlexiSectionBlockRenderingMode renderingMode = flexiSectionBlockOptions.RenderingMode;

            ValidateRenderingMode(renderingMode);

            // Create FlexiSectionBlock
            var flexiSectionBlock = new FlexiSectionBlock(blockName,
                                                          element,
                                                          flexiSectionBlockOptions.LinkIcon,
                                                          renderingMode,
                                                          level,
                                                          flexiSectionBlockOptions.Attributes,
                                                          blockParser)
            {
                Column = blockProcessor.Column,
                Span   = new SourceSpan(blockProcessor.Start, blockProcessor.Line.End), // TODO span should include children
                // BlockProcessor will assign Line
            };

            // Create FlexiSectionHeadingBlock
            FlexiSectionHeadingBlock flexiSectionHeadingBlock = _flexiSectionHeadingBlockFactory.Create(blockProcessor, flexiSectionBlockOptions, blockParser);

            flexiSectionBlock.Add(flexiSectionHeadingBlock);

            // Close FlexiSectionBlocks with same or lower levels
            UpdateOpenFlexiSectionBlocks(blockProcessor, flexiSectionBlock);

            return(flexiSectionBlock);
        }