internal virtual FlexiTableRowBlock CreateFlexiTableRowBlock(FlexiTableType type,
                                                                     BlockProcessor childBlockProcessor,
                                                                     List <ColumnDefinition> columnDefinitions,
                                                                     int numColumns,
                                                                     int rowIndex,
                                                                     Row row,
                                                                     bool isHeaderRow)
        {
            var flexiTableRowBlock = new FlexiTableRowBlock(isHeaderRow);

            for (int columnIndex = 0; columnIndex < numColumns;)
            {
                Cell cell = row[columnIndex];
                columnIndex = cell.EndColumnIndex + 1;

                if (cell.StartRowIndex < rowIndex) // Cell with rowspan that's already been created
                {
                    continue;
                }

                // Create cell block
                FlexiTableCellBlock flexiTableCellBlock = CreateFlexiTableCellBlock(type, childBlockProcessor, columnDefinitions, cell);

                // Add cell block to row block
                flexiTableRowBlock.Add(flexiTableCellBlock);
            }

            // Could be empty if all cells have rowspan and have already been created. We return it anyway since it could be relevant.
            // For example, if we remove this row and some cells in the row have rowspan 3 while others only have rowspan 2, the cells
            // with rowspan 3 will erroneously span into an extra row.
            return(flexiTableRowBlock);
        }
Пример #2
0
        private void WriteRowBlock(HtmlRenderer htmlRenderer, string blockName, FlexiTableRowBlock labelsFlexiTableRowBlock, FlexiTableRowBlock flexiTableRowBlock)
        {
            bool   isHeaderRow     = flexiTableRowBlock.IsHeaderRow;
            string cellElementName = isHeaderRow ? "th" : "td";
            string cellClassName   = isHeaderRow ? "header" : "data";
            int    numCells        = flexiTableRowBlock.Count;
            bool   renderLabels    = !isHeaderRow && labelsFlexiTableRowBlock != null;

            htmlRenderer.WriteStartTagLine("tr", blockName, "row");
            for (int cellIndex = 0; cellIndex < numCells; cellIndex++)
            {
                WriteCellBlock(htmlRenderer,
                               blockName,
                               cellElementName,
                               cellClassName,
                               renderLabels ? labelsFlexiTableRowBlock[cellIndex] as FlexiTableCellBlock : null, // Card type table may not have a head row. Also note, card type table cells can't have colspan.
                               flexiTableRowBlock[cellIndex] as FlexiTableCellBlock);
            }
            htmlRenderer.WriteEndTagLine("tr");
        }
Пример #3
0
        /// <summary>
        /// Renders a <see cref="FlexiTableBlock"/> as HTML.
        /// </summary>
        /// <param name="htmlRenderer">The renderer to write to.</param>
        /// <param name="block">The <see cref="FlexiTableBlock"/> to render.</param>
        protected override void WriteBlock(HtmlRenderer htmlRenderer, FlexiTableBlock block)
        {
            if (!htmlRenderer.EnableHtmlForBlock)
            {
                htmlRenderer.WriteChildren(block, false);
                return;
            }

            ReadOnlyDictionary <string, string> attributes = block.Attributes;
            string         blockName = block.BlockName;
            FlexiTableType type      = block.Type;

            // Root element
            // Wrap table in a div. Why?
            // - The "auto" algorithm for determining a table's width basically adds up the minimum content widths (MCW) of each column > https://www.w3.org/TR/CSS2/tables.html#auto-table-layout.
            // - When using "overflow-wrap: break-word" MCW does not take soft wrap oppurtunities into account > https://www.w3.org/TR/css-text-3/#valdef-overflow-wrap-break-word.
            // - The above two points result in long words not wrapping in table cells. Instead, long words cause long cells, in turn causing tables to overflow their parents.
            // - This will no longer be an issue when "overflow-wrap: anywhere" works.
            // - For now, <table> elements must be wrapped in <div>s with "overflow: auto". It is possible to set "overflow: auto" on tables themselves but this will not always work because table widths
            //   are overriden by sum of MCWs of its columns (i.e even if you set a fixed width for a table, it gets overriden in most cases). It is possible to make "overflow: auto" on tables work by
            //   setting the table's display to block (Github does this), but this is a hack that just happens to work (that "display: block" doesn't affect rendering of the table, which should have
            //   "display: table", is a coincidence).
            htmlRenderer.
            Write("<div class=\"").
            Write(blockName).
            WriteBlockKeyValueModifierClass(blockName, "type", _types[(int)type]).
            WriteAttributeValue(attributes, "class").
            Write('"').
            WriteAttributesExcept(attributes, "class").
            WriteLine(">");

            // Table
            htmlRenderer.WriteStartTagLine("table", blockName, "table");

            // Table - Rows
            FlexiTableRowBlock labelsFlexiTableRowBlock = null;
            int  numRows = block.Count;
            bool headStartRendered = false, headEndRendered = false, bodyStartRendered = false;

            for (int rowIndex = 0; rowIndex < numRows; rowIndex++)
            {
                var flexiTableRowBlock = block[rowIndex] as FlexiTableRowBlock;

                if (flexiTableRowBlock.IsHeaderRow)
                {
                    if (!headStartRendered)
                    {
                        htmlRenderer.WriteStartTagLine("thead", blockName, "head");
                        headStartRendered = true;

                        if (type == FlexiTableType.Cards)
                        {
                            labelsFlexiTableRowBlock = flexiTableRowBlock; // TODO we're only using content from first header row in labels, should concatenate content from all header rows
                        }
                    }
                }
                else
                {
                    if (headStartRendered && !headEndRendered) // Table may not have header rows
                    {
                        htmlRenderer.WriteEndTagLine("thead");
                        headEndRendered = true;
                    }

                    if (!bodyStartRendered)
                    {
                        htmlRenderer.WriteStartTagLine("tbody", blockName, "body");
                        bodyStartRendered = true;
                    }
                }

                WriteRowBlock(htmlRenderer, blockName, labelsFlexiTableRowBlock, flexiTableRowBlock);
            }
            htmlRenderer.
            WriteEndTagLine(headStartRendered && !headEndRendered, "thead").
            WriteEndTagLine(bodyStartRendered, "tbody").
            WriteEndTagLine("table").
            WriteEndTagLine("div");
        }