/**
  * This is called upon loading the special page. It should write output to the page with $wgOut.
  * 
  * @param string $par The portion of the URI after Special:StaticDocServer/
  */
 public function execute($par)
 {
     #TODO: switch to $this->getOuput() and $this->getRequest() when we upgrade MW
     global $wgOut, $wgRequest;
     $wgOut->disable();
     $found = FALSE;
     list($productName, $versionName, $path) = explode('/', $par, 3);
     if (substr($par, -1, 1) == '/') {
         $par .= 'index.html';
     }
     // Validate parameters are set
     if (isset($productName) && isset($versionName) && PonyDocsProduct::GetProductByShortName($productName) && PonyDocsProductVersion::GetVersionByName($productName, $versionName)) {
         $filename = PONYDOCS_STATIC_DIR . "/{$par}";
         if (file_exists($filename)) {
             $found = TRUE;
         }
     }
     if (!$found) {
         $wgRequest->response()->header("HTTP/1.1 404 Not Found");
         echo "<html>\n";
         echo "<head><title>Not Found</title></head>\n";
         echo "<body>\n";
         echo "<h1>Bad Request</h1>\n";
         echo "<div>The documentation you have requested does not exist.</div>\n";
         echo "</body>\n";
         echo "</html>\n";
     } else {
         $mimeMagic = MimeMagic::singleton();
         $pathParts = pathinfo($filename);
         /* get mime-type for a specific file */
         header('Content-type: ' . $mimeMagic->guessTypesForExtension($pathParts['extension']));
         readfile($filename);
     }
 }
 /**
  * Hook function which
  * - Sets the version correctly when editing a topic
  * - Redirects to the first topic in a manual if the user requested a bare manual URL
  * - Redirect to the landing page when there are no available versions
  */
 public function onArticleFromTitleQuickLookup(&$title, &$article)
 {
     global $wgScriptPath;
     if (preg_match('/&action=edit/', $_SERVER['PATH_INFO'])) {
         // Check referrer and see if we're coming from a doc page.
         // If so, we're editing it, so we should force the version
         // to be from the referrer.
         if (preg_match('/^' . str_replace("/", "\\/", $wgScriptPath) . '\\/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '\\/(\\w+)\\/((latest|[\\w\\.]*)\\/)?(\\w+)\\/?/i', $_SERVER['HTTP_REFERER'], $match)) {
             $targetProduct = $match[1];
             $targetVersion = $match[3];
             if ($targetVersion == "latest") {
                 PonyDocsProductVersion::SetSelectedVersion($targetProduct, PonyDocsProductVersion::GetLatestReleasedVersion($targetProduct)->getVersionName());
             } else {
                 PonyDocsProductVersion::SetSelectedVersion($targetProduct, $targetVersion);
             }
         }
     }
     // Match a URL like /Documentation/PRODUCT
     if (preg_match('/^' . str_replace("/", "\\/", $wgScriptPath) . '\\/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '\\/([' . PONYDOCS_PRODUCT_LEGALCHARS . ']+)$/i', $_SERVER['PATH_INFO'], $match)) {
         $targetProduct = $match[1];
         $version = PonyDocsProductVersion::GetVersions($targetProduct, TRUE);
         //check for product not found
         if (empty($version)) {
             PonyDocsExtension::redirectToLandingPage();
             return true;
         }
     }
     // Matches a URL like /Documentation/PRODUCT/VERSION/MANUAL
     // TODO: Should match PONYDOCS_PRODUCTMANUAL_LEGALCHARS instead of \w at the end
     if (preg_match('/^' . str_replace("/", "\\/", $wgScriptPath) . '\\/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . '\\/([' . PONYDOCS_PRODUCT_LEGALCHARS . ']+)\\/([' . PONYDOCS_PRODUCTVERSION_LEGALCHARS . ']+)\\/(\\w+)\\/?$/i', $_SERVER['PATH_INFO'], $match)) {
         $targetProduct = $match[1];
         $targetVersion = $match[2];
         $targetManual = $match[3];
         $p = PonyDocsProduct::GetProductByShortName($targetProduct);
         if (!$p instanceof PonyDocsProduct) {
             $wgHooks['BeforePageDisplay'][] = "PonyDocsExtension::handle404";
             return false;
         }
         // User wants to find first topic in a requested manual.
         // Load up versions
         PonyDocsProductVersion::LoadVersionsForProduct($targetProduct);
         // Determine version
         if ($targetVersion == '') {
             // No version specified, use the user's selected version
             $ver = PonyDocsProductVersion::GetVersionByName($targetProduct, PonyDocsProductVersion::GetSelectedVersion($targetProduct));
         } else {
             if (strtolower($targetVersion) == "latest") {
                 // User wants the latest version.
                 $ver = PonyDocsProductVersion::GetLatestReleasedVersion($targetProduct);
             } else {
                 // Okay, they want to get a version by a specific name
                 $ver = PonyDocsProductVersion::GetVersionByName($targetProduct, $targetVersion);
             }
         }
         if (!$ver) {
             if (PONYDOCS_DEBUG) {
                 error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$wgScriptPath}/" . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME);
             }
             header('Location: ' . $wgScriptPath . '/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME);
             die;
         }
         // Okay, the version is valid, let's set the user's version.
         PonyDocsProductVersion::SetSelectedVersion($targetProduct, $ver->getVersionName());
         PonyDocsProductManual::LoadManualsForProduct($targetProduct);
         $manual = PonyDocsProductManual::GetManualByShortName($targetProduct, $targetManual);
         if (!$manual) {
             // Rewrite to Main documentation
             if (PONYDOCS_DEBUG) {
                 error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$wgScriptPath}/" . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME);
             }
             header('Location: ' . $wgScriptPath . '/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME);
             die;
         } elseif (!$manual->isStatic()) {
             // Get the TOC out of here! heehee
             $toc = new PonyDocsTOC($manual, $ver, $p);
             list($toc, $prev, $next, $start) = $toc->loadContent();
             //Added empty check for WEB-10038
             if (empty($toc)) {
                 PonyDocsExtension::redirectToLandingPage();
                 return FALSE;
             }
             foreach ($toc as $entry) {
                 if (isset($entry['link']) && $entry['link'] != "") {
                     // We found the first article in the manual with a link.
                     // Redirect to it.
                     if (PONYDOCS_DEBUG) {
                         error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to " . $entry['link']);
                     }
                     header("Location: " . $entry['link']);
                     die;
                 }
             }
             //Replace die with a warning log and redirect
             error_log("WARNING [" . __METHOD__ . ":" . __LINE__ . "] redirecting to " . PonyDocsExtension::getDefaultUrl());
             PonyDocsExtension::redirectToLandingPage();
             return FALSE;
         }
     }
     return TRUE;
 }
Example #3
0
 /**
  * Called when an unknown action occurs on url.  We are only interested in zipmanual action.
  */
 function onUnknownAction($action, $article)
 {
     global $wgOut, $wgUser, $wgTitle, $wgParser, $wgRequest;
     global $wgServer, $wgArticlePath, $wgScriptPath, $wgUploadPath, $wgUploadDirectory, $wgScript, $wgStylePath;
     // We don't do any processing unless it's zipmanual
     if ($action != 'zipmanual') {
         return true;
     }
     $zipAllowed = false;
     PonyDocsExtension::onUserCan($wgTitle, $wgUser, 'zipmanual', &$zipAllowed);
     if (!$zipAllowed) {
         error_log("WARNING [" . __METHOD__ . "] User attempted to perform a ZIP Export without permission.");
         $defaultRedirect = PonyDocsExtension::getDefaultUrl();
         header("Location: " . $defaultRedirect);
         exit;
     }
     // Get the title and make sure we're in Documentation namespace
     $title = $article->getTitle();
     if ($title->getNamespace() != NS_PONYDOCS) {
         return true;
     }
     // Grab parser options for the logged in user.
     $opt = ParserOptions::newFromUser($wgUser);
     // Any potential titles to exclude
     $exclude = array();
     // Determine articles to gather
     $articles = array();
     $pieces = explode(":", $wgTitle->__toString());
     // Try and get rid of the TOC portion of the title
     if (strpos($pieces[2], "TOC") && count($pieces) == 3) {
         $pieces[2] = substr($pieces[2], 0, strpos($pieces[2], "TOC"));
     } else {
         if (count($pieces) != 5) {
             // something is wrong, let's get out of here
             $defaultRedirect = PonyDocsExtension::getDefaultUrl();
             if (PONYDOCS_DEBUG) {
                 error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$defaultRedirect}");
             }
             header("Location: " . $defaultRedirect);
             exit;
         }
     }
     $productName = $pieces[1];
     $ponydocs = PonyDocsWiki::getInstance($productName);
     $pProduct = PonyDocsProduct::GetProductByShortName($productName);
     if ($pProduct === NULL) {
         // product wasn't valid
         wfProfileOut(__METHOD__);
         $wgOut->setStatusCode(404);
         return FALSE;
     }
     $productLongName = $pProduct->getLongName();
     if (PonyDocsProductManual::isManual($productName, $pieces[2])) {
         $pManual = PonyDocsProductManual::GetManualByShortName($productName, $pieces[2]);
     }
     $versionText = PonyDocsProductVersion::GetSelectedVersion($productName);
     if (!empty($pManual)) {
         // We should always have a pManual, if we're printing
         // from a TOC
         $v = PonyDocsProductVersion::GetVersionByName($productName, $versionText);
         $toc = new PonyDocsTOC($pManual, $v, $pProduct);
         list($manualtoc, $tocprev, $tocnext, $tocstart) = $toc->loadContent();
         // We successfully got our table of contents.  It's
         // stored in $manualtoc
         foreach ($manualtoc as $tocEntry) {
             if ($tocEntry['level'] > 0 && strlen($tocEntry['title']) > 0) {
                 $title = Title::newFromText($tocEntry['title']);
                 $articles[$tocEntry['section']][] = array('title' => $title, 'text' => $tocEntry['text']);
             }
         }
     } else {
         error_log("WARNING [" . __METHOD__ . "] " . php_uname('n') . ": User attempted to export ZIP from a non TOC page with path:" . $wgTitle->__toString());
     }
     $html = self::getManualHTML($pProduct, $pManual, $v);
     $coverPageHTML = self::getCoverPageHTML($pProduct, $pManual, $v, false);
     // Make a temporary directory to store our archive contents.
     $tempDirPath = sys_get_temp_dir() . '/ponydocs-zip-export-' . time();
     $success = @mkdir($tempDirPath);
     if (!$success) {
         error_log("FATAL [" . __METHOD__ . "] Failed to create temporary directory " . $tempDirPath . " for Zip Export.");
         throw new Exception('Failed to create temporary directory for Zip Export.');
     }
     // Now, let's fetch all the img elements for both and grab them all in
     // parallel.
     $imgData = array();
     // Initialize our RollingCurl instance
     $rollingCurl = new \RollingCurl\RollingCurl();
     $mh = curl_multi_init();
     $manualDoc = new DOMDocument();
     @$manualDoc->loadHTML($html);
     $coverPageDoc = new DOMDocument();
     @$coverPageDoc->loadHTML($coverPageHTML);
     self::prepareImageRequests($manualDoc, $rollingCurl, $tempDirPath, &$imgData);
     self::prepareImageRequests($coverPageDoc, $rollingCurl, $tempDirPath, &$imgData);
     // Execute the RollingCurl requests
     $rollingCurl->execute();
     // Now update all our image elements in our appropriate DOMDocs.
     foreach ($imgData as $img) {
         // Put the data into it.
         file_put_contents($img['local_path'], $img['request']->getResponseText());
         // Modify element
         $img['element']->setAttribute('src', $img['new_path']);
         // Do curl cleanup
     }
     $html = $manualDoc->saveHTML();
     $coverPageHTML = $coverPageDoc->saveHTML();
     // Write the HTML to a tmp file
     $file = tempnam($tempDirPath, "zipexport-");
     $fh = fopen($file, 'w+');
     fwrite($fh, $html);
     fclose($fh);
     // Okay, write the title page
     $titlepagefile = tempnam($tempDirPath, "zipexport-");
     $fh = fopen($titlepagefile, 'w+');
     fwrite($fh, $coverPageHTML);
     fclose($fh);
     // Disable output of our standard mediawiki output.  We will be outputting a zip file instead.
     $wgOut->disable();
     // Create ZIP Archive which contains a cover and manual html
     $zip = new ZipArchive();
     $tempZipFilePath = tempnam($tempDirPath, "zipexport-");
     $zipFileName = $productName . '-' . $versionText . '-' . $pManual->getShortName() . '.zip';
     $zip->open($tempZipFilePath, ZipArchive::OVERWRITE);
     $zip->addFile($titlepagefile, 'cover.html');
     $zip->addFile($file, 'manual.html');
     // Iterate through all the images
     foreach ($imgData as $img) {
         $zip->addFile($img['local_path'], $img['new_path']);
     }
     $zip->close();
     header("Content-Type: application/zip");
     header("Content-Length: " . filesize($tempZipFilePath));
     header("Content-Disposition: attachment; filename=\"" . $zipFileName . "\"");
     readfile($tempZipFilePath);
     // Now remove all temp files
     self::rrmdir($tempDirPath);
     // Okay, let's add an entry to the error log to dictate someone requested a pdf
     error_log("INFO [" . __METHOD__ . "] " . php_uname('n') . ": zip export serve username=\"" . $wgUser->getName() . "\" version=\"{$versionText}\" " . " manual=\"" . $pManual->getShortName() . "\"");
     // No more processing
     return false;
 }
Example #4
0
 /**
  * This actually loads the list of versions for which the TOC is tagged and stores the PonyDocsVersion objects. 
  *
  * @return boolean
  */
 public function load()
 {
     /**
      * First define the TOC prefix, which will be something like 'Documentation:<manualShort>TOC'.
      * We then scan the categorylinks table for the initial version supplied as 'cl_to'.
      * This should only return one row, but we're going to ignore anything but the first just in case.
      * The resulting 'cl_sortkey' is the actual full name of the TOC page.
      * From this we then scan the same table for all 'cl_to' matches for the complete name and add those versions to our list.
      */
     $dbr = wfGetDB(DB_SLAVE);
     $res = $dbr->select(array('categorylinks', 'page'), array('cl_sortkey', 'page_title'), array('cl_from = page_id', 'page_namespace = "' . NS_PONYDOCS . '"', "cl_to = 'V:" . $dbr->strencode($this->pProduct->getShortName() . ":" . $this->pInitialVersion->getVersionName()) . "'", 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper($this->pProduct->getShortName() . ":" . $this->pManual->getShortName())) . "TOC%'"), __METHOD__);
     if (!$res->numRows()) {
         return FALSE;
     }
     $row = $dbr->fetchObject($res);
     $mTOCPageTitle = PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ":{$row->page_title}";
     $this->mTOCPageTitle = $mTOCPageTitle;
     // TODO: Why not just get cl_to in previous query?
     $res = $dbr->select('categorylinks', 'cl_to', array('cl_to LIKE "V:%:%"', 'cl_type = "page"', "cl_sortkey = '" . $dbr->strencode($row->cl_sortkey) . "'"), __METHOD__);
     while ($row = $dbr->fetchObject($res)) {
         if (preg_match('/^v:(.*):(.*)/i', $row->cl_to, $match)) {
             $addV = PonyDocsProductVersion::GetVersionByName($match[1], $match[2]);
             if ($addV) {
                 $this->addVersion($addV);
             }
         }
     }
     /**
      * Now load the contents of our TOC article itself and store internally.
      *
      */
     $this->pTOCArticle = new Article(Title::newFromText($mTOCPageTitle), 0);
     $this->pTOCArticle->getContent();
     return TRUE;
 }
Example #5
0
 /**
  * Processes a rename version request for a single manual
  *
  * @param $jobID The unique id for this job (see ajaxFetchJobID)
  * @param $productName string product short name
  * @param $manualName string manual short name
  * @param $sourceVersionName string String representation of the source version
  * @param $targetVersionName string String representaiton of the target version
  * @return string Full job log of the process by printing to stdout.
  */
 public static function ajaxProcessManual($jobID, $productName, $manualName, $sourceVersionName, $targetVersionName)
 {
     global $wgScriptPath;
     ob_start();
     list($msec, $sec) = explode(' ', microtime());
     $startTime = (double) $msec + (double) $sec;
     $logFields = "action=start status=success product={$productName} manual={$manualName} " . "sourceVersion={$sourceVersionName} targetVersion={$targetVersionName}";
     error_log('INFO [' . __METHOD__ . "] [RenameVersion] {$logFields}");
     // Validate product and versions
     $product = PonyDocsProduct::GetProductByShortName($productName);
     $manual = PonyDocsProductManual::getManualByShortName($productName, $manualName);
     $sourceVersion = PonyDocsProductVersion::GetVersionByName($productName, $sourceVersionName);
     $targetVersion = PonyDocsProductVersion::GetVersionByName($productName, $targetVersionName);
     if (!($product && $manual && $sourceVersion && $targetVersion)) {
         $result = array('success', false);
         $result = json_encode($result);
         return $result;
     }
     // TODO: Is this necessary? Haven't we done this already?
     PonyDocsProductVersion::SetSelectedVersion($productName, $sourceVersionName);
     print "Beginning process job for manual: {$manualName}<br />";
     print "Source version is {$productName}:{$sourceVersionName}<br />";
     print "Target version is {$targetVersionName}<br />";
     // Get topics
     // Update log file
     // TODO: Pull this out into a separate method somewhere
     $path = PonyDocsExtension::getTempDir() . $jobID;
     $fp = fopen($path, "w+");
     fputs($fp, "Getting Topics for {$manualName}");
     fclose($fp);
     // TODO: This is copied form SpecialBranchInherit::ajaxFetchTopics() and should get DRYed out
     $manualTopics = array();
     $TOC = new PonyDocsTOC($manual, $sourceVersion, $product);
     list($toc, $prev, $next, $start) = $TOC->loadContent();
     // Time to iterate through all the items.
     $section = '';
     foreach ($toc as $tocItem) {
         if ($tocItem['level'] == 0) {
             $section = $tocItem['text'];
             $manualTopics[$manualName]['sections'][$section] = array();
             $manualTopics[$manualName]['sections'][$section]['meta'] = array();
             $manualTopics[$manualName]['sections'][$section]['topics'] = array();
         }
         // actual topic
         if ($tocItem['level'] == 1) {
             $tempEntry = array('title' => $tocItem['title'], 'text' => $tocItem['text'], 'toctitle' => $tocItem['toctitle'], 'conflicts' => PonyDocsBranchInheritEngine::getConflicts($product, $tocItem['title'], $targetVersion));
             $manualTopics[$manualName]['sections'][$section]['topics'][] = $tempEntry;
         }
     }
     foreach ($manualTopics as $manualName => $manual) {
         foreach ($manual['sections'] as $sectionIndex => $section) {
             if (count($section['topics']) == 0) {
                 unset($manualTopics[$manualName]['sections'][$sectionIndex]);
             }
         }
     }
     $logFields = "action=topics status=success product={$productName} manual={$manualName} " . "sourceVersion={$sourceVersionName} targetVersion={$targetVersionName}";
     error_log('INFO [' . __METHOD__ . "] [RenameVersion] {$logFields}");
     // Enable speed processing to avoid any unnecessary processing on topics modified by this tool.
     // TODO: I'm not 100% sure this is necessary or proper here -RU
     PonyDocsExtension::setSpeedProcessing(TRUE);
     // Determine how many topics there are to process so that we can keep track of progress
     $numOfTopics = 0;
     $numOfTopicsCompleted = 0;
     foreach ($manualTopics as $manualName => $manualData) {
         foreach ($manualData['sections'] as $sectionName => $section) {
             // The following is a goofy fix for some browsers.
             // Sometimes the JSON comes along with null values for the first element.
             // It's just an additional element, so we can drop it.
             // TODO: Since we're no longer getting this from JSON, this is probably removeable
             if (empty($section['topics'][0]['text'])) {
                 array_shift($manualTopics[$manualName]['sections'][$sectionName]['topics']);
             }
             $numOfTopics += count($manualTopics[$manualName]['sections'][$sectionName]['topics']);
         }
     }
     foreach ($manualTopics as $manualName => $manualData) {
         // TODO: We already got the manual above, why make another? We could add the manual to $manualTopics somewhere..
         $manual = PonyDocsProductManual::GetManualByShortName($productName, $manualName);
         // First update all the topics
         print '<div class="normal">Processing topics</div>';
         foreach ($manualData['sections'] as $sectionName => $section) {
             print "<div class=\"normal\">Processing section {$sectionName}</div>";
             foreach ($section['topics'] as $topic) {
                 // Update log file
                 $fp = fopen($path, "w+");
                 fputs($fp, "Renaming topics in manual {$manualName}<br />" . "Completed {$numOfTopicsCompleted} of {$numOfTopics} Total: " . (int) ($numOfTopicsCompleted / $numOfTopics * 100) . '%');
                 fclose($fp);
                 try {
                     print '<div class="normal">Attempting to update topic ' . $topic['title'] . '...';
                     PonyDocsRenameVersionEngine::changeVersionOnTopic($topic['title'], $sourceVersion, $targetVersion);
                     $logFields = "action=topic status=success product={$productName} manual={$manualName} " . "title={$topic['title']} sourceVersion={$sourceVersionName} targetVersion={$targetVersionName}";
                     error_log('INFO [' . __METHOD__ . "] [RenameVersion] {$logFields}");
                     print 'Complete</div>';
                 } catch (Exception $e) {
                     $logFields = "action=topic status=failure error={$e->getMessage()} product={$productName} manual={$manualName} " . "title={$topic['title']} sourceVersion={$sourceVersionName} targetVersion={$targetVersionName}";
                     error_log('WARNING [' . __METHOD__ . "] [RenameVersion] {$logFields}");
                     print '</div><div class="error">Exception: ' . $e->getMessage() . '</div>';
                 }
                 $numOfTopicsCompleted++;
             }
         }
         // Now we can update the TOC
         // Determine if TOC already exists for target version.
         if (!PonyDocsBranchInheritEngine::TOCExists($product, $manual, $sourceVersion)) {
             print '<div class="normal">TOC Does not exist for Manual ' . $manual->getShortName() . ' with version ' . $targetVersion->getVersionName() . '</div>';
         } else {
             try {
                 print '<div class="normal">Attempting to update TOC...';
                 PonyDocsRenameVersionEngine::changeVersionOnTOC($product, $manual, $sourceVersion, $targetVersion);
                 $logFields = "action=TOC status=success product={$productName} manual={$manualName} " . "sourceVersion={$sourceVersionName} targetVersion={$targetVersionName}";
                 error_log('INFO [' . __METHOD__ . "] [RenameVersion] {$logFields}");
                 print 'Complete</div>';
             } catch (Exception $e) {
                 $logFields = "action=TOC status=failure error={$e->getMessage()} product={$productName} manual={$manualName} " . "sourceVersion={$sourceVersionName} targetVersion={$targetVersionName}";
                 error_log('WARNING [' . __METHOD__ . "] [RenameVersion] {$logFields}");
                 print '</div><div class="error">Exception: ' . $e->getMessage() . '</div>';
             }
         }
     }
     list($msec, $sec) = explode(' ', microtime());
     $endTime = (double) $msec + (double) $sec;
     print "Done with {$manualName}! Execution Time: " . round($endTime - $startTime, 3) . ' seconds<br />';
     //WEB-10792, Clear TOCCACHE for the target version only, each Manual at a time
     PonyDocsTOC::clearTOCCache($manual, $targetVersion, $product);
     //Also clear the NAVCache for the target version
     PonyDocsProductVersion::clearNAVCache($targetVersion);
     unlink($path);
     $buffer = ob_get_clean();
     return $buffer;
 }
Example #6
0
 /**
  * Return an array of versions for the supplied article.
  * These are saved as category tags so we need to find the page_id from the article and anything in the categorylinks table.
  * Return a list with each element being a PonyDocsVersion object.
  * 
  * @param boolean $reload If true, force reload from database; else used cache copy (if found).
  * @return array
  */
 public function getProductVersions($reload = FALSE)
 {
     if (sizeof($this->versions) && !$reload) {
         return $this->versions;
     }
     $dbr = wfGetDB(DB_SLAVE);
     $revision = $this->pArticle->mRevision;
     $res = $dbr->select('categorylinks', 'cl_to', array('cl_to LIKE "V:%:%"', 'cl_type = "page"', "cl_sortkey = '" . $dbr->strencode(strtoupper($this->pTitle->getText())) . "'"), __METHOD__);
     $this->versions = array();
     while ($row = $dbr->fetchObject($res)) {
         if (preg_match('/^v:(.*):(.*)/i', $row->cl_to, $match)) {
             $v = PonyDocsProductVersion::GetVersionByName($match[1], $match[2]);
             if ($v) {
                 $this->versions[] = $v;
             }
         }
     }
     // Sort by the order on the versions admin page
     usort($this->versions, "PonyDocs_ProductVersionCmp");
     return $this->versions;
 }
 /**
  * Clear NAVDATA cache by product and version
  * @param string $product 
  * @param string $version
  */
 private function clearProductCache($productName, $versionName)
 {
     //verify product has the version
     $versionObj = PonyDocsProductVersion::GetVersionByName($productName, $versionName);
     if ($versionObj != FALSE) {
         PonyDocsProductVersion::clearNAVCache($versionObj);
     }
 }
Example #8
0
 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;
     }
 }
