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 methods of this helper 20 * 21 * @return array with methods description 22 */ 23 function getMethods() { 24 $result = array(); 25 $result[] = array( 26 'name' => 'forText', 27 'desc' => 'Manually construct a tooltip', 28 'params' => array( 29 'content' => 'string', 30 'tooltip' => 'string', 31 'title (optional)' => 'string', 32 'preTitle (optional)' => 'string', 33 'classes (optional)' => 'string', 34 'textStyles (optional)' => 'string', 35 ), 36 'return' => array('result' => 'string') 37 ); 38 $result[] = array( 39 'name' => 'forWikilink', 40 'desc' => 'Generate a tooltip from a wikilink', 41 'params' => array( 42 'id' => 'string', 43 'content (optional)' => 'string', 44 'preTitle (optional)' => 'string', 45 'classes (optional)' => 'string', 46 'textStyles (optional)' => 'string', 47 ), 48 'return' => array('result' => 'string') 49 ); 50 return $result; 51 } 52 53 54 /** 55 * Return a simple tooltip. 56 * 57 * @param string $content - The on-page content. May contain newlines. 58 * @param string $tooltip - The tooltip content. Newlines will be rendered as line breaks. 59 * @param string $title - The title inside the tooltip. 60 * @param string $preTitle - Text to display before the title. Newlines will be rendered as line breaks. 61 * @param string $classes - CSS classes to add to this tooltip. 62 * @param string $textStyle - CSS styles for the linked content 63 * @return string 64 */ 65 function forText($content, $tooltip, $title='', $preTitle = '', $classes = '', $textStyle = '') { 66 if (empty($classes)) { 67 $classes = $this->getConf('style'); 68 } 69 if (empty($classes)) { 70 $classes = 'default'; 71 } 72 73 // Sanitize 74 $classes = htmlspecialchars($classes); 75 // Add the plugin prefix to all classes. 76 $classes = preg_replace('/(\w+)/', 'plugin-autotooltip__$1', $classes); 77 78 $partCount = (empty($title) ? 0 : 1) + (empty($preTitle) ? 0 : 1) + (empty($tooltip) ? 0 : 1); 79 if ($partCount > 1 || strchr($tooltip, "\n") !== FALSE || strlen($tooltip) > 40) { 80 $classes .= ' plugin-autotooltip_big'; 81 } 82 83 $textClass = ''; 84 if (empty($textStyle)) { 85 $textClass = 'plugin-autotooltip_linked'; 86 if (strstr($content, '<a ') === FALSE) { 87 $textClass .= ' plugin-autotooltip_simple'; 88 } 89 } 90 91 $contentParts = []; 92 if (!empty($preTitle)) { 93 $contentParts[] = $this->_formatTT($preTitle); 94 } 95 if (!empty($title)) { 96 $contentParts[] = '<span class="plugin-autotooltip-title">' . $title . '</span>'; 97 } 98 if (!empty($tooltip)) { 99 $contentParts[] = $this->_formatTT($tooltip); 100 } 101 102 return '<span class="' . $textClass . '" style="' . $textStyle . '" onmouseover="autotooltip.show(this)" onmouseout="autotooltip.hide()">' . 103 $content . 104 '<span class="plugin-autotooltip-hidden-classes">' . $classes . '</span>' . 105 '<span class="plugin-autotooltip-hidden-tip">' . 106 implode('<br><br>', $contentParts) . 107 '</span>' . 108 '</span>'; 109 } 110 111 112 /** 113 * Render a tooltip, with the title and abstract of a page. 114 * 115 * @param string $id - A page id. 116 * @param string $content - The on-page content. Newlines will be rendered as line breaks. Omit to use the page's title. 117 * @param string $preTitle - Text to display before the title in the tooltip. Newlines will be rendered as line breaks. 118 * @param string $classes - CSS classes to add to this tooltip. 119 * @param string $linkStyle - Style attribute for the link. 120 * @return string 121 */ 122 function forWikilink($id, $content = null, $preTitle = '', $classes = '', $linkStyle = '') { 123 $title = p_get_metadata($id, 'title'); 124 $abstract = p_get_metadata($id, 'description abstract'); 125 126 // By default, the abstract starts with the title. Remove it so it's not displayed twice, but still fetch 127 // both pieces of metadata, in case another plugin rewrote the abstract. 128 $abstract = preg_replace('/^' . $this->_pregEscape($title) . '(\r?\n)+/', '', $abstract); 129 130 $link = $this->localRenderer->internallink($id, $content ?: $title, null, true); 131 132 if (!empty($linkStyle)) { 133 $link = preg_replace('/<a /', '<a style="' . $linkStyle . '" ', $link); 134 } 135 136 if (page_exists($id)) { 137 // Remove the title attribute, since we have a better tooltip. 138 $link = preg_replace('/title="[^"]*"/', '', $link); 139 return $this->forText($link, $abstract, $title, $preTitle, $classes); 140 } 141 else { 142 return $link; 143 } 144 } 145 146 147 /** 148 * Format tooltip text. 149 * 150 * @param string $tt - Tooltip text. 151 * @return string 152 */ 153 private function _formatTT($tt) { 154 // Convert double-newlines into vertical space. 155 $tt = preg_replace('/(\r?\n){2,}/', '<br><br>', $tt); 156 // Single newlines get collapsed, just like in HTML. 157 return preg_replace('/(\r?\n)/', ' ', $tt); 158 } 159 160 161 /** 162 * Escape a string for inclusion in a regular expression, assuming forward slash is used as the delimiter. 163 * 164 * @param string $r - The regex string, without delimiters. 165 * @return string 166 */ 167 private function _pregEscape($r) { 168 return preg_replace('/\//', '\\/', preg_quote($r)); 169 } 170} 171