diff --git a/Michelf/MarkdownExtra.php b/Michelf/MarkdownExtra.php index e620f9e9..29ffc30d 100644 --- a/Michelf/MarkdownExtra.php +++ b/Michelf/MarkdownExtra.php @@ -1653,6 +1653,88 @@ protected function appendFootnotes($text) { return $text; } + /** + * Footnote title - get plaintext representation of a footnote for use in tooltip. + * @param string $footnote + * @return string + */ + protected function get_footnote_title( $footnote ) { + // Remove newlines from the source code so they don't become visible in the tooltip + // Replace with spaces so there's a suitable gap between adjacent elements + $footnote = str_replace("\n", " ", $footnote); + + // Turn the HTML of the footnote into a DOM + $doc = new \DOMDocument(); + $doc->loadHTML( mb_convert_encoding( $footnote, 'HTML', 'UTF-8' ), LIBXML_NOERROR); + $xp = new \DOMXPath( $doc ); + + // Replace each element with the text inside it + foreach ( $xp->query('//*/text()') as $node ) { + $p_text = $doc->createTextNode( $node->wholeText ); + $node->parentNode->replaceChild( $p_text, $node ); + } + + // Replace each
with a newline + foreach ( $xp->query('//br') as $node ) { + $br2nl = $doc->createTextNode( "\n" ); + $node->parentNode->replaceChild( $br2nl, $node ); + } + + // Replace each with its alt text + foreach ( $xp->query('//img') as $node ) { + $alt_text = $doc->createTextNode( $node->getAttribute('alt') . " " ); + $node->parentNode->replaceChild( $alt_text, $node ); + } + + // Replace each with its alt text + foreach ( $xp->query('//area') as $node ) { + $alt_text = $doc->createTextNode( $node->getAttribute('alt') . " " ); + $node->parentNode->replaceChild( $alt_text, $node ); + } + + // Get a plaintext representation + $title_text = trim( html_entity_decode( strip_tags( $doc->saveHTML() ) )); + + // Split by space + $parts = explode( " ", $title_text ); + + // Remove empty elements - strlen is needed to prevent text which evaluates to false from being removed + $parts = array_filter($parts, "strlen"); + + // Add each part to a new string until it is 200 characters long + $title_length = 200; + $title = ""; + + foreach ( $parts as $part) { + // Always add the first part + if ( mb_strlen( $title ) == 0 ) { + $title .= $part . " "; + // If the first part is a very long string, reduce it to the specified length + if ( mb_strlen( $title ) > $title_length ) { + $title = mb_substr( $title, 0, $title_length ); + $title .= "…"; + break; + } + } else if ( ( mb_strlen( $title ) + mb_strlen( $part ) ) < $title_length ) { + // Add the next whole word which doesn't take the total length over the specified length + $part = str_replace("\n ", "\n", $part); + + if ( $part == "\n" ) { + // Don't add spaces if it ends with a newline to prevent indenting. + $title .= $part; + } else { + $title .= $part . " "; + } + } else { + // If it has been truncated, add an ellipsis + $title = trim( $title ); + $title .= "…"; + break; + } + } + + return trim($title); + } /** * Generates the HTML for footnotes. Called by appendFootnotes, even if @@ -1760,8 +1842,10 @@ protected function _appendFootnotes_callback($matches) { $class = $this->encodeAttribute($class); $attr .= " class=\"$class\""; } - if ($this->fn_link_title !== "") { - $title = $this->fn_link_title; + if ($this->fn_link_title == "") { + // Decode any markdown in the footnote + $title = $this->get_footnote_title( $this->formParagraphs( $this->footnotes[$node_id] ) ); + // Format it to be suitable for a title tool-tip $title = $this->encodeAttribute($title); $attr .= " title=\"$title\""; } diff --git a/test/resources/php-markdown-extra.mdtest/Footnotes.text b/test/resources/php-markdown-extra.mdtest/Footnotes.text index 95b5ea80..8f536a68 100644 --- a/test/resources/php-markdown-extra.mdtest/Footnotes.text +++ b/test/resources/php-markdown-extra.mdtest/Footnotes.text @@ -14,7 +14,7 @@ This is the first paragraph.[^first] Some paragraph with a footnote[^1], and another[^2]. [^1]: Content for fifth footnote. -[^2]: Content for sixth footnote spaning on +[^2]: Content for sixth footnote spanning on three lines, with some span-level markup like _emphasis_, a [link][]. @@ -50,7 +50,7 @@ footnote test[^reference]. [^nested]: This footnote should appear even though it is referenced - from another footnote. But [^reference] should be litteral + from another footnote. But [^reference] should be literal since the footnote with that name has already been used. - - - @@ -68,3 +68,49 @@ Footnotes mixed with images[^image-mixed] [img6]: images/MGR-1800-travel.jpeg "Travel Speeds in 1800" [^image-mixed]: Footnote Content [img7]: images/MGR-1830-travel.jpeg "Travel Speeds in 1830" + +Alt text in images is exposed in the title[^imgalt]. +[^imgalt]: This is snuggle. Photo of a cute kitten. + +Very long footnotes are truncated at word boundaries[^long]. +[^long]: Sensors indicate no shuttle or other ships in this sector. According to coordinates, we have travelled 7,000 light years and are located near the system J-25. Tractor beam released, sir. Force field maintaining our hull integrity. Damage report? Sections 27, 28 and 29 on decks four, five and six destroyed. Without our shields, at this range it is probable a photon detonation could destroy the Enterprise. + +Although some titles may be split-mid emoji if they use ZWJ[^zwj]. +[^zwj]: 👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲 + +Fully multilingual[^中国文]. +[^中国文]: 两位皇子,你们各拥党羽,雄心勃勃地争取国柄和皇座,我们现在代表民众告诉你们:罗马人民已经众口一辞,公举素有忠诚之名的安德洛尼克斯作为统治罗马的君王,因为他曾经为罗马立下许多丰功伟绩,在今日的邦城之内,没有一个比他更高贵的男子,更英勇的战士。他这次奉着元老院的召唤,从征讨野蛮的哥特人的辛苦的战役中回国;凭着他们父子使敌人破胆的声威,已经镇伏了一个强悍善战的民族。自从他为了罗马的光荣开始出征、用武力膺惩我们敌人的骄傲以来,已经费了十年的时间;他曾经五次流着血护送他的战死疆场的英勇的儿子们的灵榇回到罗马来;现在这位善良的安德洛尼克斯,雄名远播的泰特斯,终于满载着光荣的战利品,旌旗招展,奏凯班师了。凭着你们所希望克绳遗武的先皇陛下的名义,凭着你们在表面上尊崇的议会的权力,让我们请求你们各自退下,解散你们的随从,用和平而谦卑的态度,根据你们本身的才德,提出你们合法的要求。 + +Also supports elements like ``[^ruby] +[^ruby]: +漢 (kan) +字 (ji) + + +Also Emoji[^🥰] compatible. +[^🥰]: 🥰 + +All the text present in a table should be in the title tooltip[^table]. +[^table]: + + + + + + ++ + + + + + + + + + + +
The table header
The table bodywith two columns
Footer
A demo table
+ +Markdown in a footnote is turned into plain text for the title[^mdtitle]. +[^mdtitle]: Markdown *emphasis* and a [link](https://example.com) \ No newline at end of file diff --git a/test/resources/php-markdown-extra.mdtest/Footnotes.xhtml b/test/resources/php-markdown-extra.mdtest/Footnotes.xhtml index fe0a4646..65b838cd 100644 --- a/test/resources/php-markdown-extra.mdtest/Footnotes.xhtml +++ b/test/resources/php-markdown-extra.mdtest/Footnotes.xhtml @@ -1,34 +1,52 @@ -

This is the first paragraph.1

+

This is the first paragraph.1

-

Header4

+

Header4

-

Some paragraph with a footnote5, and another6.

+

Some paragraph with a footnote5, and another6.

-

Another paragraph with a named footnote7.

+

Another paragraph with a named footnote7.

This paragraph should not have a footnote marker since the footnote is undefined.[^3]

-

This paragraph has a second footnote marker to footnote number one.5

+

This paragraph has a second footnote marker to footnote number one.5

This paragraph links to a footnote with plenty of -block-level content.8

+block-level content.8

This paragraph host the footnote reference within a -footnote test9.

+footnote test9.


-

Testing unusual footnote name10.

+

Testing unusual footnote name10.


-

Footnotes mixed with images111800 Travel1830 Travel

+

Footnotes mixed with images11 +1800 Travel +1830 Travel

+ +

Alt text in images is exposed in the title12.

+ +

Very long footnotes are truncated at word boundaries13.

+ +

Although some titles may be split-mid emoji if they use ZWJ14.

+ +

Fully multilingual15.

+ +

Also supports elements like <ruby><rp><rt>16

+ +

Also Emoji17 compatible.

+ +

All the text present in a table should be in the title tooltip18.

+ +

Markdown in a footnote is turned into plain text for the title19.


@@ -55,7 +73,7 @@ footnote test -

Content for sixth footnote spaning on +

Content for sixth footnote spanning on three lines, with some span-level markup like emphasis, a link↩︎

@@ -82,7 +100,7 @@ three lines, with some span-level markup like
  • -

    This footnote has a footnote of its own.12 ↩︎

    +

    This footnote has a footnote of its own.20 ↩︎

  • @@ -90,12 +108,68 @@ three lines, with some span-level markup like
  • -

    Footnote Content ↩︎

    +

    Footnote Content ↩︎

    +
  • + +
  • +

    This is snuggle. Photo of a cute kitten. ↩︎

    +
  • + +
  • +

    Sensors indicate no shuttle or other ships in this sector. According to coordinates, we have travelled 7,000 light years and are located near the system J-25. Tractor beam released, sir. Force field maintaining our hull integrity. Damage report? Sections 27, 28 and 29 on decks four, five and six destroyed. Without our shields, at this range it is probable a photon detonation could destroy the Enterprise. ↩︎

    +
  • + +
  • +

    👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲👨‍🦲 ↩︎

    +
  • + +
  • +

    两位皇子,你们各拥党羽,雄心勃勃地争取国柄和皇座,我们现在代表民众告诉你们:罗马人民已经众口一辞,公举素有忠诚之名的安德洛尼克斯作为统治罗马的君王,因为他曾经为罗马立下许多丰功伟绩,在今日的邦城之内,没有一个比他更高贵的男子,更英勇的战士。他这次奉着元老院的召唤,从征讨野蛮的哥特人的辛苦的战役中回国;凭着他们父子使敌人破胆的声威,已经镇伏了一个强悍善战的民族。自从他为了罗马的光荣开始出征、用武力膺惩我们敌人的骄傲以来,已经费了十年的时间;他曾经五次流着血护送他的战死疆场的英勇的儿子们的灵榇回到罗马来;现在这位善良的安德洛尼克斯,雄名远播的泰特斯,终于满载着光荣的战利品,旌旗招展,奏凯班师了。凭着你们所希望克绳遗武的先皇陛下的名义,凭着你们在表面上尊崇的议会的权力,让我们请求你们各自退下,解散你们的随从,用和平而谦卑的态度,根据你们本身的才德,提出你们合法的要求。 ↩︎

    +
  • + +
  • +

    +漢 (kan) +字 (ji) + ↩︎

    +
  • + +
  • +

    🥰 ↩︎

    +
  • + +
  • + + + + + + + ++ + + + + + + + + + + +
    The table header
    The table bodywith two columns
    Footer
    A demo table
    + +

    ↩︎

    +
  • + +
  • +

    Markdown emphasis and a link ↩︎

  • This footnote should appear even though it is referenced -from another footnote. But [^reference] should be litteral +from another footnote. But [^reference] should be literal since the footnote with that name has already been used. ↩︎