/** * Return the colon-separated link with actual version (not base version) for the link to SpecialDocumentLinks */ public static function getDocumentLinksArticle() { global $wgTitle; $partialUrl = ''; $currentVersion = PonyDocsProductVersion::GetSelectedVersion(PonyDocsProduct::GetSelectedProduct(), false); $partialUrl = htmlspecialchars($wgTitle->getPartialURL()); $partialUrlParts = explode(':', $partialUrl); if (isset($partialUrlParts[3]) && isset($currentVersion)) { $partialUrl = str_replace($partialUrlParts[3], $currentVersion, $partialUrl); } return $partialUrl; }
/** * Used to render a hidden text field which will hold what version we were * in. This forced the following edit submission to put us back in the * version we were browsing. */ public static function onShowEditFormFields(&$editpage, &$output) { // Add our form element to the top of the form. $product = PonyDocsProduct::GetSelectedProduct(); $version = PonyDocsProductVersion::GetSelectedVersion($product); $output->mBodytext .= "<input type=\"hidden\" name=\"ponydocsversion\" value=\"" . $version . "\" />"; $output->mBodytext .= "<input type=\"hidden\" name=\"ponydocsproduct\" value=\"" . $product . "\" />"; return true; }
/** * 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; }
/** * This is called when {{#manual:short|long}} is found in an article content. It should produce an output * set of HTML which provides the name (long) as a link to the most recent (based on version tags) TOC * management page for that manual. * * @param Parser $parser * @param string $shortName Short name of the Manual used in links. * @param string $longName Long/display name of Manual. * @param string $categories The categories for the Manual, in a comma-separated list * @return array */ function efManualParserFunction_Render(&$parser, $shortName = '', $longName = '', $categories = '') { global $wgArticlePath; $valid = TRUE; if (!preg_match(PONYDOCS_PRODUCTMANUAL_REGEX, $shortName) || !strlen($shortName) || !strlen($longName)) { return $parser->insertStripItem('', $parser->mStripState); } $manualName = preg_replace('/([^' . PONYDOCS_PRODUCTMANUAL_LEGALCHARS . ']+)/', '', $shortName); // TODO: It's silly to do this twice (the other is in LoadManualsForProduct(). // We should get the manual object from PonyDocsProductManual $static = FALSE; if (strpos($shortName, PONYDOCS_PRODUCT_STATIC_PREFIX) === 0) { $static = TRUE; $manualName = substr($manualName, strlen(PONYDOCS_PRODUCT_STATIC_PREFIX)); } $productName = PonyDocsProduct::GetSelectedProduct(); $version = PonyDocsProductVersion::GetSelectedVersion($productName); // Don't cache Documentation:[product]:Manuals pages because when we switch selected version the content will come from cache $parser->disableCache(); // If static, link to Special:StaticDocImport if ($static) { $output = "<p><a href=\"" . str_replace('$1', "Special:StaticDocImport/{$productName}/{$manualName}", $wgArticlePath) . "\" style=\"font-size: 1.3em;\">{$longName}</a></p>\n" . "<span style=\"padding-left: 20px;\">Click manual to manage static documentation.</span>\n"; // Otherwise, link to TOC for current Version OR add a link to create a new TOC if none exists } else { // TODO: We should call PonyDocsTOC.php or maybe PonyDocsProductManual to see if there's a TOC in this manual // or maybe actually get the manual object and query it $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select(array('categorylinks', 'page'), 'page_title', array('cl_from = page_id', 'page_namespace = "' . NS_PONYDOCS . '"', "cl_to = 'V:{$productName}:{$version}'", 'cl_type = "page"', "cl_sortkey LIKE '" . $dbr->strencode(strtoupper($productName)) . ':' . $dbr->strencode(strtoupper($manualName)) . "TOC%'"), __METHOD__); if (!$res->numRows()) { /** * Link to create new TOC page -- should link to current version TOC and then add message to explain. */ $output = '<p><a href="' . str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':' . $productName . ':' . $manualName . 'TOC' . $version, $wgArticlePath) . '" style="font-size: 1.3em;">' . $longName . "</a></p>\n <span style=\"padding-left: 20px;\">Click manual to create TOC for current version (" . $version . ").</span>\n"; } else { $row = $dbr->fetchObject($res); $output = '<p><a href="' . str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ":{$row->page_title}", $wgArticlePath) . '" style="font-size: 1.3em;">' . $longName . "</a></p>\n"; } } if ($categories != '') { $output .= "<br>Categories: {$categories}"; } return $parser->insertStripItem($output, $parser->mStripState); }
/** * Create a URL path (e.g. Documentation/Foo/latest/Bar/Bas) for a Topic * * @param string $productName * @param string $manualName * @param string $topicName * @param string $versionName - Optional. We'll get the selected version (which defaults to 'latest') if empty * * @return string * * TODO: We should really be passing a topic object into this and not a string */ public static function getTopicURLPath($productName, $manualName, $topicName, $versionName = NULL) { global $wgArticlePath; if (!isset($versionName)) { $versionName = PonyDocsProductVersion::GetSelectedVersion($productName); } $latestVersion = PonyDocsProductVersion::GetLatestReleasedVersion($productName); if ($latestVersion) { if ($versionName == $latestVersion->getVersionName()) { $versionName = 'latest'; } } $base = str_replace('$1', PONYDOCS_DOCUMENTATION_NAMESPACE_NAME, $wgArticlePath); return "{$base}/{$productName}/{$versionName}/{$manualName}/{$topicName}"; }
function execute() { global $action, $IP, $wgArticlePath, $wgContLang, $wgExtraNamespaces, $wgRequest, $wgRevision, $wgTitle, $wgUser; PonyDocsProduct::LoadProducts(); $this->data['selectedProduct'] = PonyDocsProduct::GetSelectedProduct(); PonyDocsProductVersion::LoadVersionsForProduct($this->data['selectedProduct']); PonyDocsProductManual::LoadManualsForProduct($this->data['selectedProduct']); $ponydocs = PonyDocsWiki::getInstance($this->data['selectedProduct']); $this->data['products'] = $ponydocs->getProductsForTemplate(); $this->data['versions'] = $ponydocs->getVersionsForProduct($this->data['selectedProduct']); $this->data['namespaces'] = $wgExtraNamespaces; $this->data['selectedVersion'] = PonyDocsProductVersion::GetSelectedVersion($this->data['selectedProduct']); $this->data['pVersion'] = PonyDocsProductVersion::GetVersionByName($this->data['selectedProduct'], $this->data['selectedVersion']); if (PONYDOCS_DEBUG) { error_log("DEBUG [" . __METHOD__ . "] selected product/version is set to " . $this->data['selectedProduct'] . "/" . $this->data['selectedVersion']); } $this->data['versionurl'] = $this->data['wgScript'] . '?title=' . $this->data['thispage'] . '&action=changeversion'; $this->skin = $this->data['skin']; // TODO remove this, and replace elsewhere (template files mostly) with $this->skin $skin = $this->data['skin']; if ($this->skin->getTitle()) { $this->data['canonicalURI'] = $this->skin->getTitle()->getFullURL(); } $action = $wgRequest->getText('action'); // Suppress warnings to prevent notices about missing indexes in $this->data wfSuppressWarnings(); /** * When displaying a page we output header.php, then a sub-template, and then footer.php. The namespace * which we are in determines the sub-template, which is named 'ns<Namespace>'. It defaults to our * nsDefault.php template. */ $this->data['namespace'] = $wgContLang->getNsText($wgTitle->getNamespace()); $idx = $this->data['namespace'] ? "NS:{$this->data['namespace']}" : 'T:' . $wgTitle->__toString(); if (!isset($this->_methodMappings[$idx])) { $idx = 0; } $inDocumentation = FALSE; if ($this->data['namespace'] == PONYDOCS_DOCUMENTATION_NAMESPACE_NAME || $wgTitle->__toString() == PONYDOCS_DOCUMENTATION_NAMESPACE_NAME || preg_match('/^' . PONYDOCS_DOCUMENTATION_NAMESPACE_NAME . ':/', $wgTitle->__toString())) { $inDocumentation = TRUE; $this->prepareDocumentation(); } $this->data['versions'] = $ponydocs->getVersionsForProduct($this->data['selectedProduct']); $this->html('headelement'); ?> <script type="text/javascript"> function AjaxChangeProduct_callback( o ) { document.getElementById( 'docsProductSelect' ).disabled = true; var s = new String( o.responseText ); document.getElementById( 'docsProductSelect' ).disabled = false; window.location.href = s; } function AjaxChangeProduct() { var productIndex = document.getElementById( 'docsProductSelect' ).selectedIndex; var product = document.getElementById( 'docsProductSelect' )[productIndex].value; var title = '<?php Xml::escapeJsString($this->data['thispage']); ?> '; sajax_do_call( 'efPonyDocsAjaxChangeProduct', [product,title], AjaxChangeProduct_callback ); } function AjaxChangeVersion_callback( o ) { document.getElementById( 'docsVersionSelect' ).disabled = true; var s = new String( o.responseText ); document.getElementById( 'docsVersionSelect' ).disabled = false; window.location.href = s; } function AjaxChangeVersion() { var productIndex = document.getElementById( 'docsProductSelect' ).selectedIndex; var product = document.getElementById( 'docsProductSelect' )[productIndex].value; var versionIndex = document.getElementById( 'docsVersionSelect' ).selectedIndex; var version = document.getElementById( 'docsVersionSelect' )[versionIndex].value; var title = '<?php Xml::escapeJsString($this->data['thispage']); ?> '; sajax_do_call( 'efPonyDocsAjaxChangeVersion', [product,version,title], AjaxChangeVersion_callback ); } function changeManual(){ var url = $( "#docsManualSelect" ).val(); if ( url != "" ){ window.location.href = url; } } </script> <div id="globalWrapper"> <div id="column-content"> <div id="content" <?php $this->html("specialpageattributes"); ?> > <a id="top"></a> <?php if ($this->data['sitenotice']) { ?> <div id="siteNotice"><?php $this->html('sitenotice'); ?> </div> <?php } ?> <?php if (!$inDocumentation) { ?> <h1 id="firstHeading" class="firstHeading"><?php $this->html('title'); ?> </h1> <?php } ?> <div id="bodyContent"> <h3 id="siteSub"><?php $this->msg('tagline'); ?> </h3> <div id="contentSub"<?php $this->html('userlangattributes'); ?> ><?php $this->html('subtitle'); ?> </div> <?php if ($this->data['undelete']) { ?> <div id="contentSub2"><?php $this->html('undelete'); ?> </div> <?php } if ($this->data['newtalk']) { ?> <div class="usermessage"><?php $this->html('newtalk'); ?> </div> <?php } if ($this->data['showjumplinks']) { ?> <div id="jump-to-nav"> <?php $this->msg('jumpto'); ?> <a href="#column-one"><?php $this->msg('jumptonavigation'); ?> </a>, <a href="#searchInput"><?php $this->msg('jumptosearch'); ?> </a> </div> <?php } // Version group message, if any if ($this->data['versionGroupMessage'] !== null) { ?> <div class="affectedVersions <?php echo implode(" ", $this->data['versionclasses']); ?> "> <p class="bannerVersion"> <?php echo $this->data['versionGroupMessage']; ?> </p> </div> <?php } ?> <!-- start content --> <?php $this->html('bodytext'); if ($this->data['catlinks']) { $this->html('catlinks'); } ?> <!-- end content --> <?php if ($this->data['dataAfterContent']) { $this->html('dataAfterContent'); } ?> <div class="visualClear"></div> </div> </div> </div> <div id="column-one"<?php $this->html('userlangattributes'); ?> > <div id="p-cactions" class="portlet"> <h5><?php $this->msg('views'); ?> </h5> <div class="pBody"> <ul><?php foreach ($this->data['content_actions'] as $key => $tab) { echo ' <li id="' . Sanitizer::escapeId("ca-{$key}") . '"'; if ($tab['class']) { echo ' class="' . htmlspecialchars($tab['class']) . '"'; } echo '><a href="' . htmlspecialchars($tab['href']) . '"'; # We don't want to give the watch tab an accesskey if the # page is being edited, because that conflicts with the # accesskey on the watch checkbox. We also don't want to # give the edit tab an accesskey, because that's fairly su- # perfluous and conflicts with an accesskey (Ctrl-E) often # used for editing in Safari. if (in_array($action, array('edit', 'submit')) && in_array($key, array('edit', 'watch', 'unwatch'))) { echo $skin->tooltip("ca-{$key}"); } else { echo Xml::expandAttributes($skin->tooltipAndAccesskeyAttribs("ca-{$key}")); } echo '>' . htmlspecialchars($tab['text']) . '</a></li>'; } ?> </ul> </div> </div> <div class="portlet" id="p-personal"> <h5><?php $this->msg('personaltools'); ?> </h5> <div class="pBody"> <ul<?php $this->html('userlangattributes'); ?> > <?php foreach ($this->data['personal_urls'] as $key => $item) { ?> <li id="<?php echo Sanitizer::escapeId("pt-{$key}"); ?> " <?php if ($item['active']) { ?> class="active" <?php } ?> > <a href="<?php echo htmlspecialchars($item['href']); ?> " <?php echo Xml::expandAttributes($skin->tooltipAndAccesskeyAttribs('pt-' . $key)); if (!empty($item['class'])) { ?> class="<?php echo htmlspecialchars($item['class']); ?> " <?php } ?> > <?php echo htmlspecialchars($item['text']); ?> </a> </li> <?php } ?> </ul> </div> </div> <div class="portlet" id="p-logo"> <a style="background-image: url(<?php $this->text('logopath'); ?> );" href="<?php echo htmlspecialchars($this->data['nav_urls']['mainpage']['href']); ?> " <?php echo Xml::expandAttributes($skin->tooltipAndAccesskeyAttribs('p-logo')); ?> ></a><br /> </div> <script type="<?php $this->text('jsmimetype'); ?> "> if ( window.isMSIE55 ) { fixalpha(); } </script> <div id="p-documentation" class="portlet"> <h5>documentation</h5> <div id="documentationBody" class="pBody"> <?php if (!count($this->data['products'])) { ?> <p>No products defined.</p> <?php } else { ?> <div class="product"> <label for='docsProductSelect' class="navlabels">Product: </label><br /> <select id="docsProductSelect" name="selectedProduct" onChange="AjaxChangeProduct();"> <?php $this->hierarchicalProductSelect(); ?> </select> </div> <?php $versions = PonyDocsProductVersion::GetVersions($this->data['selectedProduct'], TRUE); if (!count($versions)) { ?> <p>No Product Versions Defined.</p> <?php } else { $manuals = PonyDocsProductManual::GetDefinedManuals($this->data['selectedProduct'], TRUE); if (!count($manuals)) { ?> <p>The product manual you requested is not defined, you are not logged in, or you do not have the correct permissions to view this content.</p> <?php } else { ?> <p> <div class="productVersion"> <?php // do quick manip $found = FALSE; for ($i = count($this->data['versions']) - 1; $i >= 0; $i--) { $this->data['versions'][$i]['label'] = $this->data['versions'][$i]['name']; if (!$found && $this->data['versions'][$i]['status'] == "released") { $this->data['versions'][$i]['label'] .= " (latest release)"; $found = TRUE; } } ?> <label for='docsVersionSelect' class="navlabels">Product version: </label><br /> <select id="docsVersionSelect" name="selectedVersion" onChange="AjaxChangeVersion();"> <?php foreach ($this->data['versions'] as $idx => $data) { echo '<option value="' . $data['name'] . '" '; if (!strcmp($data['name'], $this->data['selectedVersion'])) { echo 'selected'; } echo '>' . $data['label'] . '</option>'; } ?> </select> </div> <div class="productManual"> <label for="docsManualSelect" class="navlabels">Select manual: </label><br /> <select id="docsManualSelect" name="selectedManual" onChange="changeManual();"> <?php $navData = PonyDocsExtension::fetchNavDataForVersion($this->data['selectedProduct'], $this->data['selectedVersion']); print "<option value=''>Pick One...</option>"; //loop through nav array and look for current URL foreach ($navData as $manual) { $selected = ""; if (!strcmp($this->data['manualname'], $manual['longName'])) { $selected = " selected "; } print "<option value='" . $manual['firstUrl'] . "' {$selected}>"; print $manual['longName']; print "<!-- categories: {$manual['categories']} -->"; print '</option>'; } ?> </select> </div> </p> <p> <?php if (sizeof($this->data['manualtoc'])) { ?> <p> <a href="<?php echo str_replace('$1', '', $wgArticlePath); ?> index.php?title=<?php echo $wgTitle->__toString(); ?> &action=pdfbook">Pdf Version</a> </p> <?php $inUL = FALSE; $listid = ""; foreach ($this->data['manualtoc'] as $idx => $data) { if (0 == $data['level']) { if ($inUL) { echo '</ul></div>'; $inUL = FALSE; } $listid = "list" . $idx; echo '<div class="wikiSidebarBox collapsible">'; echo '<h3>' . $data['text'] . '</h3>'; echo '<ul>'; $inUL = TRUE; } elseif (1 == $data['level']) { if ($data['current']) { echo '<li class="expanded">' . $data['text'] . '</li>'; } else { echo '<li><a href="' . wfUrlencode($data['link']) . '">' . $data['text'] . '</a></li>'; } } else { if ($data['current']) { echo '<li class="expanded" style="margin-left: 13px;">' . $data['text'] . '</li>'; } else { echo '<li style="margin-left: 13px;"><a href="' . wfUrlencode($data['link']) . '">' . $data['text'] . '</a></li>'; } } } if ($inUL) { echo '</ul></div>'; } } ?> </p> <?php } } } ?> </div> </div> <?php $sidebar = $this->data['sidebar']; if (!isset($sidebar['SEARCH'])) { $sidebar['SEARCH'] = TRUE; } if (!isset($sidebar['TOOLBOX'])) { $sidebar['TOOLBOX'] = TRUE; } if (!isset($sidebar['LANGUAGES'])) { $sidebar['LANGUAGES'] = TRUE; } foreach ($sidebar as $boxName => $cont) { if ($boxName == 'SEARCH') { $this->searchBox(); } elseif ($boxName == 'TOOLBOX') { $this->toolbox(); } elseif ($boxName == 'LANGUAGES') { $this->languageBox(); } else { $this->customBox($boxName, $cont); } } ?> </div><!-- end of the left (by default at least) column --> <div class="visualClear"></div> <div id="footer"<?php $this->html('userlangattributes'); ?> > <?php if ($this->data['poweredbyico']) { ?> <div id="f-poweredbyico"><?php $this->html('poweredbyico'); ?> </div> <?php } if ($this->data['copyrightico']) { ?> <div id="f-copyrightico"><?php $this->html('copyrightico'); ?> </div> <?php } // Generate additional footer links $footerlinks = array('lastmod', 'viewcount', 'numberofwatchingusers', 'credits', 'copyright', 'privacy', 'about', 'disclaimer', 'tagline'); $validFooterLinks = array(); foreach ($footerlinks as $aLink) { if (isset($this->data[$aLink]) && $this->data[$aLink]) { $validFooterLinks[] = $aLink; } } if (count($validFooterLinks) > 0) { ?> <ul id="f-list"> <?php foreach ($validFooterLinks as $aLink) { if (isset($this->data[$aLink]) && $this->data[$aLink]) { ?> <li id="<?php echo $aLink; ?> "><?php $this->html($aLink); ?> </li> <?php } } ?> </ul> <?php } ?> </div> </div> <?php $this->html('bottomscripts'); /* JS call to runBodyOnloadHook */ ?> <?php $this->html('reporttime'); ?> <?php if ($this->data['debug']) { ?> <!-- Debug output: <?php $this->text('debug'); ?> --> <?php } ?> </body> </html> <?php wfRestoreWarnings(); }
/** * 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; }
/** * 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; }