Fossil

Check-in [2b1375ab]
Login

Check-in [2b1375ab]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Clean-up and polish relevant CSS and HTML's class names. Insure visual spacing between footnotes' markers so that numbers are distinguishable when multiple footnotes in a row are used. Factor out auxiliary decorations from HTML into the default CSS, to enable customization via skins.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | markdown-footnotes
Files: files | file ages | folders
SHA3-256: 2b1375abadb4f86c328ad9d9d64dcec444e9a91de04339563ba5a94c8a065dfd
User & Date: george 2022-02-10 23:00:32
Context
2022-02-11
01:26
Fix parsing of a multiline definition of labeled footnote for the case when lines end with CR+LF. ... (check-in: ea66d15c user: george tags: markdown-footnotes)
2022-02-10
23:00
Clean-up and polish relevant CSS and HTML's class names. Insure visual spacing between footnotes' markers so that numbers are distinguishable when multiple footnotes in a row are used. Factor out auxiliary decorations from HTML into the default CSS, to enable customization via skins. ... (check-in: 2b1375ab user: george tags: markdown-footnotes)
2022-02-09
22:59
Handle unreferenced footnotes. If a labeled footnote is defined but there are no references to it, then add a special item at the end of footnotes. This item includes a label and the text of the strayed footnote - both rendered verbatim via html_escape(). Default skin makes such items visible and easily distinguishable. The order of such items match the order in the underlying source code. ... (check-in: ada55cd4 user: george tags: markdown-footnotes)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/default.css.

1663
1664
1665
1666
1667
1668
1669

1670
1671
1672
1673
1674
1675
1676
1677

1678
1679


1680
1681
1682
1683
1684
1685
1686

1687
1688
1689
1690


1691
1692
1693









1694

1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707

1708
1709
1710
1711
1712






1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
body.branch .submenu > a.timeline-link.selected {
  display: inline;
}

.monospace {
  font-family: monospace;
}

div.content  div.markdown > ol.footnotes {
  font-size: 90%;
}
div.content  div.markdown > ol.footnotes > li {
  margin-bottom: 0.5em;
}
div.markdown ol.footnotes > li.misreferences {
  background: #ffdddd;

}
div.markdown ol.footnotes > li.unreferenced:first-child,


div.markdown ol.footnotes > li.misreferences {
  margin-top:     0.75em;
  padding-top:    0.25em;
  padding-bottom: 0.25em;
}
div.markdown ol.footnotes > li.unreferenced {
  padding-left: 0.5em;

  color: gray;
}
div.markdown ol.footnotes > li.unreferenced > code {
  color: red;


  font-weight: bold;
}
div.markdown ol.footnotes > li.unreferenced > pre {









  color: gray;

  padding-left: 0.5em;
  margin-top:  0.25em;
  border-left: 3px solid red;
}
div.content  div.markdown > ol.footnotes > li > .footnote-backrefs {
  margin-right: 0.5em;
  font-weight: bold;
}
div.markdown > ol.footnotes > li > .footnote-backrefs > a:target {
  background: gold;
}
div.markdown sup.noteref > a:target {
  background: gold;

}
div.markdown sup.noteref.misref,
div.markdown sup.noteref.misref > a {
  color: red;
  font-size: 90%;






}
div.markdown span.notescope:hover,
div.markdown span.notescope:target {
  border-bottom: 2px solid gold;
}
div.markdown span.notescope:hover  > sup.noteref > a,
div.markdown span.notescope:target > sup.noteref > a {
  background: gold;
}

/* Objects in the "desktoponly" class are invisible on mobile */
@media screen and (max-width: 600px) {
  .desktoponly {
    display: none;
  }
}







>
|


|


|
|
>

|
>
>
|
|
<
|

|
<
>


|

>
>
|

|
>
>
>
>
>
>
>
>
>

>


|

|



|
<
<
|
|
>





>
>
>
>
>
>





<
<
<
<







1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685

1686
1687
1688

1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718


1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737




1738
1739
1740
1741
1742
1743
1744
body.branch .submenu > a.timeline-link.selected {
  display: inline;
}

.monospace {
  font-family: monospace;
}

