function formatList($iStart, $iCount, $iTitleMaxLen, $defaultTemplateSuffix, $bIncludeTrim, $iTableSortCol, $updateRules, $deleteRules) { global $wgUser, $wgLang, $wgContLang; $mode = $this->mListMode; // categorypage-style list output mode if ($mode->name == 'category') { return $this->formatCategoryList($iStart, $iCount); } // other list modes $sk =& $wgUser->getSkin(); // process results of query, outputing equivalent of <li>[[Article]]</li> for each result, // or something similar if the list uses other startlist/endlist; $rBody = ''; // the following statement caused a problem with multiple columns: $this->filteredCount = 0; for ($i = $iStart; $i < $iStart + $iCount; $i++) { $article = $this->mArticles[$i]; $pagename = $article->mTitle->getPrefixedText(); $imageUrl = ''; if ($article->mNamespace == 6) { // calculate URL for existing images $img = wfFindFile($article->mTitle->getText()); if ($img && $img->exists()) { $imageUrl = $img->getURL(); $imageUrl = preg_replace('~^.*images/(.*)~', '\\1', $imageUrl); } else { $iTitle = Title::makeTitleSafe(6, $article->mTitle->getDBKey()); $imageUrl = preg_replace('~^.*images/(.*)~', '\\1', RepoGroup::singleton()->getLocalRepo()->newFile($iTitle)->getPath()); } } if ($this->mEscapeLinks && ($article->mNamespace == 14 || $article->mNamespace == 6)) { // links to categories or images need an additional ":" $pagename = ':' . $pagename; } // Page transclusion: get contents and apply selection criteria based on that contents if ($this->mIncPage) { $matchFailed = false; if (empty($this->mIncSecLabels) || $this->mIncSecLabels[0] == '*') { // include whole article $title = $article->mTitle->getPrefixedText(); if ($mode->name == 'userformat') { $incwiki = ''; } else { $incwiki = '<br />'; } $text = $this->mParser->fetchTemplate(Title::newFromText($title)); if ((count($this->mIncSecLabelsMatch) <= 0 || $this->mIncSecLabelsMatch[0] == '' || !preg_match($this->mIncSecLabelsMatch[0], $text) == false) && (count($this->mIncSecLabelsNotMatch) <= 0 || $this->mIncSecLabelsNotMatch[0] == '' || preg_match($this->mIncSecLabelsNotMatch[0], $text) == false)) { if ($this->mIncMaxLen > 0 && strlen($text) > $this->mIncMaxLen) { $text = DPLInclude::limitTranscludedText($text, $this->mIncMaxLen, ' [[' . $title . '|..→]]'); } $this->filteredCount = $this->filteredCount + 1; // update article if include=* and updaterules are given if ($updateRules != '') { $message = $this->updateArticleByRule($title, $text, $updateRules); // append update message to output $incwiki .= $message; } elseif ($deleteRules != '') { $message = $this->deleteArticleByRule($title, $text, $deleteRules); // append delete message to output $incwiki .= $message; } else { // append full text to output if (array_key_exists('0', $mode->sSectionTags)) { $incwiki .= $this->substTagParm($mode->sSectionTags[0], $pagename, $article, $imageUrl, $this->filteredCount, $iTitleMaxLen); $pieces = array(0 => $text); $this->formatSingleItems($pieces, 0, $article); $incwiki .= $pieces[0]; } else { $incwiki .= $text; } } } else { continue; } } else { // identify section pieces $secPiece = array(); $dominantPieces = false; // ONE section can be marked as "dominant"; if this section contains multiple entries // we will create a separate output row for each value of the dominant section // the values of all other columns will be repeated foreach ($this->mIncSecLabels as $s => $sSecLabel) { $sSecLabel = trim($sSecLabel); if ($sSecLabel == '') { break; } // if sections are identified by number we have a % at the beginning if ($sSecLabel[0] == '%') { $sSecLabel = '#' . $sSecLabel; } $maxlen = -1; if ($sSecLabel == '-') { // '-' is used as a dummy parameter which will produce no output // if maxlen was 0 we suppress all output; note that for matching we used the full text $secPieces = array(''); $this->formatSingleItems($secPieces, $s, $article); } elseif ($sSecLabel[0] != '{') { $limpos = strpos($sSecLabel, '['); $cutLink = 'default'; $skipPattern = array(); if ($limpos > 0 && $sSecLabel[strlen($sSecLabel) - 1] == ']') { // regular expressions which define a skip pattern may precede the text $fmtSec = explode('~', substr($sSecLabel, $limpos + 1, strlen($sSecLabel) - $limpos - 2)); $sSecLabel = substr($sSecLabel, 0, $limpos); $cutInfo = explode(' ', $fmtSec[count($fmtSec) - 1], 2); $maxlen = intval($cutInfo[0]); if (array_key_exists('1', $cutInfo)) { $cutLink = $cutInfo[1]; } foreach ($fmtSec as $skipKey => $skipPat) { if ($skipKey == count($fmtSec) - 1) { continue; } $skipPattern[] = $skipPat; } } if ($maxlen < 0) { $maxlen = -1; // without valid limit include whole section } } // find out if the user specified an includematch / includenotmatch condition if (count($this->mIncSecLabelsMatch) > $s && $this->mIncSecLabelsMatch[$s] != '') { $mustMatch = $this->mIncSecLabelsMatch[$s]; } else { $mustMatch = ''; } if (count($this->mIncSecLabelsNotMatch) > $s && $this->mIncSecLabelsNotMatch[$s] != '') { $mustNotMatch = $this->mIncSecLabelsNotMatch[$s]; } else { $mustNotMatch = ''; } // if chapters are selected by number, text or regexp we get the heading from DPLInclude::includeHeading $sectionHeading[0] = ''; if ($sSecLabel == '-') { $secPiece[$s] = $secPieces[0]; } elseif ($sSecLabel[0] == '#' || $sSecLabel[0] == '@') { $sectionHeading[0] = substr($sSecLabel, 1); // Uses DPLInclude::includeHeading() from LabeledSectionTransclusion extension to include headings from the page $secPieces = DPLInclude::includeHeading($this->mParser, $article->mTitle->getPrefixedText(), substr($sSecLabel, 1), '', $sectionHeading, false, $maxlen, $cutLink, $bIncludeTrim, $skipPattern); if ($mustMatch != '' || $mustNotMatch != '') { $secPiecesTmp = $secPieces; $offset = 0; foreach ($secPiecesTmp as $nr => $onePiece) { if ($mustMatch != '' && preg_match($mustMatch, $onePiece) == false || $mustNotMatch != '' && preg_match($mustNotMatch, $onePiece) != false) { array_splice($secPieces, $nr - $offset, 1); $offset++; } } } // if maxlen was 0 we suppress all output; note that for matching we used the full text if ($maxlen == 0) { $secPieces = array(''); } $this->formatSingleItems($secPieces, $s, $article); if (!array_key_exists(0, $secPieces)) { // avoid matching against a non-existing array element // and skip the article if there was a match condition if ($mustMatch != '' || $mustNotMatch != '') { $matchFailed = true; } break; } $secPiece[$s] = $secPieces[0]; for ($sp = 1; $sp < count($secPieces); $sp++) { if (isset($mode->aMultiSecSeparators[$s])) { $secPiece[$s] .= str_replace('%SECTION%', $sectionHeading[$sp], $this->substTagParm($mode->aMultiSecSeparators[$s], $pagename, $article, $imageUrl, $this->filteredCount, $iTitleMaxLen)); } $secPiece[$s] .= $secPieces[$sp]; } if ($mode->iDominantSection >= 0 && $s == $mode->iDominantSection && count($secPieces) > 1) { $dominantPieces = $secPieces; } if (($mustMatch != '' || $mustNotMatch != '') && count($secPieces) <= 0) { $matchFailed = true; // NOTHING MATCHED break; } } elseif ($sSecLabel[0] == '{') { // Uses DPLInclude::includeTemplate() from LabeledSectionTransclusion extension to include templates from the page // primary syntax {template}suffix $template1 = trim(substr($sSecLabel, 1, strpos($sSecLabel, '}') - 1)); $template2 = trim(str_replace('}', '', substr($sSecLabel, 1))); // alternate syntax: {template|surrogate} if ($template2 == $template1 && strpos($template1, '|') > 0) { $template1 = preg_replace('/\\|.*/', '', $template1); $template2 = preg_replace('/^.+\\|/', '', $template2); } $secPieces = DPLInclude::includeTemplate($this->mParser, $this, $s, $article, $template1, $template2, $template2 . $defaultTemplateSuffix, $mustMatch, $mustNotMatch, $this->mIncParsed, $iTitleMaxLen, implode(', ', $article->mCategoryLinks)); $secPiece[$s] = implode(isset($mode->aMultiSecSeparators[$s]) ? $this->substTagParm($mode->aMultiSecSeparators[$s], $pagename, $article, $imageUrl, $this->filteredCount, $iTitleMaxLen) : '', $secPieces); if ($mode->iDominantSection >= 0 && $s == $mode->iDominantSection && count($secPieces) > 1) { $dominantPieces = $secPieces; } if (($mustMatch != '' || $mustNotMatch != '') && count($secPieces) <= 1 && $secPieces[0] == '') { $matchFailed = true; // NOTHING MATCHED break; } } else { // Uses DPLInclude::includeSection() from LabeledSectionTransclusion extension to include labeled sections from the page $secPieces = DPLInclude::includeSection($this->mParser, $article->mTitle->getPrefixedText(), $sSecLabel, '', false, $bIncludeTrim, $skipPattern); $secPiece[$s] = implode(isset($mode->aMultiSecSeparators[$s]) ? $this->substTagParm($mode->aMultiSecSeparators[$s], $pagename, $article, $imageUrl, $this->filteredCount, $iTitleMaxLen) : '', $secPieces); if ($mode->iDominantSection >= 0 && $s == $mode->iDominantSection && count($secPieces) > 1) { $dominantPieces = $secPieces; } if ($mustMatch != '' && preg_match($mustMatch, $secPiece[$s]) == false || $mustNotMatch != '' && preg_match($mustNotMatch, $secPiece[$s]) != false) { $matchFailed = true; break; } } // separator tags if (count($mode->sSectionTags) == 1) { // If there is only one separator tag use it always $septag[$s * 2] = str_replace('%SECTION%', $sectionHeading[0], $this->substTagParm($mode->sSectionTags[0], $pagename, $article, $imageUrl, $this->filteredCount, $iTitleMaxLen)); } elseif (isset($mode->sSectionTags[$s * 2])) { $septag[$s * 2] = str_replace('%SECTION%', $sectionHeading[0], $this->substTagParm($mode->sSectionTags[$s * 2], $pagename, $article, $imageUrl, $this->filteredCount, $iTitleMaxLen)); } else { $septag[$s * 2] = ''; } if (isset($mode->sSectionTags[$s * 2 + 1])) { $septag[$s * 2 + 1] = str_replace('%SECTION%', $sectionHeading[0], $this->substTagParm($mode->sSectionTags[$s * 2 + 1], $pagename, $article, $imageUrl, $this->filteredCount, $iTitleMaxLen)); } else { $septag[$s * 2 + 1] = ''; } } // if there was a match condition on included contents which failed we skip the whole page if ($matchFailed) { continue; } $this->filteredCount = $this->filteredCount + 1; // assemble parts with separators $incwiki = ''; if ($dominantPieces != false) { foreach ($dominantPieces as $dominantPiece) { foreach ($secPiece as $s => $piece) { if ($s == $mode->iDominantSection) { $incwiki .= $this->formatItem($dominantPiece, $septag[$s * 2], $septag[$s * 2 + 1]); } else { $incwiki .= $this->formatItem($piece, $septag[$s * 2], $septag[$s * 2 + 1]); } } } } else { foreach ($secPiece as $s => $piece) { $incwiki .= $this->formatItem($piece, $septag[$s * 2], $septag[$s * 2 + 1]); } } } } else { $this->filteredCount = $this->filteredCount + 1; } if ($i > $iStart) { $rBody .= $mode->sInline; // If mode is not 'inline', sInline attribute is empty, so does nothing } // symbolic substitution of %PAGE% by the current article's name if ($mode->name == 'userformat') { $rBody .= $this->substTagParm($mode->sItemStart, $pagename, $article, $imageUrl, $this->filteredCount, $iTitleMaxLen); } else { $rBody .= $mode->sItemStart; if ($article->mDate != '') { if ($article->myDate != '') { if ($article->mRevision != '') { $rBody .= ' <html>' . $sk->makeKnownLinkObj($article->mTitle, htmlspecialchars($article->myDate), 'oldid=' . $article->mRevision) . '</html> '; } else { $rBody .= $article->myDate . ' '; } } else { if ($article->mRevision != '') { $rBody .= ' <html>' . $sk->makeKnownLinkObj($article->mTitle, htmlspecialchars($wgLang->timeanddate($article->mDate, true)), 'oldid=' . $article->mRevision) . '</html> : '; } else { $rBody .= $wgLang->timeanddate($article->mDate, true) . ': '; } } } // output the link to the article $rBody .= $article->mLink; if ($article->mSize != '' && $mode->name != 'userformat') { if (strlen($article->mSize) > 3) { $rBody .= ' [' . substr($article->mSize, 0, strlen($article->mSize) - 3) . ' kB]'; } else { $rBody .= ' [' . $article->mSize . ' B]'; } } if ($article->mCounter != '' && $mode->name != 'userformat') { // Adapted from SpecialPopularPages::formatResult() $nv = $this->msgExt('nviews', array('parsemag', 'escape'), $wgLang->formatNum($article->mCounter)); $rBody .= ' ' . $wgContLang->getDirMark() . '(' . $nv . ')'; } if ($article->mUserLink != '') { $rBody .= ' . . [[User:'******'|' . $article->mUser . ']]'; if ($article->mComment != '') { $rBody .= ' { ' . $article->mComment . ' }'; } } if ($article->mContributor != '') { $rBody .= ' . . [[User:'******'|' . $article->mContributor . " {$article->mContrib}]]"; } if (!empty($article->mCategoryLinks)) { $rBody .= ' . . <SMALL>' . wfMsg('categories') . ': ' . implode(' | ', $article->mCategoryLinks) . '</SMALL>'; } if ($this->mAddExternalLink && $article->mExternalLink != '') { $rBody .= ' → ' . $article->mExternalLink; } } // add included contents if ($this->mIncPage) { DPLInclude::open($this->mParser, $this->mParserTitle->getPrefixedText()); $rBody .= $incwiki; DPLInclude::close($this->mParser, $this->mParserTitle->getPrefixedText()); } if ($mode->name == 'userformat') { $rBody .= $this->substTagParm($mode->sItemEnd, $pagename, $article, $imageUrl, $this->filteredCount, $iTitleMaxLen); } else { $rBody .= $mode->sItemEnd; } } // if requested we sort the table by the contents of a given column if ($iTableSortCol != 0) { $sortcol = abs($iTableSortCol) + 1; $rows = explode("\n|-", $rBody); foreach ($rows as $row) { if (($word = explode("\n|", $row, $sortcol)) !== false && count($word) >= $sortcol) { $rowsKey[] = $word[$sortcol - 1]; } else { $rowsKey[] = $row; } } if ($iTableSortCol < 0) { krsort($rowsKey); } else { ksort($rowsKey); } $rows = array_combine(array_values($rowsKey), $rows); ksort($rows); $rBody = "\n|-" . join("\n|-", $rows) . "\n|-"; } // increase start value of ordered lists at multi-column output $actStart = $mode->sListStart; $start = preg_replace('/.*start=([0-9]+).*/', '\\1', $actStart); if ($start != '') { $start += $iCount; $mode->sListStart = preg_replace('/start=[0-9]+/', "start={$start}", $actStart); } return $actStart . $rBody . $mode->sListEnd; }