Improve Footnotes

The goal is not to rebuild LaTeX[1], but to give users an easy way to add footnotes to their wiki text.



1. Footnotes


we differentiate between

  1. introductory footnotes
  2. reference footnotes

we have two ways

  1. manual footnotes, meaning the user can create random links and anchors
  2. aggregated footnotes

The following suggested improvements relate all to aggregated footnotes.

1.1. Types

symbols note
Introductory footnotes
*, †, ‡, §, ‖, ¶, **, ††, ‡‡, §§, ‖‖, ¶¶ For introductory [type 1] footnotes use these symbols (always as superscripts) (in the order listed), if there are 12 or fewer footnotes.
a, b, c, etc. Use lowercase letters, if there are 13 or more footnotes.
Reference footnotes
1, 2, 3, etc. Reference footnotes [type 2] are noted in text by the insertion of numerals as either a superscript or on line.

1.1.1. Introductory


For introductory [type 1] footnotes use these symbols (always as superscripts): *, †, ‡, §, ‖, ¶, **, ††, ‡‡, §§, ‖‖, ¶¶ (in the order listed), if there are 12 or fewer footnotes. Use lowercase letters a, b, c, etc., if there are 13 or more footnotes. For example, an introductory footnote which refers to an author’s name will appear as J. M. Smith∗ in the author’s byline citation and will appear either as the first reference in the listing at the end of the paper or at the bottom of the page on which they appear.

1.1.2. Reference citations


Reference footnotes [type 2] are noted in text by the insertion of numerals as either a superscript or on line in this manner:
Smith2 does not agree with the original values given in Ref. 1.


The use of a superscript is preferred. When that use could possibly cause confusion (i.e., Pb4), the on-line form should be used [Pb (Ref. 4)]. In the footnote listing at the end of the paper use only the superscript form.

2. Denominators

The WackoFormatter splits the footnote in two parts, $denominator and $text.