div.markdown > ol.footnotes {
  font-size: 90%;
}
div.markdown > ol.footnotes > li {
  margin-bottom: 0.5em;
}
div.markdown ol.footnotes > li.fn-joined > sup.fn-joined {
  color: gray;
  font-family: monospace;
}
div.markdown ol.footnotes > li.fn-joined > sup.fn-joined::after {
  content: "(joined from multiple locations) ";
}
div.markdown ol.footnotes > li.fn-misreference {
  margin-top:    0.75em;

  margin-bottom: 0.75em;
}
div.markdown ol.footnotes > li.fn-misreference,

div.markdown ol.footnotes > li.fn-unreferenced {
  color: gray;
}
div.markdown ol.footnotes > li.fn-misreference > span {
  color: red;
}
div.markdown ol.footnotes > li.fn-misreference > span::after {
  content: " (use of undefined label).";
}
div.markdown ol.footnotes > li.fn-unreferenced {
  padding-left: 0.5em;
}
div.markdown ol.footnotes > li.fn-unreferenced > code {
  color: red;
}
div.markdown ol.footnotes > li.fn-unreferenced > i::after {
  content: " was defined but is not referenced";
}
div.markdown ol.footnotes > li.fn-unreferenced > pre {
  color: gray;
  font-size: 85%;
  padding-left: 0.5em;
  margin-top:  0.25em;
  border-left: 2px solid red;
}
div.markdown > ol.footnotes > li > .fn-backrefs {
  margin-right: 0.5em;
  font-weight: bold;
}
div.markdown > ol.footnotes > li > .fn-backrefs > a,


div.markdown sup.noteref > a {
  padding-left:  2px;
  padding-right: 2px;
}
div.markdown sup.noteref.misref,
div.markdown sup.noteref.misref > a {
  color: red;
  font-size: 90%;
}
div.markdown sup.noteref > a:target,
div.markdown span.notescope:target > sup.noteref > a,
div.markdown span.notescope:hover  > sup.noteref > a,
div.markdown > ol.footnotes > li > .fn-backrefs > a:target {
  background: gold;
}
div.markdown span.notescope:hover,
div.markdown span.notescope:target {
  border-bottom: 2px solid gold;
}





/* Objects in the "desktoponly" class are invisible on mobile */
@media screen and (max-width: 600px) {
  .desktoponly {
    display: none;
  }
}

Changes to src/markdown.c.

2584
2585
2586
2587
2588
2589
2590

