/** * Return a simple associative array format for template output of all versions which apply to the supplied topic. * * @param PonyDocsTopic $pTopic Topic to obtain versions for. * @return array */ public function getVersionsForTopic(PonyDocsTopic &$pTopic) { global $wgArticlePath; $versions = array(); foreach ($pTopic->getProductVersions() as $productVersion) { $versions[] = array('name' => $productVersion->getVersionName(), 'href' => str_replace('$1', 'Category:V:' . $productVersion->getProductName() . ':' . $productVersion->getVersionName(), $wgArticlePath)); } return $versions; }
/** * Updates or deletes Doc Links for the article being passed in. * @param string $updateOrDelete possible values: "update" or "delete" * @param Article $article the article to be updated or deleted * @param string $content content of the article to be updated or deleted */ public static function updateOrDeleteDocLinks($updateOrDelete, $article, $content = NULL) { $dbh = wfGetDB(DB_MASTER); if ($updateOrDelete == "update") { // Match all links in the article /* Breakdown of the regex below: * two left brackets * followed by zero or more misc chars ($match[1]), until * a pound followed by one or more misc chars ($match[2]) -- but this section is optional * followed by an optional | * followed by zero or more misc chars ($match[4]) ($match[3] is the misc chars plus the |) * followed by two right brackets * Things that would match: * [[TextHere:OtherTextHere#MoreText|StillMoreText]] * [[TextHere:MoreText:Text:Text|StillMoreText]] * [[TextHere:MoreText:Text:Text:Text|StillMoreText]] * [[TextHere:OtherTextHere|StillMoreText]] * [[TextHereStillMoreText]] * etc. * For PonyDocs, this maps to: * [[Topic]] * [[Documentation:Product:Manual:Topic]] * [[Documentation:Product:Manual:Topic:Version]] * [[OtherNamespace:Topic]] */ // TODO we really should refactor this regex; for now, leaving intact $regex = "/\\[\\[([A-Za-z0-9,:._ -]*)(\\#[A-Za-z0-9 _-]+)?([|]?([A-Za-z0-9,:.'_?!@\\/\"()#\$ -]*))\\]\\]/"; preg_match_all($regex, $content, $matches, PREG_SET_ORDER); } // Get the title of the article $title = $article->getTitle()->getFullText(); $titlePieces = explode(':', $title); $fromNamespace = $titlePieces[0]; $toAndFromLinksToInsert = array(); $fromLinksToDelete = array(); // $titlePieces[3] is the version // if this is not set, we're not looking at a Topic (probably we're looking at a TOC) and we don't need doclinks if ($fromNamespace == PONYDOCS_DOCUMENTATION_NAMESPACE_NAME && isset($titlePieces[3])) { // TODO only process this topic if it's not a TOC. // Do PonyDocs-specific stuff (loop through all inherited versions) // Get the versions associated with this topic $topic = new PonyDocsTopic($article); PonyDocsProductVersion::LoadVersionsForProduct($titlePieces[1], true, true); $ponydocsVersions = $topic->getProductVersions(); // Add a link to the database for each version foreach ($ponydocsVersions as $ver) { // Make a pretty PonyDocs URL (with slashes) out of the mediawiki title (with colons) // Put this $ver in the version spot. We want one URL per inherited version $titleNoVersion = $fromNamespace . ":" . $titlePieces[1] . ":" . $titlePieces[2] . ":" . $titlePieces[3]; $humanReadableTitle = self::translateTopicTitleForDocLinks($titleNoVersion, $fromNamespace, $ver, $topic); // this will add the version // Add this title to the array of titles to be deleted from the database $fromLinksToDelete[] = $humanReadableTitle; if ($updateOrDelete == "update") { // Add links in article to database foreach ($matches as $match) { // Get pretty to_link $toUrl = self::translateTopicTitleForDocLinks($match[1], $fromNamespace, $ver, $topic); // Add this from_link and to_link to array to be inserted into the database if ($toUrl) { $toAndFromLinksToInsert[] = array('from_link' => $humanReadableTitle, 'to_link' => $toUrl); } } } } } elseif ($fromNamespace != PONYDOCS_DOCUMENTATION_NAMESPACE_NAME) { // Do generic mediawiki stuff for non-PonyDocs namespaces // Add this title to the array of titles to be deleted from the database // We don't need to translate title here since we're not in the PonyDocs namespace $fromLinksToDelete[] = $title; if ($updateOrDelete == "update") { // Add links in article to database foreach ($matches as $match) { // Get pretty to_link $toUrl = self::translateTopicTitleForDocLinks($match[1]); // Add this from_link and to_link to array to be inserted into the database if ($toUrl) { $toAndFromLinksToInsert[] = array('from_link' => $title, 'to_link' => $toUrl); } } } } // Perform database queries using arrays populated above // First, delete to clear old data out of the database if (!empty($fromLinksToDelete)) { foreach ($fromLinksToDelete as &$fromLinkToDelete) { $fromLinkToDelete = $dbh->strencode($fromLinkToDelete); } $deleteWhereConds = implode("' OR from_link = '", $fromLinksToDelete); $deleteQuery = "DELETE FROM ponydocs_doclinks WHERE from_link = '" . $deleteWhereConds . "'"; $dbh->query($deleteQuery); } // Now insert new data, if we have any if (!empty($toAndFromLinksToInsert)) { $insertValuesAry = array(); foreach ($toAndFromLinksToInsert as $toAndFromLink) { $insertValuesAry[] = "'" . $dbh->strencode($toAndFromLink['from_link']) . "', '" . $dbh->strencode($toAndFromLink['to_link']) . "'"; } $insertValuesString = implode("), (", $insertValuesAry); $insertQuery = "INSERT INTO ponydocs_doclinks (from_link, to_link) VALUES (" . $insertValuesString . ")"; $dbh->query($insertQuery); } return true; }
/** * Replace a version on an existing Topic * * @param $topicTitle string The internal mediawiki title of the article. * @param $sourceVersion PonyDocsVersion The source Version * @param $targetVersion PonyDocsVersion The target Version * @returns boolean */ public static function changeVersionOnTopic($topicTitle, $sourceVersion, $targetVersion) { global $wgTitle; // Clear any hooks so no weirdness gets called after we save the change $wgHooks['ArticleSave'] = array(); if (!preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':([^:]*):([^:]*):(.*):([^:]*)$/', $topicTitle, $match)) { throw new Exception("Invalid Title to Rename Version: {$topicTitle}"); } $productName = $match[1]; $title = $match[3]; // Get PonyDocsProduct // TODO: Why don't we just pass the product in instead of re-deriving it from something else and then loading it? $product = PonyDocsProduct::GetProductByShortName($productName); $title = Title::newFromText($topicTitle); $wgTitle = $title; $article = new Article($title); if (!$article->exists()) { // No such title exists in the system throw new Exception("Invalid Title to Rename Version: {$topicTitle}"); } $content = $article->getContent(); $oldCategory = '[[Category:V:' . $product->getShortName() . ':' . $sourceVersion->getVersionName() . ']]'; $newCategory = '[[Category:V:' . $product->getShortName() . ':' . $targetVersion->getVersionName() . ']]'; $message = ''; $editTopic = TRUE; // Get conflicts. $conflicts = PonyDocsBranchInheritEngine::getConflicts($product, $topicTitle, $targetVersion); if (!empty($conflicts)) { // If there's already a topic with the target version, // then we just want to remove the source version from the source topic foreach ($conflicts as $conflict) { $conflictingArticle = new Article(Title::newFromText($conflict)); // No big deal. A conflict no longer exists? Continue. if (!$conflictingArticle->exists()) { continue; } // Conflict was same as source material. Do nothing with it. if ($conflict == $topicTitle) { continue; // Remove source version from source article } else { $content = str_replace($oldCategory, '', $content); $message = "Removed version category {$oldCategory} via RenameVersion"; } } } if (empty($message)) { // If the Topic doesn't contain the source version, it may have been branched, or already processed if (strpos($content, $oldCategory) === FALSE) { $lastColon = strrpos($topicTitle, ':'); $baseTopic = substr_replace($topicTitle, '', $lastColon); $topicTitle = PonyDocsTopic::GetTopicNameFromBaseAndVersion($baseTopic, $productName); // We found an instance of this title with the source version! Let's recurse just this once to handle it. if ($topicTitle) { $editTopic = FALSE; $title = self::changeVersionOnTopic($topicTitle, $sourceVersion, $targetVersion); // We can't find a topic with the source version, so something is odd. Let's complain } else { throw new Exception("Topic {$topicTitle} does not contain source version " . $sourceVersion->getVersionName()); } // If the Topic already has the new version, just remove the old version } elseif (strpos($content, $newCategory) !== FALSE) { $content = str_replace($oldCategory, '', $content); $message = "Removed version category {$oldCategory} via RenameVersion"; // Otherwise replace old with new } else { $content = str_replace($oldCategory, $newCategory, $content, $count); $message = "Renamed version category {$oldCategory} to {$newCategory} in {$count} locations via RenameVersion"; } } // Finally we can edit the topic if ($editTopic) { // TODO: doEdit returns a status that we should check $article->doEdit($content, $message, EDIT_UPDATE); } return $title; }
/** * Parse the content of the TOC management page. * * It should be loaded and stored and this sort of breaks the design * in the way that it returns the template ready array of data which PonyDocsWiki is really supposed to be returning, * but I do not see the point or use of an intermediate format other than to bloat the code. * * It returns an array of arrays, which can be stored as a single array or separated using the list() = loadContnet() syntax. * * toc: This is the actual TOC as a list of arrays, * each array having a set of keys available to specify the TOC level, text, href, etc. * prev: Assoc array containing the 'previous' link data (text, href), or empty if there isn't one. * next: Assoc array containing the 'next' link data or empty if there isn't one. * start: Assoc array containing the data for the FIRST topic in the TOC. * * These can be captured in a variable when calling and individually accessed or captured using the list() construct * i.e.: list( $toc, $prev, $next, $start ) = $toc->loadContent(). * * @FIXME: Store results internally and then have a $reload flag as param. * $content = $toc- * * @return array */ public function loadContent() { global $wgArticlePath; global $wgTitle; global $wgScriptPath; global $wgPonyDocs; global $title; /** * From this we have the page ID of the TOC page to use -- fetch it then parse it so we can produce an output TOC array. * * This array will contain one array per item with the following keys: * - 'level': 0= Arbitary Section Name, 1= Actual topic link. * - 'link': Link (wiki path) to item; may be unset for section headers (or set to first section H1)? * - 'text': Text to show in sidebar TOC. * - 'current': 1 if this is the currently selected topic, 0 otherwise. * * We also have to store the index of the current section in our loop. * * The reason for this is so that we can remove any sections which have no defined/valid topics listed. * * This will also assist in our prev/next links which are stored in special indices. */ // Our title is our url. // We should check to see if latest is our version. // If so, we want to FORCE the URL to include /latest/ as the version instead of the version that the user is currently in $tempParts = explode("/", $title); $latest = FALSE; if (isset($tempParts[1]) && !strcmp($tempParts[1], "latest")) { $latest = TRUE; } $selectedProduct = $this->pProduct->getShortName(); $selectedVersion = $this->pInitialVersion->getVersionName(); $selectedManual = $this->pManual->getShortName(); // Okay, let's determine if the VERSION that the user is in is latest, if so, we should set latest to true. if (PonyDocsProductVersion::GetLatestReleasedVersion($selectedProduct) != NULL) { if ($selectedVersion == PonyDocsProductVersion::GetLatestReleasedVersion($selectedProduct)->getVersionName()) { $latest = TRUE; } } $cache = PonyDocsCache::getInstance(); $key = "TOCCACHE-" . $selectedProduct . "-" . $selectedManual . "-" . $selectedVersion; $toc = $cache->get($key); // Cache did not exist, let's load our content is build up our cache entry. if ($toc === NULL && is_object($this->pTOCArticle) && is_a($this->pTOCArticle, 'Article')) { // The current index of the element in $toc we will work on $idx = 0; $section = -1; $content = $this->pTOCArticle->getContent(); $lines = explode("\n", $content); foreach ($lines as $line) { /** * Indicates an arbitrary section header if it does not begin with a bullet point. * This is level 0 in our TOC and is not a link of any type (?). */ if (!isset($line[0]) || $line[0] != '*') { /** * See if we are CLOSING a section (i.e. $section != -1). If so, check 'subs' and ensure its >0, * otherwise we need to remove the section from the list. */ if ($section != -1 && !$toc[$section]['subs']) { unset($toc[$section]); } if (isset($line[0]) && ctype_alnum($line[0])) { $toc[$idx] = array('level' => 0, 'subs' => 0, 'link' => '', 'text' => $line, 'current' => FALSE); $section = $idx; } /** * This is a bullet point and thus an actual topic which can be linked to in MediaWiki. * {{#topic:H1 Of Topic Page}} */ } else { if (-1 == $section) { continue; } $topicRegex = '/' . PonyDocsTopic::getTopicRegex() . '/i'; if (!preg_match($topicRegex, $line, $matches)) { continue; } $baseTopic = $matches[1]; $title_suffix = preg_replace('/([^' . str_replace(' ', '', Title::legalChars()) . '])/', '', $baseTopic); $title = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ":{$selectedProduct}:{$selectedManual}:{$title_suffix}"; $newTitle = PonyDocsTopic::GetTopicNameFromBaseAndVersion($title, $selectedProduct); /** * Hide topics which have no content (i.e. have not been created yet) from the user viewing. * * Authors must go to the TOC page in order to view and edit these. * * The only way to do this (the cleanest/quickest) is to create a Title object then see if its article ID is 0 * * @tbd: Fix so that the section name is hidden if no topics are visible? */ $t = Title::newFromText($newTitle); if (!$t || !$t->getArticleID()) { continue; } /** * Obtain H1 content from the article -- WE NEED TO CACHE THIS! */ $h1 = PonyDocsTopic::FindH1ForTitle($newTitle); if ($h1 === FALSE) { $h1 = $newTitle; } $href = str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . "/{$selectedProduct}/{$selectedVersion}/{$selectedManual}/{$title_suffix}", $wgArticlePath); $toc[$idx] = array('level' => 1, 'page_id' => $t->getArticleID(), 'link' => $href, 'toctitle' => $baseTopic, 'text' => $h1, 'section' => $toc[$section]['text'], 'title' => $newTitle, 'class' => 'toclevel-1'); $toc[$section]['subs']++; } $idx++; } if (!$toc[$section]['subs']) { unset($toc[$section]); } // Okay, let's store in our cache. $cache->put($key, $toc, TOC_CACHE_TTL, TOC_CACHE_TTL / 4); } if ($toc) { $currentIndex = -1; $start = array(); // Go through and determine start, prev, next and current elements. foreach ($toc as $idx => &$entry) { // Not using $entry. Only interested in $idx. // This allows us to process tocs with removed key indexes. if ($toc[$idx]['level'] == 1) { if (empty($start)) { $start = $toc[$idx]; } // Determine current $toc[$idx]['current'] = strcmp($wgTitle->getPrefixedText(), $toc[$idx]['title']) ? FALSE : TRUE; if ($toc[$idx]['current']) { $currentIndex = $idx; } // Now rewrite link with latest, if we are in latest if ($latest) { $safeVersion = preg_quote($selectedVersion, '#'); // Lets be specific and replace the version and not some other part of the URI that might match... $toc[$idx]['link'] = preg_replace('#^/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '/([' . PONYDOCS_PRODUCT_LEGALCHARS . ']+)/' . "{$safeVersion}#", '/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '/$1/latest', $toc[$idx]['link'], 1); } } } /** * Figure out previous and next links. * * Previous should point to previous topic regardless of section, so our best bet is to skip any 'level=0'. * * Next works the same way. */ $prev = $next = $idx = -1; if ($currentIndex >= 0) { $idx = $currentIndex; while ($idx >= 0) { --$idx; if (isset($toc[$idx]) && $toc[$idx]['level'] == 1) { $prev = $idx; break; } } $idx = $currentIndex; // Array is sparse, so sizeof() truncates the end. Use max key instead. while ($idx <= max(array_keys($toc))) { ++$idx; if (isset($toc[$idx]) && $toc[$idx]['level'] == 1) { $next = $idx; break; } } if ($prev != -1) { $prev = array('link' => $toc[$prev]['link'], 'text' => $toc[$prev]['text']); } if ($next != -1) { $next = array('link' => $toc[$next]['link'], 'text' => $toc[$next]['text']); } } /** * You should typically capture this by doing: * list( $toc, $prev, $next, $start ) = $ponydocstoc->loadContent(); * * @FIXME: Previous and next links change based on the page you are on, so we cannot CACHE those! * * $obj = new stdClass(); * $obj->toc = $toc; * $obj->prev = $prev; * $obj->next = $next; * $obj->start = $start; * $cache->addKey($tocKey, $obj); */ // Last but not least, get the manual description if there is one. if (is_object($this->pTOCArticle) && preg_match('/{{#manualDescription:([^}]*)}}/', $this->pTOCArticle->getContent(), $matches)) { $this->mManualDescription = $matches[1]; } // $this->pTOCArticle is empty, we're probably creating a new TOC } else { $toc = array(); $prev = array(); $next = array(); $start = array(); } return array($toc, $prev, $next, $start); }
/** * Do a bulk add operation. Take a collection of topics and add them to the TOC if it doesn't already exist. * * @param $manual PonyDocsManual The manual the TOC belongs to. * @param $version PonyDocsVersion The version the TOC belongs to. * @param $collection array A multidimensional array of topics. First keyed with section name, then titles. * @returns boolean */ static function addCollectionToTOC($product, $manual, $version, $collection) { global $wgTitle; $title = self::TOCExists($product, $manual, $version); if ($title == FALSE) { throw new Exception("TOC does not exist for " . $manual->getShortName() . " with version " . $version->getVersionName()); } $title = Title::newFromText($title); $wgTitle = $title; $article = new Article($title); if (!$article->exists()) { throw new Exception("TOC does not exist for " . $manual->getShortName() . " with version " . $version->getVersionName()); } // Okay, let's search for the content. $content = $article->getContent(); foreach ($collection as $sectionName => $topics) { // $evalSectionName is the cleaned up section name to look for. $evalSectionName = preg_quote(trim(str_replace('?', "", strtolower($sectionName)))); foreach ($topics as $topic) { if ($topic == NULL) { continue; } // $topic is the trimmed original version of the topic. $topic = trim($topic); // $evalTopic is the clened up topic name to look for $evalTopic = preg_quote(str_replace('?', '', strtolower($topic))); $content = explode("\n", $content); $found = FALSE; $inSection = FALSE; $newContent = ''; foreach ($content as $line) { $evalLine = trim(str_replace('?', '', strtolower($line))); $topicRegex = PonyDocsTopic::getTopicRegex($evalTopic); if (preg_match("/^" . $evalSectionName . "\$/", $evalLine)) { $inSection = TRUE; $newContent .= $line . "\n"; continue; } elseif (preg_match("/\\*\\s*{$topicRegex}/", $evalLine)) { if ($inSection) { $found = TRUE; } $newContent .= $line . "\n"; continue; } elseif (preg_match("/^\\s?\$/", $evalLine)) { if ($inSection && !$found) { $newContent .= "* {{#topic:" . $topic . "}}\n\n"; $found = TRUE; continue; } $inSection = FALSE; } $newContent .= $line . "\n"; } if (!$found) { // Then the section didn't event exist, we should add to TOC and add the item. // We need to add it before the Category evalLine. $text = $sectionName . "\n" . "* {{#topic:" . $topic . "}}\n\n[[Category"; $newContent = preg_replace("/\\[\\[Category/", $text, $newContent); } $inSection = FALSE; // Reset loop data $content = $newContent; } } // Okay, do the edit $article->doEdit($content, "Updated TOC in bulk branch operation.", EDIT_UPDATE); return TRUE; }
/** * This expects to find: * {{#topic:Text Name}} * * @param Parser $parser * @param string $param1 Full text name of topic, must be converted to wiki topic name. * @return array * * TODO: Much of this function duplicates code above in efGetTitleFromMarkup(), can we DRY? * There really shouldn't be any real code in this file, just calls to class methods... */ function efTopicParserFunction_Render(&$parser, $param1 = '') { global $wgArticlePath, $wgTitle, $action; if (PonyDocsExtension::isSpeedProcessingEnabled()) { return TRUE; } /** * We ignore this parser function if not in a TOC management page. */ if (!preg_match('/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(.*):(.*)TOC(.*)/i', $wgTitle->__toString(), $matches)) { return FALSE; } $manualShortName = $matches[2]; $productShortName = $matches[1]; PonyDocsWiki::getInstance($productShortName); /** * Get the earliest tagged version of this TOC page and append it to the wiki page? * Ensure the manual is valid then use PonyDocsManual::getManualByShortName(). * Next attempt to get the version tags for this page -- which may be NONE -- * and from this determine the "earliest" version to which this page applies. * * TODO: This comment is duplicated above in efGetTitleFromMarkup, can we DRY? */ if (!PonyDocsProductManual::IsManual($productShortName, $manualShortName)) { return FALSE; } $pManual = PonyDocsProductManual::GetManualByShortName($productShortName, $manualShortName); $pTopic = new PonyDocsTopic(new Article($wgTitle)); /** * @FIXME: If TOC page is NOT tagged with any versions we cannot create the pages/links to the * topics, right? */ $manVersionList = $pTopic->getProductVersions(); if (!sizeof($manVersionList)) { return $parser->insertStripItem($param1, $parser->mStripState); } $earliestVersion = PonyDocsProductVersion::findEarliest($productShortName, $manVersionList); /** * Clean up the full text name into a wiki-form. This means remove spaces, #, ?, and a few other * characters which are not valid or wanted. It's not important HOW this is done as long as it is * consistent. */ $wikiTopic = preg_replace('/([^' . str_replace(' ', '', Title::legalChars()) . '])/', '', $param1); $wikiPath = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $productShortName . ':' . $manualShortName . ':' . $wikiTopic; $dbr = wfGetDB(DB_SLAVE); /** * Now look in the database for any instance of this topic name PLUS :<version>. * We need to look in categorylinks for it to find a record with a cl_to (version tag) * which is equal to the set of the versions for this TOC page. * For instance, if the TOC page was for versions 1.0 and 1.1 and our topic was 'How To Foo' * we need to find any cl_sortkey which is 'HowToFoo:%' and has a cl_to equal to 1.0 or 1.1. * There should only be 0 or 1, so we ignore anything beyond 1. * If found, we use THAT cl_sortkey as the link; * if NOT found we create a new topic, the name being the compressed topic name plus the earliest TOC version * ($earliestVersion->getName()). * We then need to ACTUALLY create it in the database, tag it with all the versions the TOC mgmt page is tagged with, * and set the H1 to the text inside the parser function. * * @fixme: Can we test if $action=save here so we don't do this on every page view? */ $versionIn = array(); foreach ($manVersionList as $pV) { $versionIn[] = $productShortName . ':' . $pV->getVersionName(); } $res = $dbr->select(array('categorylinks', 'page'), 'page_title', array('cl_from = page_id', 'page_namespace = "' . NS_PONYDOCS . '"', "cl_to IN ('V:" . implode("','V:", $versionIn) . "')", 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper($productShortName . ':' . $manualShortName . ':' . $wikiTopic)) . ":%'"), __METHOD__); $topicName = ''; if (!$res->numRows()) { /** * No match -- so this is a "new" topic. Set name. */ $topicName = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $productShortName . ':' . $manualShortName . ':' . $wikiTopic . ':' . $earliestVersion->getVersionName(); } else { $row = $dbr->fetchObject($res); $topicName = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ":{$row->page_title}"; } $output = '<a href="' . wfUrlencode(str_replace('$1', $topicName, $wgArticlePath)) . '">' . $param1 . '</a>'; return $parser->insertStripItem($output, $parser->mStripState); }
public function prepareDocumentation() { global $wgOut, $wgParser, $wgScriptPath, $wgTitle, $wgUser; /** * We need a lot of stuff from our PonyDocs extension! */ $ponydocs = PonyDocsWiki::getInstance($this->data['selectedProduct']); $this->data['manuals'] = $ponydocs->getManualsForProduct($this->data['selectedProduct']); /** * Adjust content actions as needed, such as add 'view all' link. */ $this->contentActions(); $this->navURLS(); /** * Possible topic syntax we must handle: * * Documentation:<topic> *Which may include a version tag at the end, we don't care about this. * Documentation:<productShortName>:<manualShortName>:<topic>:<version> * Documentation:<productShortName>:<manualShortName> */ /** * Based on the name; i.e. 'Documentation:Product:Manual:Topic' we need to parse it out and store the manual name and * the topic name as parameters. We store manual in 'manualname' and topic in 'topicname'. Special handling * needs to be done for versions and TOC? * * 0=NS (Documentation) * 1=Product (Short name) * 2=Manual (Short name) * 3=Topic * 4=Version */ $pManual = null; $pieces = explode(':', $wgTitle->__toString()); $helpClass = ''; /** * This isn't a specific topic+version -- handle appropriately. */ if (sizeof($pieces) < 4) { if (!strcmp(PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $this->data['selectedProduct'] . PONYDOCS_PRODUCTVERSION_SUFFIX, $wgTitle->__toString())) { $this->data['titletext'] = 'Versions Management - ' . $this->data['selectedProduct']; $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>* Use {{#version:name|status}} to define a new version,' . ' where status is released, unreleased, or preview.' . ' Valid chars in version name are A-Z, 0-9, period, comma, and dash.</i></span>'); $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>* Use {{#versiongroup:name|message}} to set a banner' . ' message that will appear on every topic in every version following the versiongroup.</i></span>'); } elseif (!strcmp(PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $this->data['selectedProduct'] . PONYDOCS_PRODUCTMANUAL_SUFFIX, $wgTitle->__toString())) { $this->data['titletext'] = 'Manuals Management - ' . $this->data['selectedProduct']; $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Use {{#manual:manualShortName|displayName|categories}} to define a new manual.'); $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Prepend manual short name with ' . PONYDOCS_PRODUCT_STATIC_PREFIX . ' to define a static manual.' . '</i></span>'); $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* If you omit display name, the short name will be used in links.</i></span>'); $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* Categories is a comma-separated list of categories</i></span>'); } elseif (!strcmp(PONYDOCS_DOCUMENTATION_PRODUCTS_TITLE, $wgTitle->__toString())) { $this->data['titletext'] = 'Products Management'; $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Use {{#product:productShortName|displayName|description|parent|categories}} to define a new product.' . '</i></span>'); $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Prepend product short name with ' . PONYDOCS_PRODUCT_STATIC_PREFIX . ' to define a static product.' . '</i></span>'); $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* displayName, description, parent, and categories can be left empty.</i></span>'); $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* If you leave displayName empty, productShortName will be used in links.</i></span>'); $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* Categories is a comma-separated list of categories.</i></span>'); $wgOut->addHTML('<br><span class="' . $helpClass . '">' . '<i>* Each product here <b>MUST</b> also be listed in $ponyDocsProductsList,' . ' usually configured in LocalSettings.php.</i></span>'); } elseif (preg_match('/(.*)TOC(.*)/', $pieces[2], $matches)) { $this->data['titletext'] = $matches[1] . ' Table of Contents Page'; $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Optionally start this page with {{#manualDescription:Manual Description.}}' . ' followed by two line-breaks to set a manual description for the Manual this TOC belongs to.' . '</i></span>'); $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Topics are grouped into sections by section headers.' . ' Any line without markup is considered a section header.' . ' A section header is required before the the first topic tag.</i></span>'); $wgOut->addHTML('<br><span class="' . $helpClass . '"><i>' . '* Topic tags must be part of an unordered list.' . ' Use {{#topic:Display Name}} after a * (list item markup) to create topics.</i></span>'); } elseif (sizeof($pieces) >= 2 && PonyDocsProductManual::IsManual($pieces[1], $pieces[2])) { $pManual = PonyDocsProductManual::GetManualByShortName($pieces[1], $pieces[2]); if ($pManual) { $this->data['manualname'] = $pManual->getLongName(); } else { $this->data['manualname'] = $pieces[2]; } $this->data['topicname'] = $pieces[3]; $this->data['titletext'] = $pieces[2]; } else { $this->data['topicname'] = $pieces[2]; } } else { $pManual = PonyDocsProductManual::GetManualByShortName($pieces[1], $pieces[2]); if ($pManual) { $this->data['manualname'] = $pManual->getLongName(); } else { $this->data['manualname'] = $pieces[2]; } $this->data['topicname'] = $pieces[3]; $h1 = PonyDocsTopic::FindH1ForTitle($wgTitle->__toString()); if ($h1 !== FALSE) { $this->data['titletext'] = $h1; } } /** * Get current topic, passing it our global Article object. * From this, generate our TOC based on the current topic selected. * This generates our left sidebar TOC plus our prev/next/start navigation links. * This should ONLY be done if we actually are WITHIN a manual, so special pages like TOC, etc. should not do this! */ if ($pManual) { $p = PonyDocsProduct::GetProductByShortName($this->data['selectedProduct']); $v = PonyDocsProductVersion::GetVersionByName($this->data['selectedProduct'], $this->data['selectedVersion']); $toc = new PonyDocsTOC($pManual, $v, $p); list($this->data['manualtoc'], $this->data['tocprev'], $this->data['tocnext'], $this->data['tocstart']) = $toc->loadContent(); $this->data['toctitle'] = $toc->getTOCPageTitle(); } /** * Create a PonyDocsTopic from our article. From this we populate: * * topicversions: List of version names topic is tagged with. * inlinetoc: Inline TOC shown above article body. * catcode: Special category code. * cattext: Category description. * basetopicname: Base topic name (w/o :<version> at end). * basetopiclink: Link to special TopicList page to view all same topics. */ $context = $this->skin->getContext(); $article = Article::newFromTitle($context->getTitle(), $context); $topic = new PonyDocsTopic($article); if (preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(.*):(.*):(.*):(.*)/', $wgTitle->__toString()) || preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':.*:.*TOC.*/', $wgTitle->__toString())) { $this->data['topicversions'] = PonyDocsWiki::getVersionsForTopic($topic); $this->data['inlinetoc'] = $topic->getSubContents(); $this->data['versionclasses'] = $topic->getVersionClasses(); $this->data['versionGroupMessage'] = $this->data['pVersion']->getVersionGroupMessage(); /** * Sort of a hack -- we only use this right now when loading a TOC page which is new/does not exist. * When this happens a hook (AlternateEdit) adds an inline script to define this JS function, * which populates the edit box with the proper Category tag based on the currently selected version. */ $this->data['body_onload'] = 'ponyDocsOnLoad();'; switch ($this->data['catcode']) { case 0: $this->data['cattext'] = 'Applies to latest version which is currently unreleased.'; break; case 1: $this->data['cattext'] = 'Applies to latest version.'; break; case 2: $this->data['cattext'] = 'Applies to released version(s) but not the latest.'; break; case 3: $this->data['cattext'] = 'Applies to latest preview version.'; break; case 4: $this->data['cattext'] = 'Applies to one or more preview version(s) only.'; break; case 5: $this->data['cattext'] = 'Applies to one or more unreleased version(s) only.'; break; case -2: /** Means its not a a title name which should be checked. */ break; default: $this->data['cattext'] = 'Does not apply to any version of PonyDocs.'; break; } } $this->data['basetopicname'] = $topic->getBaseTopicName(); if (strlen($this->data['basetopicname'])) { $this->data['basetopiclink'] = '<a href="' . $wgScriptPath . '/index.php?title=Special:TopicList&topic=' . $this->data['basetopicname'] . '">View All</a>'; } $temp = PonyDocsTopic::FindH1ForTitle(PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $topic->getTitle()->getText()); if ($temp !== false) { // We got an H1! $this->data['pagetitle'] = $temp; } }