/** * This method actually generates the output * @param array $params not used here * @return string HTML output */ public function execute($params = false) { if ($this->hasItems()) { $out = parent::execute(); if ($this->iMoreLimit) { $out .= '<li class="bs-sb-more"><a href="#" onclick="BsShoutBox.updateShoutbox(' . $this->iMoreLimit . ');return false;"> </a></li>'; } } else { $out = '<li><i>' . wfMessage('bs-shoutbox-no-entries')->plain() . '</i></li>'; } return '<ul>' . $out . '</ul>'; }
/** * This method actually generates the output * @return string HTML output */ public function execute($params = false) { $sOut = ''; if ($this->getOption('shownewentryfield') && $this->getOption('newentryfieldposition') == 'top') { $sOut .= $this->renderShowNewEntryField(); } $sOut .= parent::execute(); $sOut .= $this->renderShowAll(); if ($this->getOption('shownewentryfield') && $this->getOption('newentryfieldposition') == 'bottom') { $sOut .= $this->renderShowNewEntryField(); } return $sOut; }
/** * This method actually generates the output * @param array $params List of parameters * @return string HTML output */ public function execute($params = false) { $aOut = array(); $aOut[] = '<ul>'; if ($this->getOption('count') == 0) { $aOut[] = '<li>' . wfMessage('bs-whoisonline-nousers')->plain() . '</li>'; } else { $this->setAutoElement(''); $aOut[] = parent::execute(); } $aOut[] = '</ul>'; $sOut = implode("\n", $aOut); if ($this->getOption('wrapper-id') !== false) { return '<div style="display: none;" class="bs-tooltip"><div id="' . $this->getOption('wrapper-id') . '">' . $sOut . '</div></div>'; } return $sOut; }
/** * This method actually generates the output * @return string HTML output */ public function execute($params = false) { $this->setTemplate(''); $bChecked = $this->iEntriesChecked > 0 ? true : false; $sFacetHead = '<div class="bs-facet-title bs-extendedsearch-default-textspacing">'; $sFacetHead .= Xml::check('', $bChecked, array('urldiff' => $this->getOption('uri-facet-all-diff'))); $sFacetHead .= '<label>' . wfMessage($this->getOption('title'))->plain() . '</label>'; $sFacetHead .= '</div>'; $this->addCompleteDataset($this->aEntriesChecked); $body = parent::execute(); if (!empty($this->aEntriesChecked) && !empty($this->aEntriesUnChecked)) { $body .= Xml::element('span', array('class' => 'bs-extendedsearch-facet-separator'), '', false); } $this->addCompleteDataset($this->aEntriesUnChecked); $body .= parent::execute(); if (empty($body)) { return ''; } $body .= '<div class="bs-extendedsearch-facetend"></div><div class="bs-extendedsearch-facetbox-more"></div>'; $body = Xml::openElement('div', array('class' => 'bs-extendedsearch-facetbox-container')) . $body . Xml::closeElement('div'); $body = Xml::openElement('div', array('class' => 'bs-extendedsearch-facetbox')) . $body . Xml::closeElement('div'); return $sFacetHead . $body; }
/** * Hook-Handler for 'OutputPageBeforeHTML' (MediaWiki). Replaces Emoticon syntax with images. * @param ParserOutput $oParserOutput The ParserOutput object that corresponds to the page. * @param string $sText The text that will be displayed in HTML. * @return bool Always true to keep hook running. */ public function onOutputPageBeforeHTML(&$oParserOutput, &$sText) { global $wgScriptPath; $sCurrentAction = $this->getRequest()->getVal('action', 'view'); $oCurrentTitle = $this->getTitle(); if (in_array($sCurrentAction, array('edit', 'history', 'delete', 'watch'))) { return true; } if (in_array($oCurrentTitle->getNamespace(), array(NS_SPECIAL, NS_MEDIAWIKI))) { return true; } wfProfileIn('BS::' . __METHOD__); $sKey = BsCacheHelper::getCacheKey('BlueSpice', 'Emoticons'); $aMapping = BsCacheHelper::get($sKey); if ($aMapping == false) { $sPathToEmoticons = $wgScriptPath . '/extensions/BlueSpiceExtensions/Emoticons/emoticons'; // Get the list of emoticons from the message system. $sMappingContent = "smile.png :-) :)\n\t\t\t\t\t\t\t\tsad.png :-( :(\n\t\t\t\t\t\t\t\tneutral.png :-| :|\n\t\t\t\t\t\t\t\tangry.png :-@ :@\n\t\t\t\t\t\t\t\twink.png ;-) ;)\n\t\t\t\t\t\t\t\tsmile-big.png :D :-D\n\t\t\t\t\t\t\t\tthinking.png :-/ :/\n\t\t\t\t\t\t\t\tshut-mouth.png :-X :X\n\t\t\t\t\t\t\t\tcrying.png :'(\n\t\t\t\t\t\t\t\tshock.png :-O\n\t\t\t\t\t\t\t\tconfused.png :-S\n\t\t\t\t\t\t\t\tglasses-cool.png 8-)\n\t\t\t\t\t\t\t\tlaugh.png :lol:\n\t\t\t\t\t\t\t\tyawn.png (:|\n\t\t\t\t\t\t\t\tgood.png :good:\n\t\t\t\t\t\t\t\tbad.png :bad:\n\t\t\t\t\t\t\t\tembarrassed.png :-[\n\t\t\t\t\t\t\t\tshame.png [-X [-x"; if (empty($sMappingContent)) { return true; } // If the content successfully loaded, do the replacement $aMappingLines = explode("\n", $sMappingContent); $aEmoticons = array(); $aImageReplacements = array(); foreach ($aMappingLines as $sLine) { $sLine = trim($sLine); //Remove leading space if (empty($sLine)) { continue; } //Empty line? if ($sLine[0] == '#') { continue; } //Comment line? $aEmoticonHash = preg_split('/ +/', $sLine); // $aEmoticonHash = array('smile.png', ':-)', ':)'); if (count($aEmoticonHash) > 1) { $sImageName = array_shift($aEmoticonHash); // first element is image name, here 'smile.png' $oEmoticonImageView = new ViewBaseElement(); $oEmoticonImageView->setTemplate(' <img border="0" src="' . $sPathToEmoticons . '/{FILENAME}" alt="emoticon" />'); $oEmoticonImageView->addData(array('FILENAME' => $sImageName)); foreach ($aEmoticonHash as $sEmote) { $aEmoticons[] = ' ' . $sEmote; $aEmoticons[] = ' ' . $sEmote; $aEmoticons[] = ' ' . $sEmote; // (TL., 25.02.2011) das brauchen wir wirklich 3 mal, weil auch aEmoticons[] 3 mal gefüllt wird! $aImageReplacements[] = $oEmoticonImageView->execute(); $aImageReplacements[] = $oEmoticonImageView->execute(); $aImageReplacements[] = $oEmoticonImageView->execute(); } } } $aMapping = array('emoticons' => $aEmoticons, 'replacements' => $aImageReplacements); BsCacheHelper::set($sKey, $aMapping); } $sText = str_replace($aMapping['emoticons'], $aMapping['replacements'], $sText); wfProfileOut('BS::' . __METHOD__); return true; }
/** * * @global User $wgUser * @param Title $oTitle * @return false|\ViewStateBarBodyElement */ private function makeStateBarBodySubPages($oTitle) { global $wgUser; if ($oTitle->hasSubpages() == false) { return false; } wfProfileIn('BS::' . __METHOD__); $oSubpageListView = new ViewStateBarBodyElement(); $oSubpageListView->setKey('Subpages'); $oSubpageListView->setHeading(wfMessage('bs-articleinfo-subpages')->plain()); $aSubpages = $oTitle->getSubpages(-1); if (count($aSubpages) > 100) { $oSubpageListView->setBodyText(wfMessage('bs-articleinfo-subpages-too-much')->plain()); } else { // TODO RBV (22.02.12 10:22): Less inline CSS, more use of classes $oList = new ViewBaseElement(); $oList->setAutoWrap('<ul style="margin:0">###CONTENT###</ul>'); $oList->setTemplate('<li style="{STYLE}">→ {LINK}</li>'); foreach ($aSubpages as $oTitle) { $sLink = $wgUser->getSkin()->link($oTitle, $oTitle->getSubpageText()); $sStyle = 'margin-left:' . (count(explode('/', $oTitle->getText())) - 1) . 'em'; $oList->addData(array('LINK' => $sLink, 'STYLE' => $sStyle)); } $oSubpageListView->setBodyText($oList->execute()); } wfRunHooks('BSArticleInfoBeforeSubpagesBodyView', array($this, &$oSubpageListView)); wfProfileOut('BS::' . __METHOD__); return $oSubpageListView; }
public static function makeStateBarBodyElementKeyValueTable($aParameters) { $oKeyValueTable = new ViewBaseElement(); $oKeyValueTable->setTemplate('<table class="contenttable">###ROWS###</table>'); $oRowView = new ViewBaseElement(); $oRowView->setTemplate('<tr><td>{KEY}</td><td><em>{VALUE}</em></td></tr>'); foreach ($aParameters['rows'] as $sKey => $sValue) { $oRowView->addData(array('KEY' => wfMessage('bs-universalexport-' . $sKey)->plain(), 'VALUE' => $sValue)); } $oKeyValueTable->addItem($oRowView, 'ROWS'); $oKeyValueStateBarBodyView = new ViewStateBarBodyElement(); $oKeyValueStateBarBodyView->setKey($aParameters['key']); $oKeyValueStateBarBodyView->setHeading($aParameters['heading']); $oKeyValueStateBarBodyView->setBodyText($oKeyValueTable->execute()); return $oKeyValueStateBarBodyView; }
/** * 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()); }
/** * Renders the inner content of search result page. * @return ViewBaseElement View with inner content of search result page. */ public function renderSpecialpage() { $this->oSearchRequest->init(); $this->oSearchOptions->readInSearchRequest(); $this->oSearchUriBuilder->init(); // Form and results views are added via addItem to a ViewBaseElement $oSearchformView = new ViewBaseElement(); $oSearchform = new ViewExtendedSearchFormPage(); $oSearchform->setRequest($this->oSearchRequest); $aMonitor = array(); if ($this->oSearchOptions->getOptionBool('bExtendedForm')) { $aMonitor['linkToExtendedPageMessageKey'] = 'bs-extendedsearch-specialpage-form-return-to-simple'; $aMonitor['linkToExtendedPageUri'] = $this->oSearchUriBuilder->buildUri(SearchUriBuilder::ALL); $this->renderExtendedForm($oSearchform); $oSearchform->setOptions($aMonitor); $oSearchformView->addItem($oSearchform); return $oSearchformView; } else { $aMonitor['linkToExtendedPageMessageKey'] = 'bs-extendedsearch-specialpage-form-expand-to-extended'; $aMonitor['linkToExtendedPageUri'] = $this->oSearchUriBuilder->buildUri(SearchUriBuilder::ALL | SearchUriBuilder::EXTENDED); } $oSearchform->setOptions($aMonitor); $oSearchformView->addItem($oSearchform); $this->oContext->getOutPut()->addHTML($oSearchformView->execute()); return $this->getResults(false); }
/** * This method actually generates the output * @return string HTML output */ public function execute($param = false) { $aOut = array(); $aOut[] = parent::execute(); $aOut[] = $this->sOut; if (!empty($this->aResultEntryView)) { $sResults = implode("\n", $this->aResultEntryView); $aOut[] = '<div id="bs-extendedsearch-spinner"></div>'; $aOut[] = '<hr /><br />'; if ($this->getOption('siteUri')) { $aOut[] = Xml::element('div', array('id' => 'bs-extendedsearch-siteuri', 'siteuri' => $this->getOption('siteUri')), '', false); } $aOut[] = '<div id="bs-extendedsearch-filters-results-paging">'; if ($this->getOption('showfacets')) { $sFilterBoxes = ''; foreach ($this->aFacetBoxes as $box) { $sFilterBoxes .= $box->execute(); } $sFilterBoxes = Xml::openElement('div', array('id' => 'bs-extendedsearch-all-filter-boxes')) . $sFilterBoxes . Xml::closeElement('div'); $aOut[] = Xml::openElement('div', array('id' => 'bs-extendedsearch-filters')) . $sFilterBoxes . Xml::closeElement('div'); } $cachePaging = $this->getPaging(); $upperPaging = Xml::openElement('div', array('class' => 'bs-extendedsearch-default-line bs-extendedsearch-paging', 'id' => 'bs-extendedsearch-paging-upper')); $upperPaging .= $cachePaging; $upperPaging .= Xml::closeElement('div'); $lowerPaging = Xml::openElement('div', array('class' => 'bs-extendedsearch-default-line bs-extendedsearch-paging', 'id' => 'bs-extendedsearch-paging-lower')); $lowerPaging .= $cachePaging; $lowerPaging .= Xml::closeElement('div'); $sortingBar = Xml::openElement('div', array('class' => 'bs-extendedsearch-sorting-bar bs-extendedsearch-default-textspacing')); $sortingBar .= $this->getSortingBar(); $sortingBar .= Xml::closeElement('div'); $results = Xml::openElement('div', array('id' => 'bs-extendedsearch-results')); $results .= $sResults; $results .= Xml::closeElement('div'); $aOut[] = $this->getOption('showfacets') ? '<div id="bs-extendedsearch-results-paging" class="bs-extendedsearch-results-with-facets">' : '<div id="bs-extendedsearch-results-paging">'; $aOut[] = $upperPaging . $sortingBar . $results . $lowerPaging; $aOut[] = ' </div>'; // bs-extendedsearch-results-paging $aOut[] = '</div>'; // bs-extendedsearch-filters-results-paging $aOut[] = '<div id="bs-extendedsearch-results-finalizer"></div>'; $aOut[] = '<br /><br />'; } // Placeholder for SearchUsers, SearchProfiles, SearchHelpdesk etc $sOut = implode("\n", $aOut); return $sOut; }