-
Notifications
You must be signed in to change notification settings - Fork 529
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Titles for footnotes #390
base: lib
Are you sure you want to change the base?
Titles for footnotes #390
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 <br> with a newline | ||
foreach ( $xp->query('//br') as $node ) { | ||
$br2nl = $doc->createTextNode( "\n" ); | ||
$node->parentNode->replaceChild( $br2nl, $node ); | ||
} | ||
|
||
// Replace each <img> 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 <area> 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] ) ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's unfortunate we're calling `formParagraph twice for every footnote now. Once for the footnote reference, and once for the actual footnote at the end of the document. More than twice if there is more than one references to the same footnote. I think this requires more strategy. |
||
// Format it to be suitable for a title tool-tip | ||
$title = $this->encodeAttribute($title); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure |
||
$attr .= " title=\"$title\""; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic doesn't make much sense. If a title was specified by
fn_link_title
it shouldn't be ignored. There should be anelse
clause.