/**
  * Renders the blog. Called by parser function for bs:blog tag and also from Blog::onUnknownAction.
  * @param string $input Inner HTML of bs:blog 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 onBlog($input, $args, $parser)
 {
     $oTitle = null;
     if ($parser instanceof Parser) {
         $oTitle = $parser->getTitle();
         $parser->disableCache();
     } else {
         $oTitle = $this->getTitle();
     }
     $sKey = BsCacheHelper::getCacheKey('BlueSpice', 'Blog', $oTitle->getArticleID());
     $aData = BsCacheHelper::get($sKey);
     if ($aData !== false) {
         return $aData;
     }
     // initialize local variables
     $oErrorListView = new ViewTagErrorList($this);
     BsExtensionManager::setContext('MW::Blog::ShowBlog');
     // get all config options
     $iShowLimit = BsConfig::get('MW::Blog::ShowLimit');
     //$blogShowTrackback    = BsConfig::get('MW::Blog::ShowTrackback');  // see comment below
     $bShowPermalink = BsConfig::get('MW::Blog::ShowPermalink');
     $bShowInfo = BsConfig::get('MW::Blog::ShowInfo');
     $sSortBy = BsConfig::get('MW::Blog::SortBy');
     $bMoreInNewWindow = BsConfig::get('MW::Blog::MoreInNewWindow');
     $bShowAll = BsConfig::get('MW::Blog::ShowAll');
     $bMoreAtEndOfEntry = BsConfig::get('MW::Blog::MoreAtEndOfEntry');
     $bShowNewEntryField = BsConfig::get('MW::Blog::ShowNewEntryField');
     $bNewEntryFieldPosition = BsConfig::get('MW::Blog::NewEntryFieldPosition');
     $sImageRenderMode = BsConfig::get('MW::Blog::ImageRenderMode');
     $sImageFloatDirection = BsConfig::get('MW::Blog::ThumbFloatDirection');
     $iMaxEntryCharacters = BsConfig::get('MW::Blog::MaxEntryCharacters');
     // Trackbacks are not supported the way we intend it to be. From http://www.mediawiki.org/wiki/Manual:$wgUseTrackbacks
     // When MediaWiki receives a trackback ping, a box will show up at the bottom of the article containing a link to the originating page
     //if (!$wgUseTrackbacks)
     $bShowTrackback = false;
     // get tag attributes
     $argsIShowLimit = BsCore::sanitizeArrayEntry($args, 'count', $iShowLimit, BsPARAMTYPE::NUMERIC | BsPARAMOPTION::DEFAULT_ON_ERROR);
     $argsSCategory = BsCore::sanitizeArrayEntry($args, 'cat', false, BsPARAMTYPE::STRING);
     $argsINamespace = BsNamespaceHelper::getNamespaceIndex(BsCore::sanitizeArrayEntry($args, 'ns', NS_BLOG, BsPARAMTYPE::STRING));
     $argsBNewEntryField = BsCore::sanitizeArrayEntry($args, 'newentryfield', $bShowNewEntryField, BsPARAMTYPE::BOOL);
     $argsSNewEntryFieldPosition = BsCore::sanitizeArrayEntry($args, 'newentryfieldposition', $bNewEntryFieldPosition, BsPARAMTYPE::STRING);
     $argsSImageRenderMode = BsCore::sanitizeArrayEntry($args, 'imagerendermode', $sImageRenderMode, BsPARAMTYPE::STRING);
     $argsSImageFloatDirection = BsCore::sanitizeArrayEntry($args, 'imagefloatdirection', $sImageFloatDirection, BsPARAMTYPE::STRING);
     $argsIMaxEntryCharacters = BsCore::sanitizeArrayEntry($args, 'maxchars', $iMaxEntryCharacters, BsPARAMTYPE::INT);
     $argsSSortBy = BsCore::sanitizeArrayEntry($args, 'sort', $sSortBy, BsPARAMTYPE::STRING);
     $argsBShowInfo = BsCore::sanitizeArrayEntry($args, 'showinfo', $bShowInfo, BsPARAMTYPE::BOOL);
     $argsBMoreInNewWindow = BsCore::sanitizeArrayEntry($args, 'moreinnewwindow', $bMoreInNewWindow, BsPARAMTYPE::BOOL);
     $argsBShowPermalink = BsCore::sanitizeArrayEntry($args, 'showpermalink', $bShowPermalink, BsPARAMTYPE::BOOL);
     $argsModeNamespace = BsCore::sanitizeArrayEntry($args, 'mode', null, BsPARAMTYPE::STRING);
     if ($argsModeNamespace === 'ns' && is_object($oTitle)) {
         $argsINamespace = $oTitle->getNamespace();
     }
     // validate tag attributes
     $validateIShowLimit = BsValidator::isValid('ArgCount', $argsIShowLimit, array('fullResponse' => true));
     if ($validateIShowLimit->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError($validateIShowLimit->getI18N()));
     }
     if ($argsSCategory) {
         $validateSCategory = BsValidator::isValid('Category', $argsSCategory, array('fullResponse' => true));
         if ($validateSCategory->getErrorCode()) {
             $oErrorListView->addItem(new ViewTagError($validateSCategory->getI18N()));
         }
     }
     $oValidationResult = BsValidator::isValid('SetItem', $argsSImageRenderMode, array('fullResponse' => true, 'setname' => 'imagerendermode', 'set' => array('full', 'thumb', 'none')));
     if ($oValidationResult->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError($oValidationResult->getI18N()));
     }
     $oValidationResult = BsValidator::isValid('SetItem', $argsSImageFloatDirection, array('fullResponse' => true, 'setname' => 'imagefloatdirection', 'set' => array('left', 'right', 'none')));
     if ($oValidationResult->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError($oValidationResult->getI18N()));
     }
     $oValidationResult = BsValidator::isValid('SetItem', $argsSSortBy, array('fullResponse' => true, 'setname' => 'sort', 'set' => array('title', 'creation')));
     if ($oValidationResult->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError($oValidationResult->getI18N()));
     }
     // if there are errors, abort with a message
     if ($oErrorListView->hasEntries()) {
         return $oErrorListView->execute();
     }
     if (BsConfig::get('MW::Blog::ShowTagFormWhenNotLoggedIn') != true) {
         $oPermissionTest = Title::newFromText('PermissionTest', $argsINamespace);
         if (!$oPermissionTest->userCan('edit')) {
             $argsBNewEntryField = false;
         }
     }
     // get array of article ids from Blog/subpages
     $oBlogTitle = Title::makeTitleSafe($oTitle->getNamespace(), 'Blog');
     $aSubpages = $oBlogTitle->getSubpages();
     $iLimit = 0;
     // for later use
     $aArticleIds = array();
     foreach ($aSubpages as $oSubpage) {
         $aArticleIds[] = $oSubpage->getArticleID();
         $iLimit++;
         // for later use
     }
     if (count($aArticleIds) < 1) {
         $aArticleIds = 0;
     }
     $aTables = array('page');
     $aFields = array('entry_page_id' => 'page_id');
     $aConditions = array();
     $aOptions = array();
     $aJoins = array();
     $dbr = wfGetDB(DB_SLAVE);
     // get blog entries
     if ($argsSSortBy == 'title') {
         $aOptions['ORDER BY'] = 'page_title ASC';
     } else {
         //Creation: Also fetch possible custom timestamps from page_props table
         $aOptions['ORDER BY'] = 'entry_timestamp DESC';
         $aOptions['GROUP BY'] = 'page_id';
         global $wgDBtype;
         switch ($wgDBtype) {
             case 'oracle':
                 $aFields['entry_timestamp'] = "NVL( pp_value, rev_timestamp )";
                 $aConditions[] = "NVL( pp_value, rev_timestamp ) < " . wfTimestampNow();
                 break;
             case 'mssql':
                 $aFields['entry_timestamp'] = "ISNULL( pp_value, rev_timestamp )";
                 $aConditions[] = "ISNULL( pp_value, rev_timestamp ) < " . wfTimestampNow();
                 break;
             case 'postgres':
                 $aFields['entry_timestamp'] = "NULLIF( pp_value, rev_timestamp )";
                 $aConditions[] = "NULLIF( pp_value, rev_timestamp ) < " . wfTimestampNow();
                 break;
             default:
                 //MySQL, SQLite
                 //use pp_value if exists
                 $aFields['entry_timestamp'] = "IFNULL( pp_value, rev_timestamp )";
                 //also do not list future entries
                 $aConditions[] = "IFNULL( pp_value, rev_timestamp ) < " . wfTimestampNow();
         }
         $aTables[] = 'revision';
         $aTables[] = 'page_props';
         $aConditions[] = 'rev_page = page_id';
         $aJoins['page_props'] = array('LEFT JOIN', "pp_page = rev_page AND pp_propname = 'blogtime'");
     }
     if ($argsSCategory) {
         $aTables[] = 'categorylinks';
         $aConditions['cl_to'] = $argsSCategory;
         $aConditions[] = 'cl_from = page_id';
     } else {
         if ($argsModeNamespace === 'ns') {
             $aConditions['page_id'] = $aArticleIds;
         }
         $aConditions['page_namespace'] = $argsINamespace;
     }
     $res = $dbr->select($aTables, $aFields, $aConditions, __METHOD__, $aOptions, $aJoins);
     $iNumberOfEntries = $dbr->numRows($res);
     $iLimit = $iNumberOfEntries;
     //All
     // Sole importance is the existence of param 'showall'
     $paramBShowAll = $this->getRequest()->getFuzzyBool('showall', false);
     if ($paramBShowAll == false) {
         $iLimit = $argsIShowLimit;
     }
     // abort if there are no entries
     if ($iNumberOfEntries < 1) {
         $oBlogView = new ViewBlog();
         $oBlogView->setOption('shownewentryfield', $argsBNewEntryField);
         $oBlogView->setOption('newentryfieldposition', $argsSNewEntryFieldPosition);
         $oBlogView->setOption('namespace', BsNamespaceHelper::getNamespaceName($argsINamespace));
         if ($argsSCategory) {
             $oBlogView->setOption('blogcat', $argsSCategory);
         }
         // actually create blog output
         $sOut = $oBlogView->execute();
         $sOut .= wfMessage('bs-blog-no-entries')->plain();
         return $sOut;
     }
     $oBlogView = new ViewBlog();
     // prepare views per blog item
     $iLoop = 0;
     foreach ($res as $row) {
         // prepare data for view class
         $oEntryTitle = Title::newFromID($row->entry_page_id);
         if (!$oEntryTitle->userCan('read')) {
             $iNumberOfEntries--;
             continue;
         }
         $bMore = false;
         $aContent = preg_split('#<(bs:blog:)?more */>#', BsPageContentProvider::getInstance()->getContentFromTitle($oEntryTitle));
         if (sizeof($aContent) > 1) {
             $bMore = true;
         }
         $aContent = trim($aContent[0]);
         // Prevent recursive rendering of blog tag
         $aContent = preg_replace('/<(bs:)blog[^>]*?>/', '', $aContent);
         // Thumbnail images
         $sNamespaceRegEx = implode('|', BsNamespaceHelper::getNamespaceNamesAndAliases(NS_IMAGE));
         switch ($argsSImageRenderMode) {
             case 'none':
                 $aContent = preg_replace('/(\\[\\[(' . $sNamespaceRegEx . '):[^\\|\\]]*)(\\|)?(.*?)(\\]\\])/', '', $aContent);
                 break;
             case 'full':
                 // do nothing
                 break;
             case 'thumb':
             default:
                 $aContent = preg_replace('/(\\[\\[(' . $sNamespaceRegEx . '):[^\\|\\]]*)(\\|)?(.*?)(\\]\\])/', "\$1|thumb|{$argsSImageFloatDirection}\$3\$4|150px\$5", $aContent);
                 break;
         }
         if (strlen($aContent) > $argsIMaxEntryCharacters) {
             $bMore = true;
         }
         $aContent = BsStringHelper::shorten($aContent, array('max-length' => $argsIMaxEntryCharacters, 'ignore-word-borders' => false, 'position' => 'end'));
         $resComment = $dbr->selectRow('revision', 'COUNT( rev_id ) AS cnt', array('rev_page' => $oEntryTitle->getTalkPage()->getArticleID()));
         $iCount = $resComment->cnt;
         // set data for view class
         $oBlogItemView = new ViewBlogItem();
         // use magic set
         $oBlogItemView->setOption('showInfo', $argsBShowInfo);
         $oBlogItemView->setOption('showLimit', $argsIShowLimit);
         $oBlogItemView->setOption('showTrackback', $bShowTrackback);
         $oBlogItemView->setOption('showPermalink', $argsBShowPermalink);
         $oBlogItemView->setOption('moreInNewWindow', $argsBMoreInNewWindow);
         $oBlogItemView->setOption('showAll', $bShowAll);
         $oBlogItemView->setOption('moreAtEndOfEntry', $bMoreAtEndOfEntry);
         $oBlogItemView->setOption('more', $bMore);
         //TODO: magic_call?
         if ($argsModeNamespace === 'ns') {
             $sTitle = substr($oEntryTitle->getText(), 5);
         } else {
             $sTitle = $oEntryTitle->getText();
         }
         $aTalkParams = array();
         if (!$oEntryTitle->getTalkPage()->exists()) {
             $aTalkParams = array('action' => 'edit');
         }
         $oRevision = Revision::newFromTitle($oEntryTitle);
         $oBlogItemView->setTitle($sTitle);
         $oBlogItemView->setRevId($oRevision->getId());
         $oBlogItemView->setURL($oEntryTitle->getLocalURL());
         $oBlogItemView->setTalkURL($oEntryTitle->getTalkPage()->getLocalURL($aTalkParams));
         $oBlogItemView->setTalkCount($iCount);
         $oBlogItemView->setTrackbackUrl($oEntryTitle->getLocalURL());
         if ($bShowInfo) {
             $oFirstRevision = $oEntryTitle->getFirstRevision();
             $sTimestamp = $oFirstRevision->getTimestamp();
             $sLocalDateTimeString = BsFormatConverter::timestampToAgeString(wfTimestamp(TS_UNIX, $sTimestamp));
             $oBlogItemView->setEntryDate($sLocalDateTimeString);
             $iUserId = $oFirstRevision->getUser();
             if ($iUserId != 0) {
                 $oAuthorUser = User::newFromId($iUserId);
                 $oBlogItemView->setAuthorPage($oAuthorUser->getUserPage()->getPrefixedText());
                 $oBlogItemView->setAuthorName($this->mCore->getUserDisplayName($oAuthorUser));
             } else {
                 $oBlogItemView->setAuthorName($oFirstRevision->getUserText());
             }
         }
         $oBlogItemView->setContent($aContent);
         $oBlogView->addItem($oBlogItemView);
         $iLoop++;
         if ($iLoop >= $iLimit) {
             break;
         }
     }
     $dbr->freeResult($res);
     // prepare complete blog output
     if ($bShowAll && !$paramBShowAll && $iNumberOfEntries > $argsIShowLimit) {
         $oBlogView->setOption('showall', true);
     }
     $oBlogView->setOption('shownewentryfield', $argsBNewEntryField);
     $oBlogView->setOption('newentryfieldposition', $argsSNewEntryFieldPosition);
     $oBlogView->setOption('namespace', BsNamespaceHelper::getNamespaceName($argsINamespace, false));
     $oBlogView->setOption('blogcat', $argsSCategory);
     if ($argsModeNamespace === 'ns') {
         $oBlogView->setOption('parentpage', 'Blog/');
     }
     // actually create blog output
     $sOut = $oBlogView->execute();
     //Use cache only in NS_BLOG - there is curently no functionality to
     //figure out in what type of blog tag a entry is showen and why
     //(coditions). Possible blog by categories or subpages...
     //Needs rework.
     if (in_array($oTitle->getNamespace(), array(NS_BLOG, NS_BLOG_TALK))) {
         $aKey = array($sKey);
         $sTagsKey = BsCacheHelper::getCacheKey('BlueSpice', 'Blog', 'Tags');
         $aTagsData = BsCacheHelper::get($sTagsKey);
         if ($aTagsData !== false) {
             if (!in_array($sKey, $aTagsData)) {
                 $aTagsData = array_merge($aTagsData, $aKey);
             }
         } else {
             $aTagsData = $aKey;
         }
         BsCacheHelper::set($sTagsKey, $aTagsData, 60 * 1440);
         // one day
         BsCacheHelper::set($sKey, $sOut, 60 * 1440);
         // one day
     }
     return $sOut;
 }
 /**
  * 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;
 }
 /**
  * Generates a list of the most visisted pages
  * @param string $sInput Inner HTML of BsTagMToplist tag. Not used.
  * @param array $aArgs List of tag attributes.
  * @param Parser $oParser MediaWiki parser object
  * @return string HTML output that is to be displayed.
  */
 public function getToplist($sInput, $aArgs, $oParser)
 {
     $sCat = BsCore::sanitizeArrayEntry($aArgs, 'cat', '', BsPARAMTYPE::STRING);
     $sNs = BsCore::sanitizeArrayEntry($aArgs, 'ns', '', BsPARAMTYPE::STRING);
     $iCount = BsCore::sanitizeArrayEntry($aArgs, 'count', 10, BsPARAMTYPE::INT);
     $sPeriod = BsCore::sanitizeArrayEntry($aArgs, 'period', 'alltime', BsPARAMTYPE::STRING);
     $iPortletPeriod = BsCore::sanitizeArrayEntry($aArgs, 'portletperiod', 0, BsPARAMTYPE::INT);
     $bAlltime = true;
     $oDbr = wfGetDB(DB_SLAVE);
     if (in_array($sPeriod, array('week', 'month')) || in_array($iPortletPeriod, array(7, 30))) {
         $aTables = array('bs_whoisonline');
         $aColumns = array('COUNT( wo_page_title ) AS page_counter', 'wo_page_title', 'wo_page_namespace');
         $aConditions = array('wo_action' => 'view');
         $aOptions = array('GROUP BY' => 'wo_page_title', 'ORDER BY' => 'page_counter DESC');
         $aJoinConditions = array();
         if ($sPeriod === 'week' || $iPortletPeriod === 7) {
             $iTimestamp = wfTimestamp(TS_UNIX) - 7 * 24 * 60 * 60;
             $aConditions[] = 'wo_timestamp >= ' . $iTimestamp;
         }
         $bAlltime = false;
     } else {
         $aTables = array('page');
         $aColumns = array('page_title', 'page_counter', 'page_namespace');
         $aConditions = array();
         $aOptions = array('ORDER BY' => 'page_counter DESC');
         $aJoinConditions = array();
     }
     if (!empty($sCat)) {
         $aCategories = explode(',', $sCat);
         $aCategories = array_map('trim', $aCategories);
         $aCategories = str_replace(' ', '_', $aCategories);
         if ($bAlltime === false) {
             $aColumns[] = 'wo_page_id';
             $aJoinConditions = array('categorylinks' => array('INNER JOIN ', 'wo_page_id = cl_from'));
             $aTables[] = 'categorylinks';
             $aConditions['cl_to'] = $aCategories;
         } else {
             $aTables[] = 'categorylinks';
             $aConditions[] = 'page_id = cl_from';
             $aConditions['cl_to'] = $aCategories;
         }
     }
     if (!empty($sNs) || $sNs === '0') {
         // string 0 is empty
         $aNamespaces = BsNamespaceHelper::getNamespaceIdsFromAmbiguousCSVString($sNs);
         if (!empty($aNamespaces)) {
             $sField = $bAlltime ? 'page_namespace' : 'wo_page_namespace';
             $aConditions[$sField] = $aNamespaces;
         }
     }
     $res = $oDbr->select($aTables, $aColumns, $aConditions, __METHOD__, $aOptions, $aJoinConditions);
     if ($oDbr->numRows($res) > 0) {
         $bCategories = false;
         if (!empty($aCategories)) {
             $bCategories = true;
             $aPrefixedCategories = array();
             foreach ($aCategories as $sCategory) {
                 $sCategory = str_replace(' ', '_', $sCategory);
                 $sCat = Title::makeTitle(NS_CATEGORY, $sCategory);
                 $aPrefixedCategories[] = $sCat->getPrefixedDBKey();
             }
         }
         $aList = array();
         $aInList = array();
         $iCurrCount = 0;
         if ($bAlltime === false) {
             foreach ($res as $row) {
                 if ($iCurrCount === $iCount) {
                     break;
                 }
                 if (empty($row->wo_page_title)) {
                     continue;
                 }
                 $oTitle = Title::makeTitle($row->wo_page_namespace, $row->wo_page_title);
                 if (!$oTitle->quickUserCan('read')) {
                     continue;
                 }
                 if ($bCategories === true) {
                     $aParents = array_keys($oTitle->getParentCategories());
                     $aResult = array_diff($aPrefixedCategories, $aParents);
                     if (!empty($aResult)) {
                         continue;
                     }
                 }
                 if (in_array($oTitle->getPrefixedText(), $aInList)) {
                     continue;
                 }
                 $aInList[] = $oTitle->getPrefixedText();
                 $sLink = BsLinkProvider::makeLink($oTitle);
                 $aList['<li>' . $sLink . ' (' . $row->page_counter . ')</li>'] = (int) $row->page_counter;
                 $iCurrCount++;
             }
             arsort($aList);
             $aList = array_keys($aList);
             array_unshift($aList, '<ol>');
         } else {
             $aList[] = '<ol>';
             foreach ($res as $row) {
                 if ($iCurrCount == $iCount) {
                     break;
                 }
                 if ($row->page_counter == '0') {
                     continue;
                 }
                 $oTitle = Title::makeTitle($row->page_namespace, $row->page_title);
                 if (!$oTitle->quickUserCan('read')) {
                     continue;
                 }
                 if ($bCategories === true) {
                     $aParents = array_keys($oTitle->getParentCategories());
                     $aResult = array_diff($aPrefixedCategories, $aParents);
                     if (!empty($aResult)) {
                         continue;
                     }
                 }
                 if (in_array($oTitle->getPrefixedText(), $aInList)) {
                     continue;
                 }
                 $aInList[] = $oTitle->getPrefixedText();
                 $sLink = BsLinkProvider::makeLink($oTitle);
                 $aList[] = '<li>' . $sLink . ' (' . $row->page_counter . ')</li>';
                 $iCurrCount++;
             }
         }
         $aList[] = '</ol>';
         $oDbr->freeResult($res);
         return "\n" . implode("\n", $aList);
     }
     $oDbr->freeResult($res);
     return wfMessage('bs-smartlist-no-entries')->plain();
 }
 /**
  * Creates the HTML for &lt;bs:watchlist /&gt; tag
  * @param string $sInput Inner HTML of the tag. Not used.
  * @param array $aAttributes List of the tag's attributes.
  * @param Parser $oParser MediaWiki parser object.
  * @return string Rendered HTML.
  */
 public function onWatchlistTag($sInput, $aAttributes, $oParser)
 {
     //Get arguments
     $iCount = BsCore::sanitizeArrayEntry($aAttributes, 'count', 5, BsPARAMTYPE::INT);
     $iMaxTitleLength = BsCore::sanitizeArrayEntry($aAttributes, 'maxtitlelength', 20, BsPARAMTYPE::INT);
     $sOrder = BsCore::sanitizeArrayEntry($aAttributes, 'order', 'pagename', BsPARAMTYPE::SQL_STRING);
     //'pagename|time'
     //Validation
     $oErrorListView = new ViewTagErrorList($this);
     $oValidationICount = BsValidator::isValid('IntegerRange', $iCount, array('fullResponse' => true, 'lowerBoundary' => 1, 'upperBoundary' => 1000));
     if ($oValidationICount->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError('count: ' . wfMessage($oValidationICount->getI18N())->text()));
     }
     $oValidationIMaxTitleLength = BsValidator::isValid('IntegerRange', $iMaxTitleLength, array('fullResponse' => true, 'lowerBoundary' => 5, 'upperBoundary' => 500));
     if ($oValidationIMaxTitleLength->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError('maxtitlelength: ' . wfMessage($oValidationIMaxTitleLength->getI18N())->text()));
     }
     $oValidationResult = BsValidator::isValid('SetItem', $sOrder, array('fullResponse' => true, 'setname' => 'sort', 'set' => array('time', 'pagename')));
     if ($oValidationResult->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError($oValidationResult->getI18N()));
     }
     if ($oErrorListView->hasItems()) {
         return $oErrorListView->execute();
     }
     $oWatchList = $this->fetchWatchlist($this->getUser(), $iCount, $iMaxTitleLength, $sOrder);
     return $this->mCore->parseWikiText($oWatchList->execute(), $this->getTitle());
 }
 /**
  * Handles the Parser Hook for TagExtensions
  * @param string $sInput Content of $lt;pagesvisited /&gt; from MediaWiki Framework
  * @param array $aAttributes Attributes of &lt;pagesvisited /&gt; from MediaWiki Framework
  * @param Parser $oParser Parser object from MediaWiki Framework
  * @return string HTML list of recently visited pages
  */
 public function onPagesVisitedTag($sInput, $aAttributes, $oParser)
 {
     $oParser->disableCache();
     $oErrorListView = new ViewTagErrorList($this);
     $iCount = BsCore::sanitizeArrayEntry($aAttributes, 'count', 5, BsPARAMTYPE::INT);
     $iMaxTitleLength = BsCore::sanitizeArrayEntry($aAttributes, 'maxtitlelength', 20, BsPARAMTYPE::INT);
     $sNamespaces = BsCore::sanitizeArrayEntry($aAttributes, 'namespaces', 'all', BsPARAMTYPE::STRING | BsPARAMOPTION::CLEANUP_STRING);
     $sSortOrder = BsCore::sanitizeArrayEntry($aAttributes, 'order', 'time', BsPARAMTYPE::STRING | BsPARAMOPTION::CLEANUP_STRING);
     //Validation
     $oValidationICount = BsValidator::isValid('IntegerRange', $iCount, array('fullResponse' => true, 'lowerBoundary' => 1, 'upperBoundary' => 30));
     if ($oValidationICount->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError('count: ' . $oValidationICount->getI18N()));
     }
     $oValidationIMaxTitleLength = BsValidator::isValid('IntegerRange', $iMaxTitleLength, array('fullResponse' => true, 'lowerBoundary' => 5, 'upperBoundary' => 50));
     if ($oValidationIMaxTitleLength->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError('maxtitlelength: ' . $oValidationIMaxTitleLength->getI18N()));
     }
     if ($oErrorListView->hasItems()) {
         return $oErrorListView->execute();
     }
     $iCurrentNamespaceId = $oParser->getTitle()->getNamespace();
     $oListView = $this->makePagesVisitedWikiList($iCount, $sNamespaces, $iCurrentNamespaceId, $iMaxTitleLength, $sSortOrder);
     $sOut = $oListView->execute();
     if ($oListView instanceof ViewTagErrorList) {
         return $sOut;
     } else {
         return $this->mCore->parseWikiText($sOut, $this->getTitle());
     }
 }
 /**
  * Callback for MediaWiki Parser. Renders the list of wanted articles
  * @param string $sInput The content of the tag. Usually empty string.
  * @param array $aAttributes An Array of given attributes
  * @param Parser $oParser The MediaWiki parser object
  * @return string The rendered <bs:wantedarticles /> tag
  */
 public function onWantedArticlesTag($sInput, $aAttributes, $oParser)
 {
     $oParser->disableCache();
     $oErrorListView = new ViewTagErrorList($this);
     $sDefaultTitle = wfMessage('bs-wantedarticle-tag-default-title')->plain();
     $iCount = BsCore::sanitizeArrayEntry($aAttributes, 'count', 5, BsPARAMTYPE::INT);
     $sSort = BsCore::sanitizeArrayEntry($aAttributes, 'sort', 'time', BsPARAMTYPE::STRING);
     $sOrder = BsCore::sanitizeArrayEntry($aAttributes, 'order', 'DESC', BsPARAMTYPE::STRING);
     $sTitle = BsCore::sanitizeArrayEntry($aAttributes, 'title', $sDefaultTitle, BsPARAMTYPE::STRING);
     $sType = BsCore::sanitizeArrayEntry($aAttributes, 'type', 'list', BsPARAMTYPE::STRING);
     //Validation
     $oValidationICount = BsValidator::isValid('IntegerRange', $iCount, array('fullResponse' => true, 'lowerBoundary' => 1, 'upperBoundary' => 30));
     if ($oValidationICount->getErrorCode()) {
         $oErrorListView->addItem(new ViewTagError('count: ' . $oValidationICount->getI18N()));
     }
     if (!in_array($sSort, array('', 'time', 'title'))) {
         $oErrorListView->addItem(new ViewTagError('sort: ' . wfMessage('bs-wantedarticle-sort-value-unknown')->plain()));
     }
     if (!in_array($sOrder, array('', 'ASC', 'DESC'))) {
         $oErrorListView->addItem(new ViewTagError('order: ' . wfMessage('bs-wantedarticle-order-value-unknown')->plain()));
     }
     if ($oErrorListView->hasItems()) {
         return $oErrorListView->execute();
     }
     //Create list
     $aWishList = $this->getTitleListFromTitle($this->getDataSourceTemplateArticle()->getTitle());
     switch ($sSort) {
         case 'title':
             $aTitleList = $this->sortWishListByTitle($aWishList);
             break;
         case 'time':
         default:
             $aTitleList = $this->getDefaultTitleList($aWishList);
     }
     if ($sOrder == 'ASC') {
         $aTitleList = array_reverse($aTitleList);
     }
     $oWishListView = new ViewWantedArticleTag();
     $oWishListView->setTitle($sTitle)->setType($sType)->setOrder($sOrder)->setSort($sSort)->setCount($iCount)->setList($aTitleList);
     return $oWishListView->execute();
 }