Extension:Kw bread crumbs/Source
From MediaWiki.org
<?php /* ===Description=== This extension allows you to dynamically create a "trace" of the pages you have visited so far. This trace is displayed as a small list of links that can typically be positionned at the top of a page. Additional parameters can be specified to control the layout of the list and specify how many pages should be "remembered". ===Parameters=== <kw_bread_crumbs>max_nb_crumbs=value|max_title_len=value|prefix=stringtrim_prefix=string|separator=string|bgcolor=string|small=boolean|on_top_hack=boolean</kw_bread_crumbs> * max_nb_crumbs=value: max number of page titles this extension should remember * max_title_len=value: max length for each page title (will crop otherwise) * prefix=string: string to use in front of the list of titles. * trim_prefix=string: if this prefix is found, remove it from each page title. * separator=string: string to use between each page title. * bgcolor=string: in hex format (ex: FF22AA), color of the table background. * small=[0|1]: if true, use a smaller font. * on_top_hack=[0|1]: if true, try to put titles on top of page. Note that trim_prefix can be specified multiple times so that different prefixes can be trimmed. The on_top_hack option is a hack. I mean, really. It will try to put the trace on top of the page, before the page title. This is achieved by piggy-backing on top of the wgSiteNotice variable, and will work only for the monobook skin. See 'Positioning' below for more options. ===Download=== http://public.kitware.com/cgi-bin/viewcvs.cgi/%2Acheckout%2A/scripts/media-wiki-extensions/kwBreadCrumbs.php?content-type=text%2Fplain&root=kwGridWeb ===Installation=== To activate the extension, copy the file to the Wiki/extensions directory and include its contents from your Wiki/LocalSettings.php with: include("extensions/kwBreadCrumbs.php"); ===Positioning=== There are different ways to position the trace: * inline: use the tag in your page at the specific location you want the trace to be rendered. * on top: use the tag anywhere in the page and use on_top_hack=1; the extension will attempt to place the trace on top of the page, before the page title. * anywhere in the layout: you can use this extension as a template element but you will not be able to specify any parameter. In order to do so, modify the xhtml_slim.tp file to insert the kwBreadCrumbs element, then modify the outputPage() function in SkinPHPTal.php to create the contents of this element by calling kwBreadCrumbsTAL(): xhtml_slim.tp: <div class="kwBreadCrumbs" tal:content="structure kwBreadCrumbs">Bread Crumbs</div> SkinPHPTal.php: $tpl->set("kwBreadCrumbs", kwBreadCrumbsTAL()); ===Issues=== The Wiki engine caches pages to achieve better performance. Sadly, this makes extensions relying on dynamic or external contents pretty much useless. To prevent pages using this extension from being cached, the 'cur_touched' field in the 'cur' table is set slightly ahead in the future, so that the page cache is automatically invalidated. The side-effects should be minimal :) ===Author=== Sebastien Barre (Kitware, Inc.) ===Thanks=== I noticed this feature in the DokuWiki project, so kudos to them (http://wiki.splitbrain.org/wiki:dokuwiki). */ $wgExtensionFunctions[] = "kwBreadCrumbsExtension"; // ------------------------------------------------------------------------ function kwBreadCrumbsExtension() { global $wgParser; $wgParser->setHook( "kw_bread_crumbs", "kwBreadCrumbs"); } // ------------------------------------------------------------------------ function kwBreadCrumbs($input) { global $wgUser, $wgTitle, $wgOut; kwBreadCrumbsNoCache(); // Initialize parameters $max_nb_crumbs = 5; $max_title_len = 30; $separator = ' » '; $trim_prefixes = array(); $prefix = NULL; $small = 1; $bgcolor = F9F9F9; $on_top_hack = 0; $class = 'kwBreadCrumbs'; // Parse each parameter $params = explode('|', $input); foreach ($params as $param) { $param_components = explode("=", $param, 2); $param_name = strtolower(trim($param_components[0])); $param_value = isset($param_components[1]) ? $param_components[1] : NULL; // max_nb_crumbs if ($param_name == 'max_nb_crumbs') { if (!strlen($param_value)) { return kwBreadCrumbsError("missing value for parameter '$param_name'"); } $value = (int)$param_value; if ($value >= 1 && $value <= 50) { $max_nb_crumbs = $value; } } // max_title_len else if ($param_name == 'max_title_len') { if (!strlen($param_value)) { return kwBreadCrumbsError("missing value for parameter '$param_name'"); } $value = (int)$param_value; if ($value >= 0 && $value <= 150) { $max_title_len = $value; } } // trim_prefix else if ($param_name == 'trim_prefix') { if (!strlen($param_value)) { return kwSiteMapError("missing value for parameter '$param_name'"); } $trim_prefixes[] = $param_value; } // prefix else if ($param_name == 'prefix') { if (!strlen($param_value)) { return kwSiteMapError("missing value for parameter '$param_name'"); } $prefix = $param_value; } // separator else if ($param_name == 'separator') { if (!strlen($param_value)) { return kwBreadCrumbsError("missing value for parameter '$param_name'"); } $separator = $param_value; } // bgcolor else if ($param_name == 'bgcolor') { if (!strlen($param_value)) { return kwSiteMapError("missing value for parameter '$param_name'"); } $bgcolor = $param_value; } // small else if ($param_name == 'small') { if (!strlen($param_value)) { return kwBreadCrumbsError("missing value for parameter '$param_name'"); } $small = $param_value ? 1 : 0;; } // on_top_hack else if ($param_name == 'on_top_hack') { if (!strlen($param_value)) { return kwBreadCrumbsError("missing value for parameter '$param_name'"); } $on_top_hack = $param_value ? 1 : 0;; } // unknown parameter else if ($param_name) { return kwBreadCrumbsError("unknown parameter '$param_name'"); } } // Make sure we started a session @session_start(); $key = 'kw_bread_crumbs'; if (!isset($_SESSION[$key])) { $_SESSION[$key] = array(); } // Remove duplicates $current_title = $wgTitle->getPrefixedText(); $titles = array(); foreach ($_SESSION[$key] as $title) { if ($title != $current_title) { $titles[] = $title; } } $_SESSION[$key] = $titles; $_SESSION[$key][] = $current_title; // Shrink the list $nb_titles = count($_SESSION[$key]); while ($nb_titles > $max_nb_crumbs) { array_shift($_SESSION[$key]); $nb_titles--; } // Create the trace $skin =& $wgUser->getSkin(); $urls = array(); foreach ($_SESSION[$key] as $title) { $text = $title; if (count($trim_prefixes)) { foreach ($trim_prefixes as $trim_prefix) { if (strpos($text, $trim_prefix) === 0) { $text = substr($text, strlen($trim_prefix)); } } } if ($max_title_len > 0) { $text_len = strlen($text); if ($text_len > $max_title_len) { $half = (int)($max_title_len / 2); $text = substr($text, 0, $max_title_len - $half - 1) . '…' . substr($text, -$half); } } $urls[] = ($title == $current_title ? $text : $skin->makeLink($title, $text)); } $output = '<div class="' . $class . '"'; if ($small) { $output .= ' style="font-size:80%"'; } $output .= '>'; if (!is_null($bgcolor)) { $output .= '<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr><td bgcolor="#' . htmlspecialchars($bgcolor) . '">'; } $output .= $prefix . implode(htmlentities($separator), $urls); if (!is_null($bgcolor)) { $output .= '</td></tr></table>'; } $output .= '</div>'; // Hack to display the titles on top: // - only if monobook // - piggy-back after the site notice (wgSiteNotice) // - remove border if <= 1.3.0 beta, alpha, etc. if ($on_top_hack) { $user_skin_name = $wgUser->getOption('skin'); if ($user_skin_name == "monobook") { global $wgSiteNotice, $wgVersion; if (!$wgSiteNotice || !strpos($wgSiteNotice, $class)) { if (preg_match("/^(\d+)\.(\d+)\.(\d+)(\w*)$/", $wgVersion, $ver)) { $new_notice = NULL; if ($ver[1] == 1 && $ver[2] == 3 && $ver[3] == 0 && isset($ver[4])) { $new_notice .= '<div style="margin: -1px -1px -1px -1px; border: 1px solid #FFFFFF; font-weight: bold;"></div>'; } $new_notice .= '</div>' . $output; if ($wgSiteNotice) { $new_notice .= '<div id="siteNotice">' . $wgSiteNotice; } else { $new_notice .= '<div>'; } $wgSiteNotice = $new_notice; } } } return ''; } return $output; } // ------------------------------------------------------------------------ function kwBreadCrumbsError($msg) { return "[kw_bread_crumbs] <b>Error</b>: " . htmlspecialchars($msg); } // ------------------------------------------------------------------------ function kwBreadCrumbsNoCache() { global $wgTitle, $wgOut; if (!isset($wgTitle) || !isset($wgOut)) { return; } /* Let's 'touch' the page to invalidate its cache. The code below is slightly identical to Title::invalidateCache(). Even though invalidateCache() sets cur_touched to 'now', we are still in the process of creating and rendering the page itself and the page will be cached only once it is done. At the end of the day the cache would always end up newer than cur_touched, defeating the whole purpose of calling invalidateCache(). The trick here is to set cur_touched in the future, something not too intrusive, say 'now' + 120 seconds, provided that we expect the cached page to be created within 120 secs after this extension code has been executed. That way, cur_touched remains 'fresher' than the cache, and the page is always re-created dynamically. */ $ts = mktime(); $now = gmdate("YmdHis", $ts + 120); $ns = $wgTitle->getNamespace(); $ti = wfStrencode($wgTitle->getDBkey()); $sql = "UPDATE page SET page_touched='$now' WHERE page_namespace=$ns AND page_title='$ti'"; wfQuery($sql, DB_WRITE, "kwBreadCrumbsNoCache"); // This does not seem to do anything. I assume once it's called here // in the extension, it's already too late. $wgOut->enableClientCache(false); // The followings should prevent browsers to cache too long /* $wgOut->addMeta("http:Pragma", "no-cache"); $wgOut->addMeta("http:no-cache", NULL); $wgOut->addMeta("http:EXPIRES", "TUES, 31 DEC 1996 12:00:00 GMT"); */ // HTTP_IF_MODIFIED_SINCE ? // see OutputPage: checkLastModified } // ------------------------------------------------------------------------ function kwBreadCrumbsTAL() { return kwBreadCrumbs(''); }