2591
2592
2593
2594
2595
2596
2597
2598
        k += blob_size(&fn[j].text) + 10;
        j++;
        nDups++;
      }
      if( i+1<j ){
        Blob tmp = empty_blob;
        blob_reserve(&tmp, k);

        blob_append_string(&tmp, "<ul class='footnote-joined'>\n");
        for(k=i; k<j; k++){
          struct footnote *y = fn + k;
          blob_append_string(&tmp, "<li>");
          blob_append(&tmp, blob_buffer(&y->text), blob_size(&y->text));
          blob_append_string(&tmp, "</li>\n");

          /* free memory buffer */







>
|







2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
        k += blob_size(&fn[j].text) + 10;
        j++;
        nDups++;
      }
      if( i+1<j ){
        Blob tmp = empty_blob;
        blob_reserve(&tmp, k);
        /* must match _joined_footnote_indicator in html_footnote_item() */
        blob_append_string(&tmp, "<ul class='fn-joined'>\n");
        for(k=i; k<j; k++){
          struct footnote *y = fn + k;
          blob_append_string(&tmp, "<li>");
          blob_append(&tmp, blob_buffer(&y->text), blob_size(&y->text));
          blob_append_string(&tmp, "</li>\n");

          /* free memory buffer */

Changes to src/markdown_html.c.

381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406



407
408



409
410
411
412
413
414
415

416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436




437



438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
  const char * const unique = ((struct MarkdownToHtml*)opaque)->unique.c;
  assert( nUsed >= 0 );
  /* expect BUGs if the following yields compiler warnings */

  if( iMark < 0 ){                     /* misreferences */
    assert( iMark == -1 );
    if( !nUsed ) return;
    BLOB_APPEND_LITERAL(ob,"<li class='misreferences'>"
                              "<sup class='footnote-backrefs'>");
    if( nUsed == 1 ){
      blob_appendf(ob,"<a id='misreference%s-a' "
                      "href='#misref%s-a'>^</a>", unique, unique);
    }else{
      int i;
      blob_append_char(ob, '^');
      for(i=0; i<nUsed && i<26; i++){
        const int c = i + (unsigned)'a';
        blob_appendf(ob," <a id='misreference%s-%c' "
              "href='#misref%s-%c'>%c</a>", unique,c, unique,c, c);
      }
      if( i < nUsed ) BLOB_APPEND_LITERAL(ob," &hellip;");
    }
    BLOB_APPEND_LITERAL(ob,"</sup>\nMisreference: use of undefined label.");

  }else if( nUsed ){                   /* a regular footnote */
    char pos[24];



    assert( text );
    assert( blob_size(text) );




    memset(pos,0,24);
    sprintf(pos, "%s-%i", unique, iMark);

    blob_appendf(ob, "<li id='footnote%s'>", pos);
    BLOB_APPEND_LITERAL(ob,"<sup class='footnote-backrefs'>");
    if( nUsed <= 1 ){

      blob_appendf(ob,"<a id='footnote%s-a' "
                       "href='#noteref%s-a'>^</a>", pos, pos);
    }else{
      int i;
      blob_append_char(ob, '^');
      for(i=0; i<nUsed && i<26; i++){
        const int c = i + (unsigned)'a';
        blob_appendf(ob," <a id='footnote%s-%c'"
                         " href='#noteref%s-%c'>%c</a>", pos,c, pos,c, c);
      }
      /* It's unlikely that so many backrefs will be usefull */
      /* but maybe for some machine generated documents... */
      for(; i<nUsed && i<676; i++){
        const bitfield64_t l = to_base26(i,0);
        blob_appendf(ob," <a id='footnote%s-%s'"
                         " href='#noteref%s-%s'>%s</a>",
                         pos,l.c, pos,l.c, l.c);
      }
      if( i < nUsed ) BLOB_APPEND_LITERAL(ob," &hellip;");
    }
    BLOB_APPEND_LITERAL(ob,"</sup>\n");




    BLOB_APPEND_BLOB(ob, text);



  }else{
    /* a footnote was defined but wasn't used */
    /* make.footnote_item() invocations should pass args accordingly */
    const struct Blob * id = text-1;
    assert( text );
    assert( blob_size(text) );
    assert( blob_size(id) );
    BLOB_APPEND_LITERAL(ob,"<li class='unreferenced'>\n[^&nbsp;<code>");
    html_escape(ob, blob_buffer(id), blob_size(id));
    BLOB_APPEND_LITERAL(ob, "</code>&nbsp;] "
        "<i>was defined but is not referenced</i>\n"
        "<pre><code class='language-markdown'>");
    html_escape(ob, blob_buffer(text), blob_size(text));
    BLOB_APPEND_LITERAL(ob,"</code></pre>");
  }
  BLOB_APPEND_LITERAL(ob, "\n</li>\n");
}
static void html_footnotes(







|
|













|



>
>
>


>
>
>
|


<
|
|
|
>




|
















>
>
>
>
|
>
>
>







|

|
<







381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417

418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460

461
462
463
464
465
466
467
  const char * const unique = ((struct MarkdownToHtml*)opaque)->unique.c;
  assert( nUsed >= 0 );
  /* expect BUGs if the following yields compiler warnings */

  if( iMark < 0 ){                     /* misreferences */
    assert( iMark == -1 );
    if( !nUsed ) return;
    BLOB_APPEND_LITERAL(ob,"<li class='fn-misreference'>"
                              "<sup class='fn-backrefs'>");
    if( nUsed == 1 ){
      blob_appendf(ob,"<a id='misreference%s-a' "
                      "href='#misref%s-a'>^</a>", unique, unique);
    }else{
      int i;
      blob_append_char(ob, '^');
      for(i=0; i<nUsed && i<26; i++){
        const int c = i + (unsigned)'a';
        blob_appendf(ob," <a id='misreference%s-%c' "
              "href='#misref%s-%c'>%c</a>", unique,c, unique,c, c);
      }
      if( i < nUsed ) BLOB_APPEND_LITERAL(ob," &hellip;");
    }
    BLOB_APPEND_LITERAL(ob,"</sup>\n<span>Misreference</span>");

  }else if( nUsed ){                   /* a regular footnote */
    char pos[24];
    const char *join = "";
    #define _joined_footnote_indicator "<ul class='fn-joined'>"
    #define _jfi_sz (sizeof(_joined_footnote_indicator)-1)
    assert( text );
    assert( blob_size(text) );
    if( blob_size(text)>=_jfi_sz &&
       !memcmp(blob_buffer(text),_joined_footnote_indicator,_jfi_sz)){
      join = "fn-joined ";
    }
    memset(pos,0,24);
    sprintf(pos, "%s-%i", unique, iMark);

    blob_appendf(ob, "<li id='footnote%s' class='%s", pos, join);

    if( nUsed == 1 ){
      BLOB_APPEND_LITERAL(ob, "fn-monoref'><sup class='fn-backrefs'>");
      blob_appendf(ob,"<a id='footnote%s-a' "
                       "href='#noteref%s-a'>^</a>", pos, pos);
    }else{
      int i;
      BLOB_APPEND_LITERAL(ob, "fn-polyref'><sup class='fn-backrefs'>^");
      for(i=0; i<nUsed && i<26; i++){
        const int c = i + (unsigned)'a';
        blob_appendf(ob," <a id='footnote%s-%c'"
                         " href='#noteref%s-%c'>%c</a>", pos,c, pos,c, c);
      }
      /* It's unlikely that so many backrefs will be usefull */
      /* but maybe for some machine generated documents... */
      for(; i<nUsed && i<676; i++){
        const bitfield64_t l = to_base26(i,0);
        blob_appendf(ob," <a id='footnote%s-%s'"
                         " href='#noteref%s-%s'>%s</a>",
                         pos,l.c, pos,l.c, l.c);
      }
      if( i < nUsed ) BLOB_APPEND_LITERAL(ob," &hellip;");
    }
    BLOB_APPEND_LITERAL(ob,"</sup>\n");
    if( join[0] ){
      BLOB_APPEND_LITERAL(ob,"<sup class='fn-joined'></sup><ul>");
      blob_append(ob,blob_buffer(text)+_jfi_sz,blob_size(text)-_jfi_sz);
    }else{
      BLOB_APPEND_BLOB(ob, text);
    }
    #undef _joined_footnote_indicator
    #undef _jfi_sz
  }else{
    /* a footnote was defined but wasn't used */
    /* make.footnote_item() invocations should pass args accordingly */
    const struct Blob * id = text-1;
    assert( text );
    assert( blob_size(text) );
    assert( blob_size(id) );
    BLOB_APPEND_LITERAL(ob,"<li class='fn-unreferenced'>\n[^&nbsp;<code>");
    html_escape(ob, blob_buffer(id), blob_size(id));
    BLOB_APPEND_LITERAL(ob, "</code>&nbsp;]<i></i>\n"

        "<pre><code class='language-markdown'>");
    html_escape(ob, blob_buffer(text), blob_size(text));
    BLOB_APPEND_LITERAL(ob,"</code></pre>");
  }
  BLOB_APPEND_LITERAL(ob, "\n</li>\n");
}
static void html_footnotes(

Changes to test/markdown-test3.md.

49
50
51
52
53
54
55



56
57
58
59
60
61
62
This can be overridden by the skin though.

The refenrence at the end of this sentence is the sole reason of
rendering of <s>`lost1` and</s> [lost2][^].

If several labeled footnote definitions have the same equal label then texts
from all these definitions are joined.[^duplicate]




## Footnotes

[branch]: /timeline?r=markdown-footnotes&nowiki

[^ 1]:  Footnotes is a Fossil' extention of
        Markdown. Your other tools may have limited support for these.







>
>
>







49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
This can be overridden by the skin though.

The refenrence at the end of this sentence is the sole reason of
rendering of <s>`lost1` and</s> [lost2][^].

If several labeled footnote definitions have the same equal label then texts
from all these definitions are joined.[^duplicate]

Several references should be recognized as several distinct numbers.
(^There should be an interval between numbers.) [^many-refs]

## Footnotes

[branch]: /timeline?r=markdown-footnotes&nowiki

[^ 1]:  Footnotes is a Fossil' extention of
        Markdown. Your other tools may have limited support for these.