I think we should offer the option to set your own aggregated footnote denominators:
[[^ footnote]] - auto-numbering
[[^#10 footnote]] - resets start for auto-numbering
[[^1 footnote]] - uses specified denominator
[[^a footnote]]
[[^ab footnote]]
[[^‡ Footnote]]


Now I wonder how we can mix the auto-numbering and the individual denominators concept.


Anything other than automatic numbering I consider a special case, mostly introductory footnotes, but useful especially when reproducing an existing document.

2.1. Issues

2.1.1. Replace experimental syntax

Change the experimental syntax for aggregated footnotes to [[^ footnote]] which no longer consumes the fn name space.

2.1.2. What happens when we have a footnote set a second time with the same denominator.

[[^b footnote]]
[[^b another footnote]] <-- if we have a second footnote with the same denominator and another footnote

  • it discards the individually set denominator and takes just the next denominator, simple and neat

Or
[[^ footnote]] <-- first footnote
[[^1 footnote]]


The strength of auto-numbering is also its weakness, when I add a new footnote the denominators for all following footnotes will change.


If the user accidentally reuses a already set footnote denominator it defaults to auto-numbering.

2.1.3. Then we have the case where we want refer in two places in the document to the same footnote.

[[^c footnote]]
[[^c]] <-- takes existing array, if there is one


If only a empty denominator is set [[^c]], then there is no corresponding footnote and the link goes to nowhere.

2.1.4. What denominators do we allow?

This is mainly a question regarding user input validation and sanitization.
[\p{L},\d,*,†,‡,§,‖,¶]


If the user accidentally uses a invalid character it defaults to auto-numbering.


Do we need a further restriction to Latin characters?

2.1.5. Allow multi-line auto-generated footnotes.

Conflicts with single-line markup rule for link syntax!
There are workaround to add line-breaks, via HTML (<br>) or Wiki syntax (---).

2.1.6. Custom Legend

I think it would be nice to give the user the opportunity to name the field with footnotes depending on the content. For example, in one article it can be "Notes", in another "References" or "List of ..."
Such as "legend" for textarea. -- Abram4

An additional action could be used to determine where and if the footnotes should be shown. We could parse footnotes like the {{toc}}.
We can add a {{footnotes}} action which passes some parameters to the formatter, I got some ideas but I have to play a few things through to get a picture of what is feasible and still simple and intuitive.


This however means that the footnotes must be processed in the PostWacko processor, and that like with the headings in the toc action, the footnotes (or references if you want) must be parsed into a separate location (table field). This would enable then also parsing footnote across included pages.

2.1.7. Should the footnote array be sorted or build as is?

2.1.8. Should the footnote array be parsed in a $wacko object instead of a $this formatter object?


Currently it outputs the footnote array for each cycle and some embedded formatters like info or detail calling the WackoFormatter again to parse the content. This can be changed by writing the footnotes to a $wacko object and set a flag for these formatters so it do not gives out the footnotes for them. Then however it will start auto-counting the denominators of these instances first no matter where these formatters were called in the text.

2.1.9. How it should deal with footnotes from included pages?

Again, here is the main question should we process the footnotes via the post_wacko formatter (action) or not, everything else depends on the way the footnotes are parsed and processed.


3. Limitations


aggregated footnotes

  • footnote fail if they contain a line break
  • does not work with included pages
  • do currently work not across formatters

4. Formatter Patch


copy and paste


/src/formatter/class/wackoformatter.php

<?php

// auto-generated footnote [[^ footnote here]]
else if ($url[0] == '^')
{
    $anchor = mb_substr($url, 1);

    // #18 syntax support
    if (preg_match('/^\#\d{1,3}$/u', $anchor))
    {
        $this->auto_fn['count'] = mb_substr($anchor, 1) - 1;
    }

    // validate and sanitize $anchor
    if (!preg_match('/^([\p{L}\d*†‡§‖¶])*$/u', $anchor))
    {
        $anchor = '';
    }
    // discard already set denominators, simple and neat
    else if (isset($this->auto_fn['content'][$anchor]) && $text)
    {
        $anchor = '';
    }

    // set denominator
    if ($anchor)
    {
        $fn_count = $anchor;
    }
    else
    {
        $this->auto_fn['count'] ??= 0;
        $this->auto_fn['count']++;

        $fn_count = $this->auto_fn['count'];
    }

    if ($text)
    {
        $this->auto_fn['content'] ??= null;
        $this->auto_fn['content'][$fn_count] = trim($text);
    }

    return
        '<sup class="footnote">' .
            '<a href="#footnote-' . $fn_count . '" id="footnote-' . $fn_count . '-ref" title="footnote ' . $fn_count . '">' .
                '[' . $fn_count . ']' .
            '</a>' .
        '</sup>';
}

5. Update the syntax


The installer will update the syntax in the body of the page table for 6.0.30 and 6.1.9.


{{upgrade_footnote_syntax}}


action/upgrade_footnote_syntax.php

<?php

if (!defined('IN_WACKO'))
{
    exit;
}

// TODO: Run a SELECT query before the UPDATE to check if there are matches with the old syntax at all.
//        SELECT * FROM `wacko_page` WHERE `body` LIKE '%[[fn %' ORDER BY `page_id` DESC

$pref = $this->db->table_prefix;

if ($this->is_admin())
{
    echo '<h2>Update Footnote Syntax:</h2>';
    echo '<p>Indiscriminately replaces the deprecated syntax for aggregated footnotes with the new syntax.<br>' .
            '<code>[[fn footnote here]] -> [[^ footnote here]]</code><br>' .
            'This issue exists only if you used auto-generated footnotes.</p>';
    echo '<p>CREATE a BACKUP of your database BEFORE you continue!</p>';

    if (!isset($_POST['reset_footnotes']))
    {
        echo $this->form_open('reset_footnotes');
        echo '<button type="submit" name="reset_footnotes">' . $this->_t('UpdateButton') . '</button>';
        echo $this->form_close();
    }
    else if (isset($_POST['reset_footnotes']))
    {
        // 1a. update body in page table
        $this->db->sql_query("
            UPDATE {$pref}page SET
                body = REPLACE(body, '[[fn ', '[[^ ');");

        // 1b. update body in page table
        $this->db->sql_query("
            UPDATE {$pref}page SET
                body = REPLACE(body, '((fn ', '((^ ');");

        // 2a. update body in revision table
        /* $this->db->sql_query("
            UPDATE {$pref}revision SET
                body = REPLACE(body, '[[fn ', '[[^ ');"); */

        // 2b. update body in revision table
        /* $this->db->sql_query("
            UPDATE {$pref}revision SET
                body = REPLACE(body, '((fn ', '((^ ');"); */

    }
}

6. WikiEdit

Add footnote button, mainly to solve usability issues with different keyboard layouts accessing the ^ character.
Empty footnote removes space, but it should keep the space: [[^ ]]

7. Testing

Batch One

[[^* footnote 1]]
[[^1a footnote 2]]
[[^1a footnote 3]]
[[^a footnote 4]]
[[^a footnote 5]]
[[^2 footnote 6]]
[[^ footnote 7]]
[[^ footnote 8]]
[[^ footnote 9]]
[[^ footnote 10]]
[[^5]] repeated reference
[[^ footnote 11]]
[[^ footnote 12]]
[[^‡ footnote 13]]
[[^‡ footnote 14]]
[[^ footnote 15]]
[[^ footnote 16]]
[[^ footnote 17]]
[[^ footnote 18]]	

Batch Two

[[^ footnote 1]]
[[^ footnote 2]]
[[^ footnote 3]]
[[^5]] repeated reference
[[^ footnote 4]]
[[^ footnote 5]]
[[^ footnote 6]]
[[^ footnote 7]]
[[^ footnote 8]]
[[^ footnote 9]]
[[^ footnote 10]]

[[^ footnote 11]]
[[^ footnote 12]]
[[^ footnote 13]]
[[^ footnote 14]]
[[^ footnote 15]]
[[^ footnote 16]]
[[^ footnote 17]]
[[^ footnote 18]]	

8. Documentation


The new syntax enables the user also to set his own aggregated footnote denominators:


*, †, ‡, §, ‖, ¶
a, b, c, ...
1, 2, 3, ...


This can be used as following:
[[^§ footnote]]


Double entry

If you add accidentally a custom denominator twice, or the denominator is already set, then it is either linked to the already existing footnote, when you have set only the denominator and not a footnote, otherwise this denominator will simply discarded and be replaced by the next auto-denominator.


Case 1
[5]
[5] repeated reference --> sets only a reference to the existing footnote


Case 2
[1]
[2] --> discards repeated denominator and continues with auto-numbering


Footnotes:

[5]
footnote 5
[1]
footnote 5
[2]
second footnote 5


Footnotes:

[1]
When writing, the writer uses plain text as opposed to the formatted text found in "What You See Is What You Get" word processors. The writer uses markup tagging conventions to define the general structure of a document to stylise text throughout a document (such as bold and italics), and to add citations and cross-references.