/**
  * Fetches the requested pages markup, cleans it and returns a DOMDocument.
  * @param array $aParams Needs the 'article-id' or 'title' key to be set and valid.
  * @return array 
  */
 public static function getPage($aParams)
 {
     wfRunHooks('BSUEModulePDFbeforeGetPage', array(&$aParams));
     $oBookmarksDOM = new DOMDocument();
     $oBookmarksDOM->loadXML('<bookmarks></bookmarks>');
     $oTitle = null;
     if (isset($aParams['article-id'])) {
         $oTitle = Title::newFromID($aParams['article-id']);
     }
     if ($oTitle == null) {
         //HINT: This is probably the wrong place for urldecode(); Should be
         //done by caller. I.e. BookExportModulePDF
         $oTitle = Title::newFromText(urldecode($aParams['title']));
     }
     $oPCP = new BsPageContentProvider();
     $oPageDOM = $oPCP->getDOMDocumentContentFor($oTitle, $aParams + array('follow-redirects' => true));
     // TODO RBV (06.12.11 17:09): Follow Redirect... setting or default?
     //Collect Metadata
     $aData = self::collectData($oTitle, $oPageDOM, $aParams);
     //Cleanup DOM
     self::cleanUpDOM($oTitle, $oPageDOM, $aParams);
     $oBookmarkNode = BsUniversalExportHelper::getBookmarkElementForPageDOM($oPageDOM);
     //HINT: http://www.mm-newmedia.de/blog/2010/05/wrong-document-error-wtf/
     $oBookmarksDOM->documentElement->appendChild($oBookmarksDOM->importNode($oBookmarkNode, true));
     $oDOMXPath = new DOMXPath($oPageDOM);
     $oFirstHeading = $oDOMXPath->query("//*[contains(@class, 'firstHeading')]")->item(0);
     $oBodyContent = $oDOMXPath->query("//*[contains(@class, 'bodyContent')]")->item(0);
     // TODO RBV (01.02.12 11:28): What if no TOC?
     $oTOCULElement = $oDOMXPath->query("//*[contains(@class, 'toc')]//ul")->item(0);
     if (isset($aParams['display-title'])) {
         $oBookmarkNode->setAttribute('name', $aParams['display-title']);
         $oFirstHeading->nodeValue = $aParams['display-title'];
         $aData['meta']['title'] = $aParams['display-title'];
     }
     $aPage = array('resources' => $aData['resources'], 'dom' => $oPageDOM, 'firstheading-element' => $oFirstHeading, 'bodycontent-element' => $oBodyContent, 'toc-ul-element' => $oTOCULElement, 'bookmarks-dom' => $oBookmarksDOM, 'bookmark-element' => $oBookmarkNode, 'meta' => $aData['meta']);
     wfRunHooks('BSUEModulePDFgetPage', array($oTitle, &$aPage, &$aParams, $oDOMXPath));
     return $aPage;
 }
 /**
  * Getter for $aNavigationSites array
  * @param boolean $bForceReload
  * @return array
  */
 public static function getNavigationSites($bForceReload = false)
 {
     if (!$bForceReload && !is_null(self::$aNavigationSites)) {
         return self::$aNavigationSites;
     }
     self::$aNavigationSites = array();
     $oTopBarMenuTitle = Title::makeTitle(NS_MEDIAWIKI, 'TopBarMenu');
     if (is_null($oTopBarMenuTitle) || !$oTopBarMenuTitle->exists()) {
         return self::$aNavigationSites;
     }
     $sContent = BsPageContentProvider::getInstance()->getContentFromTitle($oTopBarMenuTitle);
     $aLines = explode("\n", trim($sContent));
     $iMaxMainEntries = BsConfig::get('MW::TopMenuBarCustomizer::NumberOfMainEntries');
     $iMaxSubEntries = BsConfig::get('MW::TopMenuBarCustomizer::NumberOfSubEntries');
     $iAllowedLevels = BsConfig::get('MW::TopMenuBarCustomizer::NuberOfLevels');
     self::$aNavigationSites = self::parseArticleContentLines($aLines, $iAllowedLevels, $iMaxMainEntries, $iMaxSubEntries);
     return self::$aNavigationSites;
 }
 /**
  * Renders the pagetemplates form which is displayed when creating a new article
  * @param bool $bReturnHTML If set, the form is returned as HTML, otherwise as wiki code.
  * @return string The rendered output
  */
 protected function renderPageTemplates()
 {
     global $wgDBtype;
     $oTitle = $this->getTitle();
     // if we are not on a wiki page, return. This is important when calling import scripts that try to create nonexistent pages, e.g. importImages
     if (!is_object($oTitle)) {
         return true;
     }
     $aRes = array();
     $aOutNs = array();
     $dbr = wfGetDB(DB_SLAVE);
     $aConds = array();
     if (BsConfig::get('MW::PageTemplates::HideIfNotInTargetNs')) {
         if ($wgDBtype == 'postgres') {
             $aConds[] = "pt_target_namespace IN ('" . $oTitle->getNamespace() . "', '-99')";
         } else {
             $aConds[] = 'pt_target_namespace IN (' . $oTitle->getNamespace() . ', -99)';
         }
     }
     if ($wgDBtype == 'postgres') {
         $aFields = array("pt_template_title, pt_template_namespace, pt_label, pt_desc, pt_target_namespace");
     } else {
         $aFields = array('pt_template_title', 'pt_template_namespace', 'pt_label', 'pt_desc', 'pt_target_namespace');
     }
     $res = $dbr->select(array('bs_pagetemplate'), $aFields, $aConds, __METHOD__, array('ORDER BY' => 'pt_label'));
     // There is always one template for empty page it is added some lines beneath that
     $iCount = $dbr->numRows($res) + 1;
     $sOut = wfMessage('bs-pagetemplates-choose-template', $iCount)->parse();
     $sOutAll = '';
     $oTargetNsTitle = null;
     $sOut .= '<br /><br /><ul><li>';
     $sOut .= BsLinkProvider::makeLink($oTitle, wfMessage('bs-pagetemplates-empty-page')->plain(), array(), array('preload' => ''));
     $sOut .= '<br />' . wfMessage('bs-pagetemplates-empty-page-desc')->plain();
     $sOut .= '</li></ul>';
     $oSortingTitle = Title::makeTitle(NS_MEDIAWIKI, 'PageTemplatesSorting');
     $vOrder = BsPageContentProvider::getInstance()->getContentFromTitle($oSortingTitle);
     $vOrder = explode('*', $vOrder);
     $vOrder = array_map('trim', $vOrder);
     if ($res && $dbr->numRows($res) > 0) {
         while ($row = $dbr->fetchObject($res)) {
             $aRes[] = $row;
         }
     }
     $dbr->freeResult($res);
     foreach ($aRes as $row) {
         $oNsTitle = Title::makeTitle($row->pt_template_namespace, $row->pt_template_title);
         // TODO MRG (06.09.11 12:53): -99 is "all namespaces". Pls use a more telling constant
         if (BsConfig::get('MW::PageTemplates::ForceNamespace') && $row->pt_target_namespace != "-99" || $row->pt_target_namespace == $oTitle->getNamespace() || BsConfig::get('MW::PageTemplates::HideIfNotInTargetNs') == false) {
             $sNamespaceName = BsNamespaceHelper::getNamespaceName($row->pt_target_namespace);
             if (!isset($aOutNs[$sNamespaceName])) {
                 $aOutNs[$sNamespaceName] = array();
             }
             if (BsConfig::get('MW::PageTemplates::ForceNamespace')) {
                 $oTargetNsTitle = Title::makeTitle($row->pt_target_namespace, $oTitle->getText());
             } else {
                 $oTargetNsTitle = $oTitle;
             }
             $sLink = BsLinkProvider::makeLink($oTargetNsTitle, $row->pt_label, array(), array('preload' => $oNsTitle->getPrefixedText()));
             $sLink = '<li>' . $sLink;
             if ($row->pt_desc) {
                 $sLink .= '<br/>' . $row->pt_desc;
             }
             $sLink .= '</li>';
             $aOutNs[$sNamespaceName][] = array('link' => $sLink, 'id' => $row->pt_target_namespace);
         } elseif ($row->pt_target_namespace == "-99") {
             $sLink = BsLinkProvider::makeLink($oTitle, $row->pt_label, array(), array('preload' => $oNsTitle->getPrefixedText()));
             $sOutAll .= '<li>' . $sLink;
             if ($row->pt_desc) {
                 $sOutAll .= '<br />' . $row->pt_desc;
             }
             $sOutAll .= '</li>';
         }
     }
     if (!empty($vOrder)) {
         $aTmp = array();
         foreach ($vOrder as $key => $value) {
             if (empty($value)) {
                 continue;
             }
             if (array_key_exists($value, $aOutNs)) {
                 $aTmp[$value] = $aOutNs[$value];
             }
         }
         $aOutNs = $aTmp + array_diff_key($aOutNs, $aTmp);
     }
     $aLeftCol = array();
     $aRightCol = array();
     foreach ($aOutNs as $sNs => $aTmpOut) {
         foreach ($aTmpOut as $key => $aAttribs) {
             $sNamespaceName = BsNamespaceHelper::getNamespaceName($aAttribs['id']);
             if ($aAttribs['id'] == $oTitle->getNamespace() || $aAttribs['id'] == -99) {
                 $aLeftCol[$sNamespaceName][] = '<ul>' . $aAttribs['link'] . '</ul>';
             } else {
                 $aRightCol[$sNamespaceName][] = '<ul>' . $aAttribs['link'] . '</ul>';
             }
         }
     }
     if ($sOutAll !== '') {
         $sSectionGeneral = wfMessage('bs-pagetemplates-general-section')->plain();
         $aLeftCol[$sSectionGeneral][] = '<ul>' . $sOutAll . '</ul>';
     }
     $sOut .= '<br />';
     if (!empty($aLeftCol) || !empty($aRightCol) && BsConfig::get('MW::PageTemplates::HideIfNotInTargetNs') == false) {
         $sOut .= '<table><tr>';
         if (!empty($aLeftCol)) {
             $sOut .= '<td style="vertical-align:top;">';
             foreach ($aLeftCol as $sNamespace => $aHtml) {
                 if ($sNamespace == wfMessage('bs-ns_all')->plain()) {
                     $sNamespace = wfMessage('bs-pagetemplates-general-section')->plain();
                 }
                 $sOut .= '<br />';
                 $sOut .= '<h3>' . $sNamespace . '</h3>';
                 $sOut .= implode('', $aHtml);
             }
             $sOut .= '</td>';
         }
         if (BsConfig::get('MW::PageTemplates::HideIfNotInTargetNs') == false) {
             if (!empty($aRightCol)) {
                 $sOut .= '<td style="vertical-align:top;">';
                 foreach ($aRightCol as $sNamespace => $aHtml) {
                     $sOut .= '<br />';
                     $sOut .= '<h3>' . $sNamespace . '</h3>';
                     $sOut .= implode('', $aHtml);
                 }
                 $sOut .= '</td>';
             }
         }
         $sOut .= '</tr></table>';
     }
     return $sOut;
 }
 /**
  * Reads in a template file to a DOMDocuments and collects additional
  * information.
  * @param array $aParams Has to contain a valid 'template' entry.
  * @return array with the DOMDocument and some references.
  */
 public static function getTemplate($aParams)
 {
     $aParams = array_merge(array('language' => 'en', 'meta' => array()), $aParams);
     $sPath = realpath($aParams['path']);
     $sTemplatePath = $sPath . '/' . $aParams['template'];
     if (!file_exists($sTemplatePath)) {
         throw new BsException('Requested template not found! Path:' . $sTemplatePath);
     }
     $sTemplateDescriptor = $sTemplatePath . '/template.php';
     $sTemplateMarkup = $sTemplatePath . '/template.html';
     $aTemplate = (include $sTemplateDescriptor);
     $oTemplateDOM = new DOMDocument();
     $oTemplateDOM->formatOutput = true;
     $oTemplateDOM->load($sTemplateMarkup);
     $oHeadElement = $oTemplateDOM->getElementsByTagName('head')->item(0);
     $oBodyElement = $oTemplateDOM->getElementsByTagName('body')->item(0);
     $oTitleElement = $oTemplateDOM->getElementsByTagName('title')->item(0);
     $aResources = array();
     foreach ($aTemplate['resources'] as $sType => $aFiles) {
         foreach ($aFiles as $sFile) {
             $aResources[$sType][basename($sFile)] = $sTemplatePath . '/' . $sFile;
         }
     }
     //Substitue MSG elements
     $oMsgTags = $oTemplateDOM->getElementsByTagName('msg');
     //Get the message data; If not available use "en" as fallback
     $aMsgs = isset($aTemplate['messages'][$aParams['language']]) ? $aTemplate['messages'][$aParams['language']] : $aTemplate['messages']['en'];
     //Be careful with "replaceChild" within "foreach"!
     //HINT: http://stackoverflow.com/questions/7035202/why-does-getelementsbytagname-only-grab-every-other-element-here
     $i = $oMsgTags->length - 1;
     while ($i > -1) {
         $oMsgTag = $oMsgTags->item($i);
         $sKey = $oMsgTag->getAttribute('key');
         $sReplacement = '';
         if (isset($aMsgs[$sKey])) {
             $sReplacement = $aMsgs[$sKey];
         }
         $oReplacmentElement = $oTemplateDOM->createTextNode($sReplacement);
         $oMsgTag->parentNode->replaceChild($oReplacmentElement, $oMsgTag);
         $i--;
     }
     //Substitute META elements
     $oMetaTags = $oTemplateDOM->getElementsByTagName('meta');
     $i = $oMetaTags->length - 1;
     while ($i > -1) {
         $oMetaTag = $oMetaTags->item($i);
         $sKey = $oMetaTag->getAttribute('key');
         if (isset($aParams['meta'][$sKey])) {
             $oReplacmentElement = $oTemplateDOM->createTextNode($aParams['meta'][$sKey]);
             $oMetaTag->parentNode->replaceChild($oReplacmentElement, $oMetaTag);
         } else {
             $oMetaTag->parentNode->removeChild($oMetaTag);
         }
         $i--;
     }
     //Add meta tags to head
     foreach ($aParams['meta'] as $sKey => $sValue) {
         $oMetaTag = $oTemplateDOM->createElement('meta');
         $oMetaTag->setAttribute('name', $sKey);
         $oMetaTag->setAttribute('content', $sValue);
         $oHeadElement->appendChild($oMetaTag);
     }
     //Find CONTENT elements
     $oContentTags = $oTemplateDOM->getElementsByTagName('content');
     $aContentTagRefs = array();
     foreach ($oContentTags as $oContentTag) {
         $sKey = $oContentTag->getAttribute('key');
         $aContentTagRefs[$sKey] = $oContentTag;
     }
     //Create a bookmarks tag within the head element;
     $oBookmarksNode = $oTemplateDOM->createElement('bookmarks');
     $oHeadElement->appendChild($oBookmarksNode);
     //Get additional stylesheets from wiki context
     $aStyleBlocks = array();
     global $wgUseSiteCss;
     if ($wgUseSiteCss) {
         $oTitle = Title::makeTitle(NS_MEDIAWIKI, 'Common.css');
         $aStyleBlocks['MediaWiki:Common.css'] = BsPageContentProvider::getInstance()->getContentFromTitle($oTitle);
     }
     wfRunHooks('BSUEModulePDFBeforeAddingStyleBlocks', array(&$aTemplate, &$aStyleBlocks));
     foreach ($aStyleBlocks as $sBlockName => $sCss) {
         $sCss = "\n/* " . $sBlockName . " */\n" . $sCss . "\n";
         $oStyleElement = $oTemplateDOM->createElement('style');
         $oStyleElement->appendChild($oTemplateDOM->createCDATASection($sCss));
         $oStyleElement->setAttribute('type', 'text/css');
         $oStyleElement->setAttribute('rel', 'stylesheet');
         $oHeadElement->appendChild($oStyleElement);
     }
     return array('resources' => $aResources, 'dom' => $oTemplateDOM, 'content-elements' => $aContentTagRefs, 'bookmarks-element' => $oBookmarksNode, 'head-element' => $oHeadElement, 'body-element' => $oBodyElement, 'title-element' => $oTitleElement);
 }
 public function buildRssNsBlog()
 {
     global $wgSitename, $wgContLang;
     $oRequest = $this->getRequest();
     $sTitle = $oRequest->getVal('p', '');
     $iNSid = $oRequest->getInt('ns', 0);
     $aNamespaces = $wgContLang->getNamespaces();
     if ($iNSid != 0) {
         $sPageName = $aNamespaces[$iNSid] . ':' . $sTitle;
     } else {
         $sPageName = $sTitle;
     }
     /*$dbr = wfGetDB( DB_SLAVE );
     		$res = $dbr->select(
     			array( 'page', 'recentchanges' ),
     			'*',
     			array(
     				'page_title'     => $sTitle,
     				'page_namespace' => $iNSid,
     				'rc_timestamp > '. $dbr->timestamp( time() - intval( 7 * 86400 ) )
     			),
     			__METHOD__,
     			array( 'ORDER BY' => 'rc_timestamp DESC' ),
     			array(
     				'page'=> array( 'LEFT JOIN', 'rc_cur_id = page_id' )
     			)
     		);*/
     $oChannel = RSSCreator::createChannel(RSSCreator::xmlEncode($wgSitename . ' - ' . $sPageName), 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'], wfMessage('bs-rssstandards-description_page')->plain());
     $oTitle = Title::makeTitle($iNSid, 'Blog');
     $aSubpages = $oTitle->getSubpages();
     foreach ($aSubpages as $oSubpage) {
         //			$oPageCP = new BsPageContentProvider();
         if ($oSubpage instanceof Title) {
         }
         $entry = RSSItemCreator::createItem($oSubpage->getText(), $oSubpage->getFullURL(), BsPageContentProvider::getInstance()->getContentFromTitle($oSubpage));
         $entry->setPubDate(wfTimestamp(TS_UNIX, $oSubpage->getTouched()));
         $oChannel->addItem($entry);
     }
     return $oChannel->buildOutput();
 }
 /**
  * Renders the Progress tag. Called by parser function.
  * @param string $input Inner HTML of InfoBox tag. Not used.
  * @param array $args List of tag attributes.
  * @param Parser $parser MediaWiki parser object
  * @return string HTML output that is to be displayed.
  */
 public function onTagProgress($input, $args, $parser)
 {
     $iBaseCount = BsCore::sanitizeArrayEntry($args, 'basecount', 100, BsPARAMTYPE::INT);
     $sBaseItem = BsCore::sanitizeArrayEntry($args, 'baseitem', '', BsPARAMTYPE::STRING);
     $sFraction = BsCore::sanitizeArrayEntry($args, 'progressitem', 'OK', BsPARAMTYPE::STRING);
     $iWidth = BsCore::sanitizeArrayEntry($args, 'width', 100, BsPARAMTYPE::INT);
     // no Article when in cli mode
     if (!is_object($this->getTitle())) {
         return '';
     }
     $sText = BsPageContentProvider::getInstance()->getContentFromTitle($this->getTitle());
     // substract 1 because one item is in the progressitem attribute
     $iFraction = substr_count($sText, $sFraction) - 1;
     if ($sBaseItem) {
         $iBase = substr_count($sText, $sBaseItem) - 1;
     } else {
         $iBase = $iBaseCount;
     }
     $fPercent = $iFraction / $iBase;
     $iWidthGreen = floor($iWidth * $fPercent);
     $iWidthRemain = $iWidth - $iWidthGreen;
     $sPercent = sprintf("%0.1f", $fPercent * 100);
     $sOut = '<div style="background-color:green;border:2px solid #DDDDDD;width:' . $iWidthGreen . 'px;height:25px;float:left;color:#DDDDDD;text-align:center;border-right:0px;text-weight:bold;vertical-align:middle;">' . $sPercent . '%</div>';
     $sOut .= '<div style="border:2px solid #DDDDDD;border-left:0px;width:' . $iWidthRemain . 'px;height:25px;float:left;"></div>';
     return $sOut;
 }
 public static function addCategoriesToArticle($iArticleId)
 {
     if (BsCore::checkAccessAdmission('read') === false) {
         return FormatJson::encode(array('success' => false));
     }
     if (wfReadOnly()) {
         global $wgReadOnly;
         return FormatJson::encode(array('success' => false, 'msg' => wfMessage('bs-readonly', $wgReadOnly)->plain()));
     }
     $sTags = RequestContext::getMain()->getRequest()->getVal('categories');
     $aTags = empty($sTags) ? array() : explode(',', $sTags);
     $oTitle = Title::newFromID($iArticleId);
     if (is_null($oTitle) || !$oTitle->exists()) {
         $oRequest = RequestContext::getMain()->getRequest();
         $sPageName = $oRequest->getVal("page_name", "");
         $oTitle = Title::newFromText($sPageName);
     }
     $sCat = BsNamespaceHelper::getNamespaceName(NS_CATEGORY);
     $sText = BsPageContentProvider::getInstance()->getContentFromTitle($oTitle, Revision::RAW);
     // Remove all before adding
     $sPattern = '#^\\[\\[' . $sCat . ':.*?\\]\\]#im';
     $sText = preg_replace($sPattern, '', $sText);
     if (!empty($aTags)) {
         foreach ($aTags as $sTag) {
             $sText .= "\n[[" . $sCat . ":{$sTag}]]";
         }
     }
     $oWikiPage = new WikiPage($oTitle);
     $oUser = RequestContext::getMain()->getUser();
     $oContent = new WikitextContent($sText);
     $oStatus = $oWikiPage->doEditContent($oContent, "", 0, false, $oUser);
     if (!$oStatus->isGood()) {
         return FormatJson::encode(array('success' => false, 'msg' => $oStatus->getMessage()));
     }
     return FormatJson::encode(array('success' => true));
 }
 /**
  * Actually renders the SmartList list view.
  * @param int $aArgs['count'] Maximum number of items in list.
  * @param string $aArgs['namespaces'] Comma separated list of namespaces that should be considered.
  * @param string $aArgs['categories'] Comma separated list of categories that should be considered.
  * @param string $aArgs['period'] Period of time that should be considered (-|day|week|month)
  * @param string $aArgs['mode'] Defines the basic criteria of pages that should be considered. Default: recentchanges. Other Extensions can hook into SmartList and define their own mode.
  * @param bool $aArgs['showMinorChanges'] Should minor changes be considered
  * @param bool $aArgs['showOnlyNewArtiles'] Should edits be considered or only page creations
  * @param int $aArgs['trim'] Maximum number of title characters.
  * @param bool $aArgs['showtext'] Also display article text.
  * @param int $aArgs['trimtext'] Maximum number of text characters.
  * @param string $aArgs['order'] Sort order for list. (time|title)
  * @param bool $aArgs['showns'] Show namespace befor title.
  * @return string HTML output that is to be displayed.
  */
 private function getCustomList($aArgs)
 {
     /*
      * Contains the items that need to be displayed
      * @var List of objects with three properties: title, namespace and timestamp
      */
     $aObjectList = array();
     $oErrorListView = new ViewTagErrorList($this);
     $oValidationResult = BsValidator::isValid('ArgCount', $aArgs['count'], array('fullResponse' => true));
     if ($oValidationResult->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError($oValidationResult->getI18N()));
     }
     /*
      * Validation of namespaces and categories
      */
     $oValidationResult = BsValidator::isValid('SetItem', $aArgs['categoryMode'], array('fullResponse' => true, 'setname' => 'catmode', 'set' => array('AND', 'OR')));
     if ($oValidationResult->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError($oValidationResult->getI18N()));
     }
     $oValidationResult = BsValidator::isValid('SetItem', $aArgs['period'], array('fullResponse' => true, 'setname' => 'period', 'set' => array('-', 'day', 'week', 'month')));
     if ($oValidationResult->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError($oValidationResult->getI18N()));
     }
     $oValidationResult = BsValidator::isValid('PositiveInteger', $aArgs['trim'], array('fullResponse' => true));
     if ($oValidationResult->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError($oValidationResult->getI18N()));
     }
     $oValidationResult = BsValidator::isValid('PositiveInteger', $aArgs['trimtext'], array('fullResponse' => true));
     if ($oValidationResult->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError($oValidationResult->getI18N()));
     }
     $oValidationResult = BsValidator::isValid('SetItem', $aArgs['sort'], array('fullResponse' => true, 'setname' => 'sort', 'set' => array('time', 'title')));
     if ($oValidationResult->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError($oValidationResult->getI18N()));
     }
     $oValidationResult = BsValidator::isValid('SetItem', $aArgs['order'], array('fullResponse' => true, 'setname' => 'order', 'set' => array('ASC', 'DESC')));
     if ($oValidationResult->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError($oValidationResult->getI18N()));
     }
     if ($aArgs['mode'] == 'recentchanges') {
         $dbr = wfGetDB(DB_SLAVE);
         $aConditions = array();
         switch ($aArgs['period']) {
             case 'month':
                 $sMinTimestamp = $dbr->timestamp(time() - 30 * 24 * 60 * 60);
                 break;
             case 'week':
                 $sMinTimestamp = $dbr->timestamp(time() - 7 * 24 * 60 * 60);
                 break;
             case 'day':
                 $sMinTimestamp = $dbr->timestamp(time() - 24 * 60 * 60);
                 break;
             default:
                 break;
         }
         try {
             $aNamespaceIds = BsNamespaceHelper::getNamespaceIdsFromAmbiguousCSVString($aArgs['namespaces']);
             $aConditions[] = 'rc_namespace IN (' . implode(',', $aNamespaceIds) . ')';
         } catch (BsInvalidNamespaceException $ex) {
             $sInvalidNamespaces = implode(', ', $ex->getListOfInvalidNamespaces());
             $oErrorListView->addItem(new ViewTagError(wfMessage('bs-smartlist-invalid-namespaces')->numParams(count($ex->getListOfInvalidNamespaces()))->params($sInvalidNamespaces)->text()));
         }
         $this->makeCategoriesFilterCondition($aConditions, $aArgs, 'rc_cur_id');
         switch ($aArgs['sort']) {
             case 'title':
                 $sOrderSQL = 'rc_title';
                 break;
             default:
                 // ORDER BY MAX() - this one was tricky. It makes sure, only the changes with the maximum date are selected.
                 $sOrderSQL = 'MAX(rc_timestamp)';
                 break;
         }
         switch ($aArgs['order']) {
             case 'ASC':
                 $sOrderSQL .= ' ASC';
                 break;
             default:
                 $sOrderSQL .= ' DESC';
                 break;
         }
         if (!$aArgs['showMinorChanges']) {
             $aConditions[] = 'rc_minor = 0';
         }
         if ($aArgs['showOnlyNewArticles']) {
             $sOrderSQL = 'MIN(rc_timestamp) DESC';
             $aConditions[] = 'rc_new = 1';
         }
         if (!empty($aArgs['period']) && $aArgs['period'] !== '-') {
             $aConditions[] = "rc_timestamp > '" . $sMinTimestamp . "'";
         }
         $aConditions[] = 'rc_title = page_title AND rc_namespace = page_namespace';
         //prevent display of deleted articles
         $aConditions[] = 'NOT (rc_type = 3)';
         //prevent moves and deletes from being displayed
         $aFields = array('rc_title as title', 'rc_namespace as namespace');
         if (isset($aArgs['meta']) && $aArgs['meta'] == true) {
             $aFields[] = 'MAX(rc_timestamp) as time, rc_user_text as username';
         }
         if (BsConfig::get('MW::SmartList::Comments')) {
             $aFields[] = 'MAX(rc_comment) as comment';
         }
         $res = $dbr->select(array('recentchanges', 'page'), $aFields, $aConditions, __METHOD__, array('GROUP BY' => 'rc_title, rc_namespace', 'ORDER BY' => $sOrderSQL));
         $iCount = 0;
         foreach ($res as $row) {
             if ($iCount == $aArgs['count']) {
                 break;
             }
             $oTitle = Title::makeTitleSafe($row->namespace, $row->title);
             if (!$oTitle || !$oTitle->quickUserCan('read')) {
                 continue;
             }
             $aObjectList[] = $row;
             $iCount++;
         }
         $dbr->freeResult($res);
     } elseif ($aArgs['mode'] == 'whatlinkshere') {
         //PW(25.02.2015) TODO:
         //There could be filters - see Special:Whatlinkshere
         $oTargetTitle = empty($aArgs['target']) ? $this->getContext()->getTitle() : Title::newFromText($aArgs['target']);
         if (is_null($oTargetTitle)) {
             $oErrorListView->addItem(new ViewTagError(wfMessage('bs-smartlist-invalid-target')->text()));
             return $oErrorListView->execute();
         }
         $dbr = wfGetDB(DB_SLAVE);
         $aTables = array('pagelinks', 'page');
         $aFields = array('title' => 'page_title', 'namespace' => 'page_namespace');
         $aConditions = array("page_id = pl_from", "pl_namespace = {$oTargetTitle->getNamespace()}", "pl_from NOT IN ({$oTargetTitle->getArticleID()})", "pl_title = '{$oTargetTitle->getDBkey()}'");
         $aOptions = array();
         try {
             $aNamespaceIds = BsNamespaceHelper::getNamespaceIdsFromAmbiguousCSVString($aArgs['namespaces']);
             $aConditions['page_namespace'] = $aNamespaceIds;
         } catch (BsInvalidNamespaceException $ex) {
             $sInvalidNamespaces = implode(', ', $ex->getListOfInvalidNamespaces());
             $oErrorListView->addItem(new ViewTagError(wfMessage('bs-smartlist-invalid-namespaces')->numParams(count($ex->getListOfInvalidNamespaces()))->params($sInvalidNamespaces)->text()));
             return $oErrorListView->execute();
         }
         $this->makeCategoriesFilterCondition($aConditions, $aArgs, 'page_id');
         //Default: time
         $aOptions['ORDER BY'] = $aArgs['sort'] == 'title' ? 'page_title' : 'page_id';
         //Default DESC
         $aOptions['ORDER BY'] .= $aArgs['order'] == 'ASC' ? ' ASC' : ' DESC';
         $res = $dbr->select($aTables, $aFields, $aConditions, __METHOD__, $aOptions);
         $iCount = 0;
         foreach ($res as $row) {
             if ($iCount == $aArgs['count']) {
                 break;
             }
             $oTitle = Title::makeTitleSafe($row->namespace, $row->title);
             if (!$oTitle || !$oTitle->quickUserCan('read')) {
                 continue;
             }
             $aObjectList[] = $row;
             $iCount++;
         }
         $dbr->freeResult($res);
     } else {
         wfRunHooks('BSSmartListCustomMode', array(&$aObjectList, $aArgs, $this));
     }
     if ($oErrorListView->hasEntries()) {
         return $oErrorListView->execute();
     }
     $oSmartListListView = new ViewBaseElement();
     $oSmartListListView->setAutoElement(false);
     $iItems = 1;
     if (count($aObjectList)) {
         foreach ($aObjectList as $row) {
             $oTitle = Title::makeTitleSafe($row->namespace, $row->title);
             // Security here: only show pages the user can read.
             $sText = '';
             $sMeta = '';
             $sComment = '';
             $sTitle = $oTitle->getText();
             if (BsConfig::get('MW::SmartList::Comments')) {
                 $sComment = strlen($row->comment) > 50 ? substr($row->comment, 0, 50) . '...' : $row->comment;
                 $sComment = wfMessage('bs-smartlist-comment')->params($sComment)->escaped();
             }
             if (isset($aArgs['meta']) && $aArgs['meta'] == true) {
                 $sMeta = ' - <i>(' . $row->username . ', ' . $this->getLanguage()->date($row->time, true, true) . ')</i>';
             }
             $oSmartListListEntryView = new ViewBaseElement();
             if ($aArgs['showtext'] && $iItems <= $aArgs['numwithtext']) {
                 $oSmartListListEntryView->setTemplate('*[[:{NAMESPACE}:{TITLE}|{DISPLAYTITLE}]]{META}<br/>{TEXT}' . "\n");
                 $sText = BsPageContentProvider::getInstance()->getContentFromTitle($oTitle);
                 $sText = Sanitizer::stripAllTags($sText);
                 $sText = BsStringHelper::shorten($sText, array('max-length' => $aArgs['trimtext'], 'position' => 'end'));
                 $sText = '<nowiki>' . $sText . '</nowiki>';
             } else {
                 $oSmartListListEntryView->setTemplate('*[[:{NAMESPACE}:{TITLE}|{DISPLAYTITLE}]] {COMMENT} {META}' . "\n");
             }
             if ($aArgs['showns'] == true) {
                 $sDisplayTitle = $oTitle->getFullText();
             } else {
                 $sDisplayTitle = $oTitle->getText();
             }
             $sDisplayTitle = BsStringHelper::shorten($sDisplayTitle, array('max-length' => $aArgs['trim'], 'position' => 'middle'));
             $sNamespaceText = '';
             if ($row->namespace > 0 && $row->namespace != null) {
                 $sNamespaceText = MWNamespace::getCanonicalName($row->namespace);
             }
             $aData = array('NAMESPACE' => $sNamespaceText, 'TITLE' => $sTitle, 'DISPLAYTITLE' => $sDisplayTitle, 'COMMENT' => $sComment, 'META' => $sMeta, 'TEXT' => $sText);
             wfRunHooks('BSSmartListBeforeEntryViewAddData', array(&$aData, $aArgs, $oSmartListListEntryView, $row));
             $oSmartListListEntryView->addData($aData);
             $oSmartListListView->addItem($oSmartListListEntryView);
             $iItems++;
         }
     } else {
         return '';
     }
     return $this->mCore->parseWikiText($oSmartListListView->execute(), $this->getTitle());
 }
 /**
  *
  * @param type $input
  * @param type $args
  * @param Parser $parser
  * @return type
  */
 public function onMagicWordBsCountCharacters($input, $args, $parser)
 {
     $parser->disableCache();
     if (empty($input)) {
         $oErrorView = new ViewTagError(wfMessage('bs-countthings-error-no-input')->plain());
         return $oErrorView->execute();
     }
     $sMode = isset($args['mode']) ? str_replace(' ', '', $args['mode']) : 'all';
     $aModes = explode(',', $sMode);
     $aAvailableModes = array('chars', 'words', 'pages', 'all');
     $sOut = '';
     $bValidModeProvided = false;
     foreach ($aModes as $sMode) {
         if (!in_array($sMode, $aAvailableModes)) {
             $oErrorView = new ViewTagError(wfMessage('bs-countthings-error-invalid-mode', $sMode)->plain());
             $sOut .= $oErrorView->execute();
             continue;
         }
         $bValidModeProvided = true;
     }
     if ($bValidModeProvided == false) {
         $aModes = array('all');
     }
     $aTitleTexts = explode(',', $input);
     foreach ($aTitleTexts as $sTitleText) {
         $oTitle = Title::newFromText(trim($sTitleText));
         if ($oTitle == null || $oTitle->exists() == false) {
             $oErrorView = new ViewTagError(wfMessage('bs-countthings-error-not-exist', $sTitleText)->plain());
             $sOut .= $oErrorView->execute();
             continue;
         }
         $sContent = BsPageContentProvider::getInstance()->getContentFromTitle($oTitle);
         //Old: last revision
         $oCountView = new ViewCountCharacters();
         $oCountView->setTitle($oTitle);
         if (in_array('all', $aModes)) {
             $iChars = strlen(preg_replace("/\\s+/", " ", $sContent));
             $iWords = sizeof(explode(' ', $sContent));
             $iPages = ceil($iChars / 2000);
             $oCountView->setChars($iChars);
             $oCountView->setWords($iWords);
             $oCountView->setPages($iPages);
             $sOut .= $oCountView->execute();
             continue;
         }
         // TODO RBV (17.02.12 15:34): Find better logic for this...
         if (in_array('chars', $aModes)) {
             $iChars = strlen(preg_replace("/\\s+/", " ", $sContent));
             $oCountView->setChars($iChars);
         }
         if (in_array('words', $aModes)) {
             $iChars = strlen(preg_replace("/\\s+/", " ", $sContent));
             $iWords = sizeof(explode(' ', $sContent));
             $oCountView->setWords($iWords);
         }
         if (in_array('pages', $aModes)) {
             $iChars = strlen(preg_replace("/\\s+/", " ", $sContent));
             $iWords = sizeof(explode(' ', $sContent));
             $iPages = ceil($iChars / 2000);
             $oCountView->setPages($iPages);
         }
         $sOut .= $oCountView->execute();
     }
     return $sOut;
 }
 /**
  * Getter for the $aNavigationSites array - either from hook, TopBarMenu title or cache
  * @global string $wgSitename
  * @return array
  */
 public static function getNavigationSites()
 {
     if (!is_null(self::$aNavigationSites)) {
         return self::$aNavigationSites;
     }
     $sKey = BsExtensionManager::getExtension('TopMenuBarCustomizer')->getCacheKey('NavigationSitesData');
     self::$aNavigationSites = BsCacheHelper::get($sKey);
     if (self::$aNavigationSites !== false) {
         return self::$aNavigationSites;
     }
     self::$aNavigationSites = array();
     $oTopBarMenuTitle = Title::makeTitle(NS_MEDIAWIKI, 'TopBarMenu');
     if (!is_null($oTopBarMenuTitle) && $oTopBarMenuTitle->exists()) {
         $sContent = BsPageContentProvider::getInstance()->getContentFromTitle($oTopBarMenuTitle);
         // Force unset of all menu items by creating an empty page
         if (!empty($sContent)) {
             self::$aNavigationSites = TopMenuBarCustomizerParser::getNavigationSites();
         }
         BsCacheHelper::set($sKey, self::$aNavigationSites, 60 * 1440);
         //max cache time 24h
         return self::$aNavigationSites;
     }
     global $wgSitename;
     $oCurrentTitle = RequestContext::getMain()->getTitle();
     $oMainPage = Title::newMainPage();
     self::$aNavigationSites[] = array('id' => 'wiki', 'href' => $oMainPage->getFullURL(), 'text' => $wgSitename, 'active' => $oCurrentTitle->equals($oMainPage), 'level' => 1, 'containsactive' => false, 'external' => false, 'children' => array());
     wfRunHooks('BSTopMenuBarCustomizerRegisterNavigationSites', array(&self::$aNavigationSites));
     BsCacheHelper::set($sKey, self::$aNavigationSites, 60 * 1440);
     //max cache time 24h
     return self::$aNavigationSites;
 }
 /**
  * Extracts the edit sections out of a given text
  * @param object $oTitle Text to be parsed
  * @return array array of sections
  */
 public function extractEditSections($oTitle)
 {
     $aSections = array();
     if (!$oTitle instanceof Title) {
         return $aSections;
     }
     $sText = BsPageContentProvider::getInstance()->getContentFromTitle($oTitle);
     $aMatches = array();
     $aLines = explode("\n", $sText);
     foreach ($aLines as $sLine) {
         if (preg_match('#^(=){1,6}(.*?)(=){1,6}$#', $sLine, $aMatches)) {
             $aSections[] = trim($aMatches[2]);
         }
     }
     return $aSections;
 }
 /**
  *
  * @param Title $oTitle
  * @return array An Array of Title objects
  */
 public function getTitleListFromTitle($oTitle)
 {
     $sKey = BsCacheHelper::getCacheKey('BlueSpice', 'WantedArticle', $oTitle->getPrefixedText());
     $aData = BsCacheHelper::get($sKey);
     if ($aData !== false) {
         wfDebugLog('BsMemcached', __CLASS__ . ': Fetching WantedArticle list from cache');
         $aTitleList = $aData;
     } else {
         wfDebugLog('BsMemcached', __CLASS__ . ': Fetching WantedArticle list from DB');
         $oArticleContent = BsPageContentProvider::getInstance()->getContentFromTitle($oTitle);
         $aTitleList = array();
         $aLines = explode("\n", $oArticleContent);
         foreach ($aLines as $sLine) {
             $sLine = trim($sLine);
             if (empty($sLine) || $sLine[0] != '*') {
                 continue;
             }
             $aMatches = array();
             #*[[Title]] --[[Spezial:Beiträge/0:0:0:0:0:0:0:1|0:0:0:0:0:0:0:1]] 12:31, 7. Jan. 2013 (AST)
             #*[[Title2]]--[[Benutzer:WikiSysop|WikiSysop]] ([[Benutzer Diskussion:WikiSysop|Diskussion]]) 17:47, 4. Jan. 2013 (AST)
             preg_match('#\\*.*?\\[\\[(.*?)\\]\\]( ?--\\[\\[.*?:(.*?/)?(.*?)\\|.*?\\]\\].*?\\)? (\\(.*?\\))? ?(.*?))?$#si', $sLine, $aMatches);
             if (empty($aMatches) || !isset($aMatches[1])) {
                 continue;
             }
             $sTitle = $aMatches[1];
             $sUsername = isset($aMatches[4]) ? $aMatches[4] : '';
             $sSignature = isset($aMatches[2]) ? $aMatches[2] : '';
             $oT = Title::newFromText($sTitle);
             if ($oT === null) {
                 continue;
             }
             $aTitleList[] = array('title' => $oT, 'username' => $sUsername, 'signature' => $sSignature);
         }
         BsCacheHelper::set($sKey, $aTitleList);
     }
     return $aTitleList;
 }