localRenderer = new Doku_Renderer_xhtml; } /** * Return methods of this helper * * @return array with methods description */ public function getMethods() { $result = array(); $result[] = array( 'name' => 'forText', 'desc' => 'Manually construct a tooltip', 'params' => array( 'content' => 'string', 'tooltip' => 'string', 'title (optional)' => 'string', 'preTitle (optional)' => 'string', 'classes (optional)' => 'string', 'textClasses (optional)' => 'string', ), 'return' => array('result' => 'string') ); $result[] = array( 'name' => 'forWikilink', 'desc' => 'Generate a tooltip from a wikilink', 'params' => array( 'id' => 'string', 'content (optional)' => 'string', 'preTitle (optional)' => 'string', 'classes (optional)' => 'string', 'textClasses (optional)' => 'string', ), 'return' => array('result' => 'string') ); return $result; } /** * Return a simple tooltip. * * @param string $content - The on-page content. May contain newlines. * @param string $tooltip - The tooltip content. Newlines will be rendered as line breaks. * @param string $title - The title inside the tooltip. * @param string $preTitle - Text to display before the title. Newlines will be rendered as line breaks. * @param string $classes - CSS classes to add to this tooltip. * @param string $textClasses - CSS classes to add to the linked text. * @return string */ public function forText($content, $tooltip, $title='', $preTitle = '', $classes = '', $textClasses = '') { if (empty($classes)) { $classes = $this->getConf('style'); } if (empty($classes)) { $classes = 'default'; } $delay = $this->getConf('delay') ?: 0; // Sanitize $classes = htmlspecialchars($classes); // Add the plugin prefix to all classes. $classes = preg_replace('/(\w+)/', 'plugin-autotooltip__$1', $classes); $partCount = (empty($title) ? 0 : 1) + (empty($preTitle) ? 0 : 1) + (empty($tooltip) ? 0 : 1); if ($partCount > 1 || strchr($tooltip, "\n") !== FALSE || strlen($tooltip) > 40) { $classes .= ' plugin-autotooltip_big'; } if (empty($textClasses)) { $textClasses = 'plugin-autotooltip_linked'; if (strstr($content, '_formatTT($preTitle); } if (!empty($title)) { $contentParts[] = '' . $title . ''; } if (!empty($tooltip)) { $contentParts[] = $this->_formatTT($tooltip); } return '' . $content . '' . $classes . '' . '' . '' . implode('

', $contentParts) . '
' . '' . '
'; } /** * Render a tooltip, with the title and abstract of a page. * * @param string $id - A page id. * @param string $content - The on-page content. Newlines will be rendered as line breaks. Omit to use the page's title. * @param string $preTitle - Text to display before the title in the tooltip. Newlines will be rendered as line breaks. * @param string $classes - CSS classes to add to this tooltip. * @param string $textClasses - CSS classes to add to the linked text. * @return string */ public function forWikilink($id, $content = null, $preTitle = '', $classes = '', $textClasses = '') { global $ID; $id = resolve_id(getNS($ID), $id, false); $meta = self::read_meta_fast($id); $title = $meta['title']; $link = $this->localRenderer->internallink($id, $content ?: $title, null, true); if (page_exists(preg_replace('/\#.*$/', '', $id))) { $link = $this->stripNativeTooltip($link); return $this->forText($link, $meta['abstract'], $title, $preTitle, $classes, $textClasses); } else { return $link; } } /** * Is this id excluded from the plugin? * * @param string $id * @return boolean */ public function isExcluded($id) { $inclusions = $this->getConf('linkall_inclusions'); $exclusions = $this->getConf('linkall_exclusions'); return (!empty($inclusions) && !preg_match("/$inclusions/", $id)) || (!empty($exclusions) && preg_match("/$exclusions/", $id)); } /** * Strip the native title= tooltip from an anchor tag. * * @param string $link * @return string */ public function stripNativeTooltip($link) { return preg_replace('/title="[^"]*"/', '', $link); } /** * Reads specific metadata about 10x faster than p_get_metadata. p_get_metadata only uses caching for the current * page, and uses the very slow php serialization. However, in a wiki with infrequently accessed pages, it's * extremely slow. * * @param string $id * @return array - An array containing 'title' and 'abstract.' */ static function read_meta_fast($id) { global $ID; $resolver = new PageResolver($ID); $id = $resolver->resolveId(preg_replace('/\#.*$/', '', $id), null, true); if (isset(self::$metaCache[$id])) { return self::$metaCache[$id]; } $results = [ 'title' => p_get_metadata(cleanID($id), 'title'), 'abstract' => p_get_metadata(cleanID($id), 'plugin_description keywords') ?: p_get_metadata(cleanID($id), 'description abstract') ]; // By default, the abstract starts with the title. Remove it so it's not displayed twice, but still fetch // both pieces of metadata, in case another plugin rewrote the abstract. $results['abstract'] = preg_replace( '/^' . self::_pregEscape($results['title']) . '(\r?\n)+/', '', $results['abstract'] ); self::$metaCache[$id] = $results; return $results; } /** * Format tooltip text. * * @param string $tt - Tooltip text. * @return string */ private function _formatTT($tt) { // Convert double-newlines into vertical space. $tt = preg_replace('/(\r?\n){2,}/', '

', $tt); // Single newlines get collapsed, just like in HTML. return preg_replace('/(\r?\n)/', ' ', $tt); } /** * Escape a string for inclusion in a regular expression, assuming forward slash is used as the delimiter. * * @param string $r - The regex string, without delimiters. * @return string */ private static function _pregEscape($r) { return preg_replace('/\//', '\\/', preg_quote($r)); } }