1<?php 2if(!defined('DOKU_INC')) die(); 3 4/** 5 * Auto-Tooltip DokuWiki plugin 6 * 7 * @license MIT 8 * @author Eli Fenton 9 */ 10class helper_plugin_autotooltip extends DokuWiki_Admin_Plugin { 11 private $localRenderer; 12 13 public function __construct() { 14 $this->localRenderer = new Doku_Renderer_xhtml; 15 } 16 17 18 /** 19 * Return a simple tooltip. 20 * 21 * @param string $content - The on-page content. May contain newlines. 22 * @param string $tooltip - The tooltip content. Newlines will be rendered as line breaks. 23 * @param string $title - The title inside the tooltip. 24 * @param string $preTitle - Text to display before the title. Newlines will be rendered as line breaks. 25 * @param string $classes - CSS classes to add to this tooltip. 26 * @param string $textStyle - CSS styles for the linked content 27 * @return string 28 */ 29 function forText($content, $tooltip, $title='', $preTitle = '', $classes = '', $textStyle = '') { 30 if (empty($classes)) { 31 $classes = $this->getConf('style'); 32 } 33 if (empty($classes)) { 34 $classes = 'default'; 35 } 36 37 // Sanitize 38 $classes = htmlspecialchars($classes); 39 // Add the plugin prefix to all classes. 40 $classes = preg_replace('/(\w+)/', 'plugin-autotooltip__$1', $classes); 41 42 $partCount = (empty($title) ? 0 : 1) + (empty($preTitle) ? 0 : 1) + (empty($tooltip) ? 0 : 1); 43 if ($partCount > 1 || strchr($tooltip, "\n") !== FALSE || strlen($tooltip) > 40) { 44 $classes .= ' plugin-autotooltip_big'; 45 } 46 47 $textClass = ''; 48 if (empty($textStyle)) { 49 $textClass = 'plugin-autotooltip_linked'; 50 if (strstr($content, '<a ') === FALSE) { 51 $textClass .= ' plugin-autotooltip_simple'; 52 } 53 } 54 55 $contentParts = []; 56 if (!empty($preTitle)) { 57 $contentParts[] = $this->_formatTT($preTitle); 58 } 59 if (!empty($title)) { 60 $contentParts[] = '<span class="plugin-autotooltip-title">' . $title . '</span>'; 61 } 62 if (!empty($tooltip)) { 63 $contentParts[] = $this->_formatTT($tooltip); 64 } 65 66 return '<span class="' . $textClass . '" style="' . $textStyle . '" onmouseover="autotooltip.show(this)" onmouseout="autotooltip.hide()">' . 67 $content . 68 '<span class="plugin-autotooltip-hidden-classes">' . $classes . '</span>' . 69 '<span class="plugin-autotooltip-hidden-tip">' . 70 implode('<br><br>', $contentParts) . 71 '</span>' . 72 '</span>'; 73 } 74 75 76 /** 77 * Render a tooltip, with the title and abstract of a page. 78 * 79 * @param string $id - A page id. 80 * @param string $content - The on-page content. Newlines will be rendered as line breaks. Omit to use the page's title. 81 * @param string $preTitle - Text to display before the title in the tooltip. Newlines will be rendered as line breaks. 82 * @param string $classes - CSS classes to add to this tooltip. 83 * @param string $linkStyle - Style attribute for the link. 84 * @return string 85 */ 86 function forWikilink($id, $content = null, $preTitle = '', $classes = '', $linkStyle = '') { 87 $title = p_get_metadata($id, 'title'); 88 $abstract = p_get_metadata($id, 'description abstract'); 89 90 // By default, the abstract starts with the title. Remove it so it's not displayed twice, but still fetch 91 // both pieces of metadata, in case another plugin rewrote the abstract. 92 $abstract = preg_replace('/^' . $this->_pregEscape($title) . '(\r?\n)+/', '', $abstract); 93 94 $link = $this->localRenderer->internallink($id, $content ?: $title, null, true); 95 96 if (!empty($linkStyle)) { 97 $link = preg_replace('/<a /', '<a style="' . $linkStyle . '" ', $link); 98 } 99 100 if (page_exists($id)) { 101 // Remove the title attribute, since we have a better tooltip. 102 $link = preg_replace('/title="[^"]*"/', '', $link); 103 return $this->forText($link, $abstract, $title, $preTitle, $classes); 104 } 105 else { 106 return $link; 107 } 108 } 109 110 111 /** 112 * Format tooltip text. 113 * 114 * @param string $tt - Tooltip text. 115 * @return string 116 */ 117 private function _formatTT($tt) { 118 // Convert double-newlines into vertical space. 119 $tt = preg_replace('/(\r?\n){2,}/', '<br><br>', $tt); 120 // Single newlines get collapsed, just like in HTML. 121 return preg_replace('/(\r?\n)/', ' ', $tt); 122 } 123 124 125 /** 126 * Escape a string for inclusion in a regular expression, assuming forward slash is used as the delimiter. 127 * 128 * @param string $r - The regex string, without delimiters. 129 * @return string 130 */ 131 private function _pregEscape($r) { 132 return preg_replace('/\//', '\\/', preg_quote($r)); 133 } 134} 135