Example #9
0
 /**
  * Called when an unknown action occurs on url.  We are only interested in pdfbook action.
  */
 function onUnknownAction($action, $article)
 {
     global $wgOut, $wgUser, $wgTitle, $wgParser, $wgRequest;
     global $wgServer, $wgArticlePath, $wgScriptPath, $wgUploadPath, $wgUploadDirectory, $wgScript, $wgStylePath;
     // We don't do any processing unless it's pdfbook
     if ($action != 'pdfbook') {
         return true;
     }
     // Get the title and make sure we're in Documentation namespace
     $title = $article->getTitle();
     if ($title->getNamespace() != NS_PONYDOCS) {
         return true;
     }
     // Grab parser options for the logged in user.
     $opt = ParserOptions::newFromUser($wgUser);
     // Log the export
     $msg = $wgUser->getUserPage()->getPrefixedText() . ' exported as a PonyDocs PDF Book';
     $log = new LogPage('ponydocspdfbook', false);
     $log->addEntry('book', $wgTitle, $msg);
     // Initialise PDF variables
     $layout = '--firstpage p1';
     $x_margin = '1.25in';
     $y_margin = '1in';
     $font = 'Arial';
     $size = '12';
     $linkcol = '4d9bb3';
     $levels = '2';
     $exclude = array();
     $width = '1024';
     $width = "--browserwidth 1024";
     // Determine articles to gather
     $articles = array();
     $pieces = explode(":", $wgTitle->__toString());
     // Try and get rid of the TOC portion of the title
     if (strpos($pieces[2], "TOC") && count($pieces) == 3) {
         $pieces[2] = substr($pieces[2], 0, strpos($pieces[2], "TOC"));
     } else {
         if (count($pieces) != 5) {
             // something is wrong, let's get out of here
             $defaultRedirect = PonyDocsExtension::getDefaultUrl();
             if (PONYDOCS_DEBUG) {
                 error_log("DEBUG [" . __METHOD__ . ":" . __LINE__ . "] redirecting to {$defaultRedirect}");
             }
             header("Location: " . $defaultRedirect);
             exit;
         }
     }
     $productName = $pieces[1];
     $ponydocs = PonyDocsWiki::getInstance($productName);
     $pProduct = PonyDocsProduct::GetProductByShortName($productName);
     if ($pProduct === NULL) {
         // product wasn't valid
         wfProfileOut(__METHOD__);
         $wgOut->setStatusCode(404);
         return FALSE;
     }
     $productLongName = $pProduct->getLongName();
     if (PonyDocsProductManual::isManual($productName, $pieces[2])) {
         $pManual = PonyDocsProductManual::GetManualByShortName($productName, $pieces[2]);
     }
     $versionText = PonyDocsProductVersion::GetSelectedVersion($productName);
     if (!empty($pManual)) {
         // We should always have a pManual, if we're printing from a TOC
         $v = PonyDocsProductVersion::GetVersionByName($productName, $versionText);
         // We have our version and our manual Check to see if a file already exists for this combination
         $pdfFileName = "{$wgUploadDirectory}/ponydocspdf-" . $productName . "-" . $versionText . "-" . $pManual->getShortName() . "-book.pdf";
         // Check first to see if this PDF has already been created and is up to date.  If so, serve it to the user and stop
         // execution.
         if (file_exists($pdfFileName)) {
             error_log("INFO [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": cache serve username=\"" . $wgUser->getName() . "\" product=\"" . $productName . "\" version=\"" . $versionText . "\" " . " manual=\"" . $pManual->getShortName() . "\"");
             PonyDocsPdfBook::servePdf($pdfFileName, $productName, $versionText, $pManual->getShortName());
             // No more processing
             return false;
         }
     } else {
         error_log("ERROR [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": User attempted to print a pdfbook from a non TOC page with path:" . $wgTitle->__toString());
     }
     $html = self::getManualHTML($pProduct, $pManual, $v);
     // HTMLDOC does not care for utf8.
     $html = utf8_decode("{$html}\n");
     // Write the HTML to a tmp file
     $file = "{$wgUploadDirectory}/" . uniqid('ponydocs-pdf-book');
     $fh = fopen($file, 'w+');
     fwrite($fh, $html);
     fclose($fh);
     // Okay, create the title page
     $titlepagefile = "{$wgUploadDirectory}/" . uniqid('ponydocs-pdf-book-title');
     $fh = fopen($titlepagefile, 'w+');
     $coverPageHTML = self::getCoverPageHTML($pProduct, $pManual, $v);
     fwrite($fh, $coverPageHTML);
     fclose($fh);
     $format = 'manual';
     /* @todo Modify so single topics can be printed in pdf */
     $footer = $format == 'single' ? '...' : '.1.';
     $toc = $format == 'single' ? '' : " --toclevels {$levels}";
     // Send the file to the client via htmldoc converter
     $wgOut->disable();
     $cmd = " --left {$x_margin} --right {$x_margin} --top {$y_margin} --bottom {$y_margin}";
     $cmd .= " --header ... --footer {$footer} --tocfooter .i. --quiet --jpeg --color";
     $cmd .= " --bodyfont {$font} --fontsize {$size} --linkstyle plain --linkcolor {$linkcol}";
     $cmd .= "{$toc} --format pdf14 {$layout} {$width} --titlefile {$titlepagefile} --size letter";
     $cmd = "htmldoc -t pdf --book --charset iso-8859-1 --no-numbered {$cmd} {$file} > {$pdfFileName}";
     putenv("HTMLDOC_NOCGI=1");
     $output = array();
     $returnVar = 1;
     exec($cmd, $output, $returnVar);
     if ($returnVar != 0) {
         // 0 is success
         error_log("INFO [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": Failed to run htmldoc (" . $returnVar . ") Output is as follows: " . implode("-", $output));
         print "Failed to create PDF.  Our team is looking into it.";
     }
     // Delete the htmlfile and title file from the filesystem.
     @unlink($file);
     if (file_exists($file)) {
         error_log("ERROR [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": Failed to delete temp file {$file}");
     }
     @unlink($titlepagefile);
     if (file_exists($titlepagefile)) {
         error_log("ERROR [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": Failed to delete temp file {$titlepagefile}");
     }
     // Okay, let's add an entry to the error log to dictate someone requested a pdf
     error_log("INFO [PonyDocsPdfBook::onUnknownAction] " . php_uname('n') . ": fresh serve username=\"" . $wgUser->getName() . "\" version=\"{$versionText}\" " . " manual=\"" . $pManual->getLongName() . "\"");
     PonyDocsPdfBook::servePdf($pdfFileName, $productName, $versionText, $pManual->getLongName());
     // No more processing
     return false;
 }
Example #10
0
    /**
     * This is called upon loading the special page.  It should write output to the page with $wgOut.
     */
    public function execute()
    {
        global $wgOut, $wgArticlePath, $wgScriptPath;
        global $wgUser;
        $dbr = wfGetDB(DB_SLAVE);
        $this->setHeaders();
        $wgOut->setPagetitle('Documentation Branch And Inheritance');
        // if title is set we have our product and manual, else take selected product
        if (isset($_GET['titleName'])) {
            if (!preg_match('/' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':(.*):(.*):(.*):(.*)/', $_GET['titleName'], $match)) {
                throw new Exception("Invalid Title to Branch From");
            }
            $forceProduct = $match[1];
            $forceManual = $match[2];
        } else {
            $forceProduct = PonyDocsProduct::GetSelectedProduct();
            $ponydocs = PonyDocsWiki::getInstance($forceProduct);
            $products = $ponydocs->getProductsForTemplate();
        }
        // Security Check
        $authProductGroup = PonyDocsExtension::getDerivedGroup(PonyDocsExtension::ACCESS_GROUP_PRODUCT, $forceProduct);
        $groups = $wgUser->getGroups();
        if (!in_array($authProductGroup, $groups)) {
            $wgOut->addHTML("<p>Sorry, but you do not have permission to access this Special page.</p>");
            return;
        }
        // Static product check
        if (PonyDocsProduct::GetProductByShortName($forceProduct)->isStatic()) {
            $wgOut->addHTML("<p>Sorry, but you cannot branch/inherit a static product.</p>");
            return;
        }
        ob_start();
        // Grab all versions available for product
        // We need to get all versions from PonyDocsProductVersion
        $versions = PonyDocsProductVersion::GetVersions($forceProduct);
        if (isset($_GET['titleName'])) {
            ?>
			<input type="hidden" id="force_titleName" value="<?php 
            echo $_GET['titleName'];
            ?>
" />
			<input type="hidden" id="force_sourceVersion" value="<?php 
            echo PonyDocsProductVersion::GetVersionByName($forceProduct, PonyDocsProductVersion::GetSelectedVersion($forceProduct))->getVersionName();
            ?>
" />
			<input type="hidden" id="force_manual" value="<?php 
            echo $forceManual;
            ?>
" />
			<?php 
        }
        ?>

		<input type="hidden" id="force_product" value="<?php 
        echo $forceProduct;
        ?>
" />
		<div id="docbranchinherit">
		<a name="top"></a>
		<div class="versionselect">
			<h1>Branch and Inheritance Console</h1>

			Begin by selecting your product, source version material and a target version below.  You will then be presented with additional screens to specify branch and inherit behavior.
			<?php 
        if (isset($_GET['titleName'])) {
            ?>
				<p>
				Requested Operation on Single Topic: <strong><?php 
            echo $_GET['titleName'];
            ?>
</strong>
				</p>
				<?php 
        }
        ?>

			<h2>Choose a Product</h2>

			<?php 
        if (isset($_GET['titleName'])) {
            ?>
				You have selected a product: <?php 
            echo $forceProduct;
            ?>
			<?php 
        } else {
            if (!count($products)) {
                print "<p>No products defined.</p>";
            } else {
                ?>
				<div class="product">
					<select id="docsProductSelect1" name="selectedProduct" onChange="AjaxChangeProduct1();">
					<?php 
                foreach ($products as $idx => $data) {
                    echo '<option value="' . $data['name'] . '" ';
                    if (!strcmp($data['name'], $forceProduct)) {
                        echo 'selected';
                    }
                    echo '>' . $data['label'] . '</option>';
                }
                ?>
					</select>
				</div>

				<script language="javascript">
				function AjaxChangeProduct1_callback( o ) {
					document.getElementById('docsProductSelect1').disabled = true;
					var s = new String( o.responseText );
					document.getElementById('docsProductSelect1').disabled = false;
					window.location.href = s;
				}

				function AjaxChangeProduct1( ) {
					var productIndex = document.getElementById('docsProductSelect1').selectedIndex;
					var product = document.getElementById('docsProductSelect1')[productIndex].value;
					var title = '<?php 
                echo $_SERVER['REQUEST_URI'];
                ?>
'; // TODO fix this title
					var force = true;
					sajax_do_call( 'efPonyDocsAjaxChangeProduct', [product,title,force], AjaxChangeProduct1_callback,true);
				}
				</script>


			<?php 
            }
        }
        ?>

			<h2>Choose a Source Version</h2>
			<?php 
        // Determine if topic was set, if so, we should fetch version from currently selected version.
        if (isset($_GET['titleName'])) {
            $version = PonyDocsProductVersion::GetVersionByName($forceProduct, PonyDocsProductVersion::GetSelectedVersion($forceProduct));
            ?>
					You have selected a topic.  We are using the version you are currently browsing: <?php 
            echo $version->getVersionName();
            ?>
					<?php 
        } else {
            ?>
					<select name="version" id="versionselect_sourceversion">
						<?php 
            foreach ($versions as $version) {
                ?>
							<option value="<?php 
                echo $version->getVersionName();
                ?>
"><?php 
                echo $version->getVersionName() . " - " . $version->getVersionStatus();
                ?>
</option>
							<?php 
            }
            ?>
					</select>
					<?php 
        }
        ?>
			<h2>Choose a Target Version</h2>
			<select name="version" id="versionselect_targetversion">
				<?php 
        foreach ($versions as $version) {
            ?>
					<option value="<?php 
            echo $version->getVersionName();
            ?>
"><?php 
            echo $version->getVersionName() . " - " . $version->getVersionStatus();
            ?>
</option>
					<?php 
        }
        ?>
			</select>
			<p>
			<input type="button" id="versionselect_submit" value="Continue to Manuals" />
			</p>
		</div>

		<div class="manualselect" style="display: none;">
			<?php 
        if (isset($_GET['titleName'])) {
            ?>
				<p>
				Requested Operation on Single Topic: <strong><?php 
            echo $_GET['titleName'];
            ?>
</strong>
				</p>
				<?php 
        }
        ?>
			<p class="summary">
				<strong>Source Version:</strong> <span class="sourceversion"></span> <strong>Target Version:</strong> <span class="targetversion"></span>
			</p>
			<h1>Choose Manuals To Branch/Inherit From</h1>	
			<div id="manualselect_manuals">

			</div>
			<h1>Choose Default Action For Topics</h1>
			<input type="radio" selected="selected" name="manualselect_action" value="ignore" id="manualselect_action_ignore"><label for="manualselect_action_ignore">Ignore - Do Nothing</label><br />
			<input type="radio" name="manualselect_action" value="inherit" id="manualselect_action_inherit"><label for="manualselect_action_inherit">Inherit - Add Target Version to Existing Topic</label><br />
			<input type="radio" name="manualselect_action" value="branch" id="manualselect_action_branch"><label for="manualselect_action_branch">Branch - Create a copy of existing topic with Target Version</label><br />
			<br />
			<input type="button" id="manualselect_submit" value="Continue to Topics" />
		</div>
		<div class="topicactions" style="display: none;">
			<?php 
        if (isset($_GET['titleName'])) {
            ?>
				<p>
				Requested Operation on Single Topic: <strong><?php 
            echo $_GET['titleName'];
            ?>
</strong>
				</p>
				<?php 
        }
        ?>
			<p class="summary">
			<strong>Source Version:</strong> <span class="sourceversion"></span> <strong>Target Version:</strong> <span class="targetversion"></span>
			</p>

			<h1>Specify Topic Actions</h1>
			<div class="container">
			</div>
			<br />
			<br />
			<input type="button" id="topicactions_submit" value="Process Request" />
			<div id="progressconsole"></div>
		</div>
		<div class="completed" style="display: none;">
			<p class="summary">
				<strong>Source Version:</strong> <span class="sourceversion"></span> <strong>Target Version:</strong> <span class="targetversion"></span>
			</p>

			<h2>Process Complete</h2>
			The following is the log of the processed job.  Look it over for any potential issues that may have 
			occurred during the branch/inherit job.
			<div>
				<div class="logconsole" style="font-family: monospace; font-size: 10px;">

				</div>
			</div>
		</div>
		</div>
		<?php 
        $buffer = ob_get_clean();
        $wgOut->addHTML($buffer);
        return true;
    }