Footnotes
Sources, legal remarks and explanations that would interrupt the text belong at the bottom of the page, in footnotes. Your server code inserts footnotes behind words it finds, sets how they're numbered, reads the footnotes of documents it loads, formats their text and removes them before a document is published.
Users insert footnotes in the browser as described in Footnotes in the Document Editor section. The examples below are complete console programs for Program.cs and use the Core engine.
How Footnotes Work
A footnote has two visible parts. The reference mark is a number in the text, and the footnote itself stands at the bottom of the page, beginning with a footnote mark that has the same number. Its text can use all formatting attributes and can contain tables and images. The following rules apply:
- Numbered through the document. Footnotes are numbered from the beginning to the end of the document. A footnote inserted in front of others renumbers all footnotes behind it.
- On the page of the reference. When the reference mark moves to another page, its footnote moves with it.
- Main text only. Footnotes can be inserted in the main text, but not in headers, footers or text frames.
- Formats. Footnotes are saved in the TX Text Control format, DOCX, RTF and DOC; DOC is available with the Classic engine only. In a PDF document, the logical structure marks footnotes as such.
ServerTextControl.Footnotes returns the FootnoteCollection of the document, which contains a Footnote object for each footnote.
Insert and Number Footnotes
A footnote is inserted at the input position, so the reference mark appears where the input position is. The following program writes two sentences, inserts a footnote behind two phrases it finds and sets the number format to small Roman numerals:
using TXTextControl;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Text = "Service Agreement\r\n" +
"The provider delivers the software within 30 days. " +
"Support is available on business days.";
// The phrase to mark, the footnote text, a name and an ID
(string Phrase, string Text, string Name, int Id)[] notes =
{
("30 days", "Counted from the date of the signed order.", "delivery", 1),
("business days", "Monday to Friday, except public holidays.", "support", 2)
};
foreach (var note in notes)
{
// Find returns a zero-based position, or -1
int position = tx.Find(note.Phrase);
if (position == -1)
{
continue;
}
// The input position directly behind the phrase
tx.Select(position + note.Phrase.Length, 0);
Footnote footnote = new Footnote(note.Text, note.Name, note.Id);
if (!tx.Footnotes.Add(footnote, false))
{
Console.WriteLine($"No footnote could be added behind \"{note.Phrase}\".");
}
}
tx.Footnotes.NumberFormat = NumberFormat.SmallRomanNumbers;
tx.Footnotes.StartNumber = 1;
foreach (Footnote footnote in tx.Footnotes)
{
Console.WriteLine($"{footnote.Number}: {footnote.Text}");
}
tx.Save("agreement.docx", StreamType.WordprocessingML);
}
The code works as follows:
- Find is called again for each phrase, so each position takes the reference marks inserted before it into account.
- The Footnote constructor takes the footnote text and, optionally, a name and a one-based ID. An empty name and the ID 0 mean none.
- FootnoteCollection.Add inserts the footnote and returns
falseif it couldn't be inserted, for example in a header. Withtrueas the second parameter, the input position moves into the footnote text so that it can be edited;falseleaves it in the main text. - NumberFormat applies to all footnotes:
ArabicNumbers(1, 2, 3),Letters(a, b, c),CapitalLetters(A, B, C),RomanNumbers(I, II, III) orSmallRomanNumbers(i, ii, iii). - StartNumber is the number of the first footnote.
- Footnote.Number is the number of a footnote in the text flow, starting with 1, and Text its text, including the footnote mark.
Read and Remove the Footnotes of a Document
The footnotes of a loaded document are in the same collection. The following program lists the footnotes of Documents/sample.docx, saves the text of the first one as HTML and removes all footnotes:
using TXTextControl;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Load("Documents/sample.docx", StreamType.WordprocessingML);
Console.WriteLine($"{tx.Footnotes.Count} footnotes, number format {tx.Footnotes.NumberFormat}");
foreach (Footnote footnote in tx.Footnotes)
{
Console.WriteLine($"{footnote.Number} at character {footnote.ReferenceMarkStart}: {footnote.Text}");
}
if (tx.Footnotes.Count > 0)
{
// The footnote text with its formatting, including the footnote mark
tx.Footnotes[1].Save(out string html, StringStreamType.HTMLFormat);
File.WriteAllText("footnote-1.html", html);
}
// Always remove the first remaining footnote
while (tx.Footnotes.Count > 0)
{
if (!tx.Footnotes.Remove(tx.Footnotes[1]))
{
break;
}
}
tx.Save("sample-without-footnotes.docx", StreamType.WordprocessingML);
}
The code works as follows:
- The indexer Item takes the number of a footnote from 1 to Count.
- ReferenceMarkStart is the one-based position of the reference mark in the main text, and ReferenceMarkLength its number of characters.
- Footnote.Save writes the footnote text to a string in a StringStreamType format or to a byte array in a
BinaryStreamTypeformat. - FootnoteCollection.Remove removes a footnote and returns
trueif it was removed. The numbers follow the text flow, soFootnotes[1]is always the first remaining footnote.
To find a single footnote, GetItem takes its name or ID and returns null if none matches. Without a parameter, it returns the footnote at the input position; with true or false, the next or previous footnote from the input position.
Format the Text of Footnotes
The text of all footnotes of a document is a text part of its own, a FootnoteText. Like the main text, it implements IFormattedText, with paragraphs, a selection, tables and images. The following program finds it in ServerTextControl.TextParts and sets all footnote paragraphs to 8-point italic text:
using TXTextControl;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Load("agreement.docx", StreamType.WordprocessingML);
foreach (IFormattedText textPart in tx.TextParts)
{
// The text of all footnotes of the document
if (textPart is FootnoteText footnoteText)
{
foreach (Paragraph paragraph in footnoteText.Paragraphs)
{
// Paragraph.Start is one-based, Selection.Start zero-based
footnoteText.Selection.Start = paragraph.Start - 1;
footnoteText.Selection.Length = paragraph.Length;
footnoteText.Selection.FontSize = 160;
footnoteText.Selection.Italic = true;
}
}
}
tx.Save("agreement-small-footnotes.docx", StreamType.WordprocessingML);
}
IFormattedText.Selection selects text within the footnote text only. Font sizes are in twips, so 160 is 8 points. The blog article Sneak Peek 32.0: Introducing Footnotes inserts formatted HTML into footnotes the same way, with Selection.Load.
Footnotes When Saving and Merging
- Leave footnotes out.
SaveSettings.OmittedContentwith the valueOmittedContent.Footnotessaves a document without its footnotes, as Saving and Converting Documents shows. This setting can't be used for PDF. - Optional footnotes in templates. A merge block that contains a footnote is removed with its footnote when its data is missing, as Conditional Content describes.
- Events. FootnoteCreated and FootnoteDeleted occur when a footnote is created or deleted. In a
FootnoteDeletedhandler, only theID,Nameand highlight settings of the footnote are valid, as Events lists.
Next Steps
- Tables of Contents: list the headings of a document with page numbers.
- Text: find and select text.
- Footnotes in the Document Editor: insert footnotes in the browser.
- Version 32.0: the release that introduced footnotes.