mirror of
https://github.com/Universal-Omega/DynamicPageList3
synced 2024-11-30 19:04:32 +00:00
DPL3 with 1.35 support
This commit is contained in:
parent
8f2e28312e
commit
e99da9ab44
395
classes/Article.php
Normal file
395
classes/Article.php
Normal file
|
@ -0,0 +1,395 @@
|
|||
<?php
|
||||
/**
|
||||
* DynamicPageList3
|
||||
* DPL Article Class
|
||||
*
|
||||
* @author IlyaHaykinson, Unendlich, Dangerville, Algorithmix, Theaitetos, Alexia E. Smith
|
||||
* @license GPL-2.0-or-later
|
||||
* @package DynamicPageList3
|
||||
*
|
||||
**/
|
||||
namespace DPL;
|
||||
|
||||
use User;
|
||||
|
||||
class Article {
|
||||
/**
|
||||
* Title
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
public $mTitle = null;
|
||||
|
||||
/**
|
||||
* Namespace ID
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mNamespace = -1;
|
||||
|
||||
/**
|
||||
* Page ID
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $mID = 0;
|
||||
|
||||
/**
|
||||
* Selected title of initial page.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mSelTitle = null;
|
||||
|
||||
/**
|
||||
* Selected namespace ID of initial page.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mSelNamespace = -1;
|
||||
|
||||
/**
|
||||
* Selected title of image.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mImageSelTitle = null;
|
||||
|
||||
/**
|
||||
* HTML link to page.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mLink = '';
|
||||
|
||||
/**
|
||||
* External link on the page.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mExternalLink = null;
|
||||
|
||||
/**
|
||||
* First character of the page title.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mStartChar = null;
|
||||
|
||||
/**
|
||||
* Heading (link to the associated page) that page belongs to in the list (default '' means no heading)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mParentHLink = ''; // heading (link to the associated page) that page belongs to in the list (default '' means no heading)
|
||||
|
||||
/**
|
||||
* Category links on the page.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $mCategoryLinks = [];
|
||||
|
||||
/**
|
||||
* Category names (without link) in the page.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $mCategoryTexts = [];
|
||||
|
||||
/**
|
||||
* Number of times this page has been viewed.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $mCounter = null;
|
||||
|
||||
/**
|
||||
* Article length in bytes of wiki text
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $mSize = null;
|
||||
|
||||
/**
|
||||
* Timestamp depending on the user's request (can be first/last edit, page_touched, ...)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mDate = null;
|
||||
|
||||
/**
|
||||
* Timestamp depending on the user's request, based on user format definition.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $myDate = null;
|
||||
|
||||
/**
|
||||
* Revision ID
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $mRevision = null;
|
||||
|
||||
/**
|
||||
* Link to editor (first/last, depending on user's request) 's page or contributions if not registered.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mUserLink = null;
|
||||
|
||||
/**
|
||||
* Name of editor (first/last, depending on user's request) or contributions if not registered.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mUser = null;
|
||||
|
||||
/**
|
||||
* Edit Summary(Revision Comment)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mComment = null;
|
||||
|
||||
/**
|
||||
* Number of bytes changed.
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
public $mContribution = 0;
|
||||
|
||||
/**
|
||||
* Short string indicating the size of a contribution.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mContrib = '';
|
||||
|
||||
/**
|
||||
* User text of who made the changes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $mContributor = null;
|
||||
|
||||
/**
|
||||
* Article Headings - Maps heading to count (# of pages under each heading).
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static private $headings = [];
|
||||
|
||||
/**
|
||||
* Main Constructor
|
||||
*
|
||||
* @access public
|
||||
* @param string Title
|
||||
* @param integer Namespace
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($title, $namespace) {
|
||||
$this->mTitle = $title;
|
||||
$this->mNamespace = $namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a new instance from a database row.
|
||||
*
|
||||
* @access public
|
||||
* @param array Database Row
|
||||
* @param object \DPL\Parameters Object
|
||||
* @param object Mediawiki Title Object
|
||||
* @param integer Page Namespace ID
|
||||
* @param string Page Title as Selected from Query
|
||||
* @return object \DPL\Article Object
|
||||
*/
|
||||
public static function newFromRow($row, Parameters $parameters, \Title $title, $pageNamespace, $pageTitle) {
|
||||
global $wgLang, $wgContLang;
|
||||
|
||||
$article = new Article($title, $pageNamespace);
|
||||
$revActorName = User::newFromActorId( $row['rev_actor'] )->getName();
|
||||
|
||||
$titleText = $title->getText();
|
||||
if ($parameters->getParameter('shownamespace') === true) {
|
||||
$titleText = $title->getPrefixedText();
|
||||
}
|
||||
$replaceInTitle = $parameters->getParameter('replaceintitle');
|
||||
if (is_array($replaceInTitle) && count($replaceInTitle) === 2) {
|
||||
$titleText = preg_replace($replaceInTitle[0], $replaceInTitle[1], $titleText);
|
||||
}
|
||||
|
||||
//Chop off title if longer than the 'titlemaxlen' parameter.
|
||||
if ($parameters->getParameter('titlemaxlen') !== null && strlen($titleText) > $parameters->getParameter('titlemaxlen')) {
|
||||
$titleText = substr($titleText, 0, $parameters->getParameter('titlemaxlen')) . '...';
|
||||
}
|
||||
if ($parameters->getParameter('showcurid') === true && isset($row['page_id'])) {
|
||||
$articleLink = '[' . $title->getLinkURL(['curid' => $row['page_id']]) . ' ' . htmlspecialchars($titleText) . ']';
|
||||
} else {
|
||||
$articleLink = '[[' . ($parameters->getParameter('escapelinks') && ($pageNamespace == NS_CATEGORY || $pageNamespace == NS_FILE) ? ':' : '') . $title->getFullText() . '|' . htmlspecialchars($titleText) . ']]';
|
||||
}
|
||||
|
||||
$article->mLink = $articleLink;
|
||||
|
||||
//get first char used for category-style output
|
||||
if (isset($row['sortkey'])) {
|
||||
$article->mStartChar = $wgContLang->convert($wgContLang->firstChar($row['sortkey']));
|
||||
} else {
|
||||
$article->mStartChar = $wgContLang->convert($wgContLang->firstChar($pageTitle));
|
||||
}
|
||||
|
||||
$article->mID = intval($row['page_id']);
|
||||
|
||||
//External link
|
||||
if (isset($row['el_to'])) {
|
||||
$article->mExternalLink = $row['el_to'];
|
||||
}
|
||||
|
||||
//SHOW PAGE_COUNTER
|
||||
if (isset($row['page_counter'])) {
|
||||
$article->mCounter = intval($row['page_counter']);
|
||||
}
|
||||
|
||||
//SHOW PAGE_SIZE
|
||||
if (isset($row['page_len'])) {
|
||||
$article->mSize = intval($row['page_len']);
|
||||
}
|
||||
//STORE initially selected PAGE
|
||||
if (is_array($parameters->getParameter('linksto')) && (count($parameters->getParameter('linksto')) || count($parameters->getParameter('linksfrom')))) {
|
||||
if (!isset($row['sel_title'])) {
|
||||
$article->mSelTitle = 'unknown page';
|
||||
$article->mSelNamespace = 0;
|
||||
} else {
|
||||
$article->mSelTitle = $row['sel_title'];
|
||||
$article->mSelNamespace = $row['sel_ns'];
|
||||
}
|
||||
}
|
||||
|
||||
//STORE selected image
|
||||
if (is_array($parameters->getParameter('imageused')) && count($parameters->getParameter('imageused')) > 0) {
|
||||
if (!isset($row['image_sel_title'])) {
|
||||
$article->mImageSelTitle = 'unknown image';
|
||||
} else {
|
||||
$article->mImageSelTitle = $row['image_sel_title'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($parameters->getParameter('goal') != 'categories') {
|
||||
//REVISION SPECIFIED
|
||||
if ($parameters->getParameter('lastrevisionbefore') || $parameters->getParameter('allrevisionsbefore') || $parameters->getParameter('firstrevisionsince') || $parameters->getParameter('allrevisionssince')) {
|
||||
$article->mRevision = $row['rev_id'];
|
||||
$article->mUser = $revActorName;
|
||||
$article->mDate = $row['rev_timestamp'];
|
||||
$article->mComment = $row['rev_comment_id'];
|
||||
}
|
||||
|
||||
//SHOW "PAGE_TOUCHED" DATE, "FIRSTCATEGORYDATE" OR (FIRST/LAST) EDIT DATE
|
||||
if ($parameters->getParameter('addpagetoucheddate')) {
|
||||
$article->mDate = $row['page_touched'];
|
||||
} elseif ($parameters->getParameter('addfirstcategorydate')) {
|
||||
$article->mDate = $row['cl_timestamp'];
|
||||
} elseif ($parameters->getParameter('addeditdate') && isset($row['rev_timestamp'])) {
|
||||
$article->mDate = $row['rev_timestamp'];
|
||||
} elseif ($parameters->getParameter('addeditdate') && isset($row['page_touched'])) {
|
||||
$article->mDate = $row['page_touched'];
|
||||
}
|
||||
|
||||
//Time zone adjustment
|
||||
if ($article->mDate) {
|
||||
$article->mDate = $wgLang->userAdjust($article->mDate);
|
||||
}
|
||||
|
||||
if ($article->mDate && $parameters->getParameter('userdateformat')) {
|
||||
//Apply the userdateformat
|
||||
$article->myDate = gmdate($parameters->getParameter('userdateformat'), wfTimeStamp(TS_UNIX, $article->mDate));
|
||||
}
|
||||
// CONTRIBUTION, CONTRIBUTOR
|
||||
if ($parameters->getParameter('addcontribution')) {
|
||||
$article->mContribution = $row['contribution'];
|
||||
$article->mContributor = User::newFromActorId( $row['contributor'] )->getName();
|
||||
$article->mContrib = substr('*****************', 0, (int) round(log($row['contribution'])));
|
||||
}
|
||||
|
||||
//USER/AUTHOR(S)
|
||||
// because we are going to do a recursive parse at the end of the output phase
|
||||
// we have to generate wiki syntax for linking to a user´s homepage
|
||||
if ($parameters->getParameter('adduser') || $parameters->getParameter('addauthor') || $parameters->getParameter('addlasteditor')) {
|
||||
$article->mUserLink = '[[User:' . $revActorName . '|' . $revActorName . ']]';
|
||||
$article->mUser = $revActorName;
|
||||
}
|
||||
|
||||
//CATEGORY LINKS FROM CURRENT PAGE
|
||||
if ($parameters->getParameter('addcategories') && ($row['cats'])) {
|
||||
$artCatNames = explode(' | ', $row['cats']);
|
||||
foreach ($artCatNames as $artCatName) {
|
||||
$article->mCategoryLinks[] = '[[:Category:' . $artCatName . '|' . str_replace('_', ' ', $artCatName) . ']]';
|
||||
$article->mCategoryTexts[] = str_replace('_', ' ', $artCatName);
|
||||
}
|
||||
}
|
||||
// PARENT HEADING (category of the page, editor (user) of the page, etc. Depends on ordermethod param)
|
||||
if ($parameters->getParameter('headingmode') != 'none') {
|
||||
switch ($parameters->getParameter('ordermethod')[0]) {
|
||||
case 'category':
|
||||
//Count one more page in this heading
|
||||
self::$headings[$row['cl_to']] = (isset(self::$headings[$row['cl_to']]) ? self::$headings[$row['cl_to']] + 1 : 1);
|
||||
if ($row['cl_to'] == '') {
|
||||
//uncategorized page (used if ordermethod=category,...)
|
||||
$article->mParentHLink = '[[:Special:Uncategorizedpages|' . wfMessage('uncategorizedpages') . ']]';
|
||||
} else {
|
||||
$article->mParentHLink = '[[:Category:' . $row['cl_to'] . '|' . str_replace('_', ' ', $row['cl_to']) . ']]';
|
||||
}
|
||||
break;
|
||||
case 'user':
|
||||
self::$headings[$revActorName] = (isset(self::$headings[$revActorName]) ? self::$headings[$revActorName] + 1 : 1);
|
||||
if ($row['rev_actor'] == 0) { //anonymous user
|
||||
$article->mParentHLink = '[[User:' . $revActorName . '|' . $revActorName . ']]';
|
||||
} else {
|
||||
$article->mParentHLink = '[[User:' . $revActorName . '|' . $revActorName . ']]';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $article;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all heading information processed from all newly instantiated article objects.
|
||||
*
|
||||
* @access public
|
||||
* @return array Headings
|
||||
*/
|
||||
public static function getHeadings() {
|
||||
return self::$headings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the headings to their initial state.
|
||||
* Ideally this Article class should not exist and be handled by the built in MediaWiki class.
|
||||
* Bug: https://jira/browse/HYD-913
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public static function resetHeadings() {
|
||||
self::$headings = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted date for this article if available.
|
||||
*
|
||||
* @access public
|
||||
* @return mixed Formatted string or null for none set.
|
||||
*/
|
||||
public function getDate() {
|
||||
global $wgLang;
|
||||
if ($this->myDate !== null) {
|
||||
return $this->myDate;
|
||||
} elseif ($this->mDate !== null) {
|
||||
return $wgLang->timeanddate($article->mDate, true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
77
classes/Config.php
Normal file
77
classes/Config.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
/**
|
||||
* DynamicPageList3
|
||||
* DPL Config Class
|
||||
*
|
||||
* @author IlyaHaykinson, Unendlich, Dangerville, Algorithmix, Theaitetos, Alexia E. Smith
|
||||
* @license GPL-2.0-or-later
|
||||
* @package DynamicPageList3
|
||||
*
|
||||
**/
|
||||
namespace DPL;
|
||||
|
||||
class Config {
|
||||
/**
|
||||
* Configuration Settings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static private $settings = [];
|
||||
|
||||
/**
|
||||
* Initialize the static object with settings.
|
||||
*
|
||||
* @access public
|
||||
* @param array Settings to initialize for DPL.
|
||||
* @return void
|
||||
*/
|
||||
public static function init($settings = false) {
|
||||
if ($settings === false) {
|
||||
global $wgDplSettings;
|
||||
|
||||
$settings = $wgDplSettings;
|
||||
}
|
||||
|
||||
if (!is_array($settings)) {
|
||||
throw new MWException(__METHOD__ . ": Invalid settings passed.");
|
||||
}
|
||||
|
||||
self::$settings = array_merge(self::$settings, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a single setting.
|
||||
*
|
||||
* @access public
|
||||
* @param string Setting Key
|
||||
* @return mixed The setting's actual setting or null if it does not exist.
|
||||
*/
|
||||
public static function getSetting($setting) {
|
||||
return (array_key_exists($setting, self::$settings) ? self::$settings[$setting] : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a all settings.
|
||||
*
|
||||
* @access public
|
||||
* @return array All settings
|
||||
*/
|
||||
public static function getAllSettings() {
|
||||
return self::$settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a single setting.
|
||||
*
|
||||
* @access public
|
||||
* @param string Setting Key
|
||||
* @param mixed [Optional] Appropriate value for the setting key.
|
||||
* @return void
|
||||
*/
|
||||
public static function setSetting($setting, $value = null) {
|
||||
if (empty($setting) || !is_string($setting)) {
|
||||
throw new MWException(__METHOD__ . ": Setting keys can not be blank.");
|
||||
}
|
||||
self::$settings[$setting] = $value;
|
||||
}
|
||||
}
|
718
classes/LST.php
Normal file
718
classes/LST.php
Normal file
|
@ -0,0 +1,718 @@
|
|||
<?php
|
||||
/**
|
||||
* This is a modified and enhanced copy of a mediawiki extension called
|
||||
*
|
||||
* LabeledSectionTransclusion
|
||||
*
|
||||
* @link http://www.mediawiki.org/wiki/Extension:Labeled_Section_Transclusion Documentation
|
||||
*
|
||||
*
|
||||
* @author Steve Sanbeg
|
||||
* @copyright Copyright © 2006, Steve Sanbeg
|
||||
* @license GPL-2.0-or-later
|
||||
*
|
||||
*
|
||||
* This copy was made to avoid version conflicts between the two extensions.
|
||||
* In this copy names were changed (wfLst.. --> wfDplLst..).
|
||||
* So any version of LabeledSectionTransclusion can be installed together with DPL
|
||||
*
|
||||
* Enhancements were made to
|
||||
* - allow inclusion of templates ("template swapping")
|
||||
* - reduce the size of the transcluded text to a limit of <n> characters
|
||||
*
|
||||
*
|
||||
* Thanks to Steve for his great work!
|
||||
* -- Algorithmix
|
||||
*/
|
||||
namespace DPL;
|
||||
|
||||
use DPL\Lister\Lister;
|
||||
|
||||
class LST {
|
||||
##############################################################
|
||||
# To do transclusion from an extension, we need to interact with the parser
|
||||
# at a low level. This is the general transclusion functionality
|
||||
##############################################################
|
||||
|
||||
/**
|
||||
* Register what we're working on in the parser, so we don't fall into a trap.
|
||||
* @param $parser Parser
|
||||
* @param $part1
|
||||
* @return bool
|
||||
*/
|
||||
public static function open($parser, $part1) {
|
||||
// Infinite loop test
|
||||
if (isset($parser->mTemplatePath[$part1])) {
|
||||
wfDebug(__METHOD__ . ": template loop broken at '$part1'\n");
|
||||
return false;
|
||||
} else {
|
||||
$parser->mTemplatePath[$part1] = 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish processing the function.
|
||||
* @param $parser Parser
|
||||
* @param $part1
|
||||
* @return bool
|
||||
*/
|
||||
public static function close($parser, $part1) {
|
||||
// Infinite loop test
|
||||
if (isset($parser->mTemplatePath[$part1])) {
|
||||
unset($parser->mTemplatePath[$part1]);
|
||||
} else {
|
||||
wfDebug(__METHOD__ . ": close unopened template loop at '$part1'\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle recursive substitution here, so we can break cycles, and set up
|
||||
* return values so that edit sections will resolve correctly.
|
||||
**/
|
||||
private static function parse($parser, $title, $text, $part1, $skiphead = 0, $recursionCheck = true, $maxLength = -1, $link = '', $trim = false, $skipPattern = []) {
|
||||
// if someone tries something like<section begin=blah>lst only</section>
|
||||
// text, may as well do the right thing.
|
||||
$text = str_replace('</section>', '', $text);
|
||||
|
||||
// if desired we remove portions of the text, esp. template calls
|
||||
foreach ($skipPattern as $skipPat) {
|
||||
$text = preg_replace($skipPat, '', $text);
|
||||
}
|
||||
|
||||
if (self::open($parser, $part1)) {
|
||||
|
||||
//Handle recursion here, so we can break cycles.
|
||||
if ($recursionCheck == false) {
|
||||
$text = $parser->preprocess($text, $parser->mTitle, $parser->mOptions);
|
||||
self::close($parser, $part1);
|
||||
}
|
||||
|
||||
if ($maxLength > 0) {
|
||||
$text = self::limitTranscludedText($text, $maxLength, $link);
|
||||
}
|
||||
if ($trim) {
|
||||
return trim($text);
|
||||
} else {
|
||||
return $text;
|
||||
}
|
||||
} else {
|
||||
return "[[" . $title->getPrefixedText() . "]]" . "<!-- WARNING: LST loop detected -->";
|
||||
}
|
||||
}
|
||||
|
||||
##############################################################
|
||||
# And now, the labeled section transclusion
|
||||
##############################################################
|
||||
|
||||
/**
|
||||
* Parser tag hook for <section>.
|
||||
* The section markers aren't paired, so we only need to remove them.
|
||||
*
|
||||
* @param string $in
|
||||
* @param array $assocArgs
|
||||
* @param Parser $parser
|
||||
* @return string HTML output
|
||||
*/
|
||||
private static function noop($in, $assocArgs = [], $parser = null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
///Generate a regex to match the section(s) we're interested in.
|
||||
private static function createSectionPattern($sec, $to, &$any) {
|
||||
$any = false;
|
||||
$to_sec = ($to == '') ? $sec : $to;
|
||||
if ($sec[0] == '*') {
|
||||
$any = true;
|
||||
if ($sec == '**') {
|
||||
$sec = '[^\/>"' . "']+";
|
||||
} else {
|
||||
$sec = str_replace('/', '\/', substr($sec, 1));
|
||||
}
|
||||
} else {
|
||||
$sec = preg_quote($sec, '/');
|
||||
}
|
||||
if ($to_sec[0] == '*') {
|
||||
if ($to_sec == '**') {
|
||||
$to_sec = '[^\/>"' . "']+";
|
||||
} else {
|
||||
$to_sec = str_replace('/', '\/', substr($to_sec, 1));
|
||||
}
|
||||
} else {
|
||||
$to_sec = preg_quote($to_sec, '/');
|
||||
}
|
||||
$ws = "(?:\s+[^>]+)?"; //was like $ws="\s*"
|
||||
return "/<section$ws\s+(?i:begin)=['\"]?" . "($sec)" . "['\"]?$ws\/?>(.*?)\n?<section$ws\s+(?:[^>]+\s+)?(?i:end)=" . "['\"]?\\1['\"]?" . "$ws\/?>/s";
|
||||
}
|
||||
|
||||
/**
|
||||
* Count headings in skipped text.
|
||||
*
|
||||
* Count skipped headings, so parser (as of r18218) can skip them, to
|
||||
* prevent wrong heading links (see bug 6563).
|
||||
*
|
||||
* @param string $text
|
||||
* @param int $limit Cutoff point in the text to stop searching
|
||||
* @return int Number of matches
|
||||
* @private
|
||||
*/
|
||||
private static function countHeadings($text, $limit) {
|
||||
$pat = '^(={1,6}).+\1\s*$()';
|
||||
|
||||
$count = 0;
|
||||
$offset = 0;
|
||||
$m = [];
|
||||
while (preg_match("/$pat/im", $text, $m, PREG_OFFSET_CAPTURE, $offset)) {
|
||||
if ($m[2][1] > $limit) {
|
||||
break;
|
||||
}
|
||||
|
||||
$count++;
|
||||
$offset = $m[2][1];
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
public static function text($parser, $page, &$title, &$text) {
|
||||
$title = \Title::newFromText($page);
|
||||
|
||||
if (is_null($title)) {
|
||||
$text = '';
|
||||
return true;
|
||||
} else {
|
||||
$text = $parser->fetchTemplate($title);
|
||||
}
|
||||
|
||||
//if article doesn't exist, return a red link.
|
||||
if ($text == false) {
|
||||
$text = "[[" . $title->getPrefixedText() . "]]";
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
///section inclusion - include all matching sections
|
||||
public static function includeSection($parser, $page = '', $sec = '', $to = '', $recursionCheck = true, $trim = false, $skipPattern = []) {
|
||||
$output = [];
|
||||
if (self::text($parser, $page, $title, $text) == false) {
|
||||
$output[] = $text;
|
||||
return $output;
|
||||
}
|
||||
$any = false;
|
||||
$pat = self::createSectionPattern($sec, $to, $any);
|
||||
|
||||
preg_match_all($pat, $text, $m, PREG_PATTERN_ORDER);
|
||||
|
||||
foreach ($m[2] as $nr => $piece) {
|
||||
$piece = self::parse($parser, $title, $piece, "#lst:${page}|${sec}", 0, $recursionCheck, $trim, $skipPattern);
|
||||
if ($any) {
|
||||
$output[] = $m[1][$nr] . '::' . $piece;
|
||||
} else {
|
||||
$output[] = $piece;
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate a portion of wikitext so that ..
|
||||
* ... does not contain (open) html comments
|
||||
* ... it is not larger that $lim characters
|
||||
* ... it is balanced in terms of braces, brackets and tags
|
||||
* ... it is cut at a word boundary (white space) if possible
|
||||
* ... can be used as content of a wikitable field without spoiling the whole surrounding wikitext structure
|
||||
* @param $lim limit of character count for the result
|
||||
* @param $text the wikitext to be truncated
|
||||
* @param $link an optional link which will be appended to the text if it was truncatedt
|
||||
* @return the truncated text;
|
||||
* note that the returned text may be longer than the limit if this is necessary
|
||||
* to return something at all. We do not want to return an empty string if the input is not empty
|
||||
* if the text is already shorter than the limit, the text
|
||||
* will be returned without any checks for balance of tags
|
||||
*/
|
||||
public static function limitTranscludedText($text, $limit, $link = '') {
|
||||
// if text is smaller than limit return complete text
|
||||
if ($limit >= strlen($text)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
// otherwise strip html comments and check again
|
||||
$text = preg_replace('/<!--.*?-->/s', '', $text);
|
||||
if ($limit >= strlen($text)) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
// search latest position with balanced brackets/braces
|
||||
// store also the position of the last preceding space
|
||||
|
||||
$brackets = 0;
|
||||
$cbrackets = 0;
|
||||
$n0 = -1;
|
||||
$nb = 0;
|
||||
for ($i = 0; $i < $limit; $i++) {
|
||||
$c = $text[$i];
|
||||
if ($c == '[') {
|
||||
$brackets++;
|
||||
}
|
||||
if ($c == ']') {
|
||||
$brackets--;
|
||||
}
|
||||
if ($c == '{') {
|
||||
$cbrackets++;
|
||||
}
|
||||
if ($c == '}') {
|
||||
$cbrackets--;
|
||||
}
|
||||
// we store the position if it is valid in terms of parentheses balancing
|
||||
if ($brackets == 0 && $cbrackets == 0) {
|
||||
$n0 = $i;
|
||||
if ($c == ' ') {
|
||||
$nb = $i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there is a valid cut-off point we use it; it will be the largest one which is not above the limit
|
||||
if ($n0 >= 0) {
|
||||
// we try to cut off at a word boundary, this may lead to a shortening of max. 15 chars
|
||||
if ($nb > 0 && $nb + 15 > $n0) {
|
||||
$n0 = $nb;
|
||||
}
|
||||
$cut = substr($text, 0, $n0 + 1);
|
||||
|
||||
// an open html comment would be fatal, but this should not happen as we already have
|
||||
// eliminated html comments at the beginning
|
||||
|
||||
// some tags are critical: ref, pre, nowiki
|
||||
// if these tags were not balanced they would spoil the result completely
|
||||
// we enforce balance by appending the necessary amount of corresponding closing tags
|
||||
// currently we ignore the nesting, i.e. all closing tags are appended at the end.
|
||||
// This simple approach may fail in some cases ...
|
||||
|
||||
$matches = [];
|
||||
$noMatches = preg_match_all('#<\s*(/?ref|/?pre|/?nowiki)(\s+[^>]*?)*>#im', $cut, $matches);
|
||||
$tags = [
|
||||
'ref' => 0,
|
||||
'pre' => 0,
|
||||
'nowiki' => 0
|
||||
];
|
||||
|
||||
if ($noMatches > 0) {
|
||||
// calculate tag count (ignoring nesting)
|
||||
foreach ($matches[1] as $mm) {
|
||||
if ($mm[0] == '/') {
|
||||
$tags[substr($mm, 1)]--;
|
||||
} else {
|
||||
$tags[$mm]++;
|
||||
}
|
||||
}
|
||||
// append missing closing tags - should the tags be ordered by precedence ?
|
||||
foreach ($tags as $tagName => $level) {
|
||||
while ($level > 0) {
|
||||
// avoid empty ref tag
|
||||
if ($tagName == 'ref' && substr($cut, strlen($cut) - 5) == '<ref>') {
|
||||
$cut = substr($cut, 0, strlen($cut) - 5);
|
||||
} else {
|
||||
$cut .= '</' . $tagName . '>';
|
||||
}
|
||||
$level--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $cut . $link;
|
||||
} elseif ($limit == 0) {
|
||||
return $link;
|
||||
} else {
|
||||
// otherwise we recurse and try again with twice the limit size; this will lead to bigger output but
|
||||
// it will at least produce some output at all; otherwise the reader might think that there
|
||||
// is no information at all
|
||||
return self::limitTranscludedText($text, $limit * 2, $link);
|
||||
}
|
||||
}
|
||||
|
||||
public static function includeHeading($parser, $page = '', $sec = '', $to = '', &$sectionHeading, $recursionCheck = true, $maxLength = -1, $link = 'default', $trim = false, $skipPattern = []) {
|
||||
$output = [];
|
||||
if (self::text($parser, $page, $title, $text) == false) {
|
||||
$output[0] = $text;
|
||||
return $output;
|
||||
}
|
||||
/* throw away comments */
|
||||
$text = preg_replace('/<!--.*?-->/s', '', $text);
|
||||
return self::extractHeadingFromText($parser, $page, $title, $text, $sec, $to, $sectionHeading, $recursionCheck, $maxLength, $link, $trim, $skipPattern);
|
||||
}
|
||||
|
||||
//section inclusion - include all matching sections (return array)
|
||||
public static function extractHeadingFromText($parser, $page, $title, $text, $sec = '', $to = '', &$sectionHeading, $recursionCheck = true, $maxLength = -1, $cLink = 'default', $trim = false, $skipPattern = []) {
|
||||
$continueSearch = true;
|
||||
$n = 0;
|
||||
$output[$n] = '';
|
||||
$nr = 0;
|
||||
// check if we are going to fetch the n-th section
|
||||
if (preg_match('/^%-?[1-9][0-9]*$/', $sec)) {
|
||||
$nr = substr($sec, 1);
|
||||
}
|
||||
if (preg_match('/^%0$/', $sec)) {
|
||||
$nr = -2; // transclude text before the first section
|
||||
}
|
||||
|
||||
// if the section name starts with a # or with a @ we use it as regexp, otherwise as plain string
|
||||
$isPlain = true;
|
||||
if ($sec != '' && ($sec[0] == '#' || $sec[0] == '@')) {
|
||||
$sec = substr($sec, 1);
|
||||
$isPlain = false;
|
||||
}
|
||||
do {
|
||||
//Generate a regex to match the === classical heading section(s) === we're
|
||||
//interested in.
|
||||
$headLine = '';
|
||||
if ($sec == '') {
|
||||
$begin_off = 0;
|
||||
$head_len = 6;
|
||||
} else {
|
||||
if ($nr != 0) {
|
||||
$pat = '^(={1,6})\s*[^=\s\n][^\n=]*\s*\1\s*($)';
|
||||
} elseif ($isPlain) {
|
||||
$pat = '^(={1,6})\s*' . preg_quote($sec, '/') . '\s*\1\s*($)';
|
||||
} else {
|
||||
$pat = '^(={1,6})\s*' . str_replace('/', '\/', $sec) . '\s*\1\s*($)';
|
||||
}
|
||||
if (preg_match("/$pat/im", $text, $m, PREG_OFFSET_CAPTURE)) {
|
||||
$mata = [];
|
||||
$no_parenthesis = preg_match_all('/\(/', $pat, $mata);
|
||||
$begin_off = $m[$no_parenthesis][1];
|
||||
$head_len = strlen($m[1][0]);
|
||||
$headLine = trim($m[0][0], "\n =\t");
|
||||
} elseif ($nr == -2) {
|
||||
$m[1][1] = strlen($text) + 1; // take whole article if no heading found
|
||||
} else {
|
||||
// match failed
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
// create a link symbol (arrow, img, ...) in case we have to cut the text block to maxLength
|
||||
$link = $cLink;
|
||||
if ($link == 'default') {
|
||||
$link = ' [[' . $page . '#' . $headLine . '|..→]]';
|
||||
} elseif (strstr($link, 'img=') != false) {
|
||||
$link = str_replace('img=', "<linkedimage>page=" . $page . '#' . $headLine . "\nimg=Image:", $link) . "\n</linkedimage>";
|
||||
} elseif (strstr($link, '%SECTION%') == false) {
|
||||
$link = ' [[' . $page . '#' . $headLine . '|' . $link . ']]';
|
||||
} else {
|
||||
$link = str_replace('%SECTION%', $page . '#' . $headLine, $link);
|
||||
}
|
||||
if ($nr == -2) {
|
||||
// output text before first section and done
|
||||
$piece = substr($text, 0, $m[1][1] - 1);
|
||||
$output[0] = self::parse($parser, $title, $piece, "#lsth:${page}|${sec}", 0, $recursionCheck, $maxLength, $link, $trim, $skipPattern);
|
||||
return $output;
|
||||
}
|
||||
|
||||
if (isset($end_off)) {
|
||||
unset($end_off);
|
||||
}
|
||||
if ($to != '') {
|
||||
//if $to is supplied, try and match it. If we don't match, just ignore it.
|
||||
if ($isPlain) {
|
||||
$pat = '^(={1,6})\s*' . preg_quote($to, '/') . '\s*\1\s*$';
|
||||
} else {
|
||||
$pat = '^(={1,6})\s*' . str_replace('/', '\/', $to) . '\s*\1\s*$';
|
||||
}
|
||||
if (preg_match("/$pat/im", $text, $mm, PREG_OFFSET_CAPTURE, $begin_off)) {
|
||||
$end_off = $mm[0][1] - 1;
|
||||
}
|
||||
}
|
||||
if (!isset($end_off)) {
|
||||
if ($nr != 0) {
|
||||
$pat = '^(={1,6})\s*[^\s\n=][^\n=]*\s*\1\s*$';
|
||||
} else {
|
||||
$pat = '^(={1,' . $head_len . '})(?!=)\s*.*?\1\s*$';
|
||||
}
|
||||
if (preg_match("/$pat/im", $text, $mm, PREG_OFFSET_CAPTURE, $begin_off)) {
|
||||
$end_off = $mm[0][1] - 1;
|
||||
} elseif ($sec == '') {
|
||||
$end_off = -1;
|
||||
}
|
||||
}
|
||||
|
||||
$nhead = self::countHeadings($text, $begin_off);
|
||||
wfDebug("LSTH: head offset = $nhead");
|
||||
|
||||
if (isset($end_off)) {
|
||||
if ($end_off == -1) {
|
||||
return $output;
|
||||
}
|
||||
$piece = substr($text, $begin_off, $end_off - $begin_off);
|
||||
if ($sec == '') {
|
||||
$continueSearch = false;
|
||||
} else {
|
||||
$text = substr($text, $end_off);
|
||||
}
|
||||
} else {
|
||||
$piece = substr($text, $begin_off);
|
||||
$continueSearch = false;
|
||||
}
|
||||
|
||||
if ($nr > 1) {
|
||||
// skip until we reach the n-th section
|
||||
$nr--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($m[0][0])) {
|
||||
$sectionHeading[$n] = $headLine;
|
||||
//$sectionHeading[$n]=preg_replace("/^=+\s*/","",$m[0][0]);
|
||||
//$sectionHeading[$n]=preg_replace("/\s*=+\s*$/","",$sectionHeading[$n]);
|
||||
} else {
|
||||
// $sectionHeading[$n] = '';
|
||||
$sectionHeading[0] = $headLine;
|
||||
}
|
||||
|
||||
if ($nr == 1) {
|
||||
// output n-th section and done
|
||||
$output[0] = self::parse($parser, $title, $piece, "#lsth:${page}|${sec}", $nhead, $recursionCheck, $maxLength, $link, $trim, $skipPattern);
|
||||
break;
|
||||
}
|
||||
if ($nr == -1) {
|
||||
if (!isset($end_off)) {
|
||||
// output last section and done
|
||||
$output[0] = self::parse($parser, $title, $piece, "#lsth:${page}|${sec}", $nhead, $recursionCheck, $maxLength, $link, $trim, $skipPattern);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// output section by name and continue search for another section with the same name
|
||||
$output[$n++] = self::parse($parser, $title, $piece, "#lsth:${page}|${sec}", $nhead, $recursionCheck, $maxLength, $link, $trim, $skipPattern);
|
||||
}
|
||||
} while ($continueSearch);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
// template inclusion - find the place(s) where template1 is called,
|
||||
// replace its name by template2, then expand template2 and return the result
|
||||
// we return an array containing all occurences of the template call which match the condition "$mustMatch"
|
||||
// and do NOT match the condition "$mustNotMatch" (if specified)
|
||||
// we use a callback function to format retrieved parameters, accessible via $lister->formatTemplateArg()
|
||||
public static function includeTemplate($parser, Lister $lister, $dplNr, $article, $template1 = '', $template2 = '', $defaultTemplate, $mustMatch, $mustNotMatch, $matchParsed, $catlist) {
|
||||
$page = $article->mTitle->getPrefixedText();
|
||||
$date = $article->myDate;
|
||||
$user = $article->mUserLink;
|
||||
$title = \Title::newFromText($page);
|
||||
/* get text and throw away html comments */
|
||||
$text = preg_replace('/<!--.*?-->/s', '', $parser->fetchTemplate($title));
|
||||
|
||||
if ($template1 != '' && $template1[0] == '#') {
|
||||
// --------------------------------------------- looking for a parser function call
|
||||
$template1 = substr($template1, 1);
|
||||
$template2 = substr($template2, 1);
|
||||
$defaultTemplate = substr($defaultTemplate, 1);
|
||||
// when looking for parser function calls we accept regexp search patterns
|
||||
$text2 = preg_replace("/\{\{\s*#(" . $template1 . ')(\s*[:}])/i', '°³²|%PFUNC%=\1\2|', $text);
|
||||
$tCalls = preg_split('/°³²/', ' ' . $text2);
|
||||
foreach ($tCalls as $i => $tCall) {
|
||||
if (($n = strpos($tCall, ':')) !== false) {
|
||||
$tCalls[$i][$n] = ' ';
|
||||
}
|
||||
}
|
||||
} elseif ($template1 != '' && $template1[0] == '~') {
|
||||
// --------------------------------------------- looking for an xml-tag extension call
|
||||
$template1 = substr($template1, 1);
|
||||
$template2 = substr($template2, 1);
|
||||
$defaultTemplate = substr($defaultTemplate, 1);
|
||||
// looking for tags
|
||||
$text2 = preg_replace('/\<\s*(' . $template1 . ')\s*\>/i', '°³²|%TAG%=\1|%TAGBODY%=', $text);
|
||||
$tCalls = preg_split('/°³²/', ' ' . $text2);
|
||||
foreach ($tCalls as $i => $tCall) {
|
||||
$tCalls[$i] = preg_replace('/\<\s*\/' . $template1 . '\s*\>.*/is', '}}', $tCall);
|
||||
}
|
||||
} else {
|
||||
// --------------------------------------------- looking for template call
|
||||
// we accept plain text as a template name, space or underscore are the same
|
||||
// the localized name for "Template:" may preceed the template name
|
||||
// the name may start with a different namespace for the surrogate template, followed by ::
|
||||
global $wgContLang;
|
||||
$nsNames = $wgContLang->getNamespaces();
|
||||
$tCalls = preg_split('/\{\{\s*(Template:|' . $nsNames[10] . ':)?' . self::spaceOrUnderscore(preg_quote($template1, '/')) . '\s*[|}]/i', ' ' . $text);
|
||||
// We restore the first separator symbol (we had to include that symbol into the SPLIT, because we must make
|
||||
// sure that we only accept exact matches of the complete template name
|
||||
// (e.g. when looking for "foo" we must not accept "foo xyz")
|
||||
foreach ($tCalls as $nr => $tCall) {
|
||||
if ($tCall[0] == '}') {
|
||||
$tCalls[$nr] = '}' . $tCall;
|
||||
} else {
|
||||
$tCalls[$nr] = '|' . $tCall;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output = [];
|
||||
$extractParm = [];
|
||||
|
||||
// check if we want to extract parameters directly from the call
|
||||
// in that case we won´t invoke template2 but will directly return the extracted parameters
|
||||
// as a sequence of table columns;
|
||||
if (strlen($template2) > strlen($template1) && substr($template2, 0, strlen($template1) + 1) == ($template1 . ':')) {
|
||||
$extractParm = preg_split('/:\s*/s', trim(substr($template2, strlen($template1) + 1)));
|
||||
}
|
||||
|
||||
if (count($tCalls) <= 1) {
|
||||
// template was not called (note that count will be 1 if there is no template invocation)
|
||||
if (count($extractParm) > 0) {
|
||||
// if parameters are required directly: return empty columns
|
||||
if (count($extractParm) > 1) {
|
||||
$output[0] = $lister->formatTemplateArg('', $dplNr, 0, true, -1, $article);
|
||||
for ($i = 1; $i < count($extractParm); $i++) {
|
||||
$output[0] .= "\n|" . $lister->formatTemplateArg('', $dplNr, $i, true, -1, $article);
|
||||
}
|
||||
} else {
|
||||
$output[0] = $lister->formatTemplateArg('', $dplNr, 0, true, -1, $article);
|
||||
}
|
||||
} else {
|
||||
// put a red link into the output
|
||||
$output[0] = $parser->preprocess('{{' . $defaultTemplate . '|%PAGE%=' . $page . '|%TITLE%=' . $title->getText() . '|%DATE%=' . $date . '|%USER%=' . $user . '}}', $parser->mTitle, $parser->mOptions);
|
||||
}
|
||||
unset($title);
|
||||
return $output;
|
||||
}
|
||||
|
||||
$output[0] = '';
|
||||
$n = -2;
|
||||
// loop for all template invocations
|
||||
$firstCall = true;
|
||||
foreach ($tCalls as $iii => $tCall) {
|
||||
if ($n == -2) {
|
||||
$n++;
|
||||
continue;
|
||||
}
|
||||
$c = $tCall[0];
|
||||
// normally we construct a call for template2 with the parameters of template1
|
||||
if (count($extractParm) == 0) {
|
||||
// find the end of the call: bracket level must be zero
|
||||
$cbrackets = 0;
|
||||
$templateCall = '{{' . $template2 . $tCall;
|
||||
$size = strlen($templateCall);
|
||||
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$c = $templateCall[$i];
|
||||
if ($c == '{') {
|
||||
$cbrackets++;
|
||||
}
|
||||
if ($c == '}') {
|
||||
$cbrackets--;
|
||||
}
|
||||
if ($cbrackets == 0) {
|
||||
// if we must match a condition: test against it
|
||||
if (($mustMatch == '' || preg_match($mustMatch, substr($templateCall, 0, $i - 1))) && ($mustNotMatch == '' || !preg_match($mustNotMatch, substr($templateCall, 0, $i - 1)))) {
|
||||
$invocation = substr($templateCall, 0, $i - 1);
|
||||
$argChain = $invocation . '|%PAGE%=' . $page . '|%TITLE%=' . $title->getText();
|
||||
if ($catlist != '') {
|
||||
$argChain .= "|%CATLIST%=$catlist";
|
||||
}
|
||||
$argChain .= '|%DATE%=' . $date . '|%USER%=' . $user . '|%ARGS%=' . str_replace('|', '§', preg_replace('/[}]+/', '}', preg_replace('/[{]+/', '{', substr($invocation, strlen($template2) + 2)))) . '}}';
|
||||
$output[++$n] = $parser->preprocess($argChain, $parser->mTitle, $parser->mOptions);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if the user wants parameters directly from the call line of template1 we return just those
|
||||
$cbrackets = 2;
|
||||
$templateCall = $tCall;
|
||||
$size = strlen($templateCall);
|
||||
$parms = [];
|
||||
$parm = '';
|
||||
$hasParm = false;
|
||||
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$c = $templateCall[$i];
|
||||
if ($c == '{' || $c == '[') {
|
||||
$cbrackets++; // we count both types of brackets
|
||||
}
|
||||
if ($c == '}' || $c == ']') {
|
||||
$cbrackets--;
|
||||
}
|
||||
if ($cbrackets == 2 && $c == '|') {
|
||||
$parms[] = trim($parm);
|
||||
$hasParm = true;
|
||||
$parm = '';
|
||||
} else {
|
||||
$parm .= $c;
|
||||
}
|
||||
if ($cbrackets == 0) {
|
||||
if ($hasParm) {
|
||||
$parms[] = trim(substr($parm, 0, strlen($parm) - 2));
|
||||
}
|
||||
array_splice($parms, 0, 1); // remove artifact;
|
||||
// if we must match a condition: test against it
|
||||
$callText = substr($templateCall, 0, $i - 1);
|
||||
if (($mustMatch == '' || (($matchParsed && preg_match($mustMatch, $parser->recursiveTagParse($callText))) || (!$matchParsed && preg_match($mustMatch, $callText)))) && ($mustNotMatch == '' || (($matchParsed && !preg_match($mustNotMatch, $parser->recursiveTagParse($callText))) || (!$matchParsed && !preg_match($mustNotMatch, $callText))))) {
|
||||
$output[++$n] = '';
|
||||
$second = false;
|
||||
foreach ($extractParm as $exParmKey => $exParm) {
|
||||
$maxlen = -1;
|
||||
if (($limpos = strpos($exParm, '[')) > 0 && $exParm[strlen($exParm) - 1] == ']') {
|
||||
$maxlen = intval(substr($exParm, $limpos + 1, strlen($exParm) - $limpos - 2));
|
||||
$exParm = substr($exParm, 0, $limpos);
|
||||
}
|
||||
if ($second) {
|
||||
if ($output[$n] == '' || $output[$n][strlen($output[$n]) - 1] != "\n") {
|
||||
$output[$n] .= "\n";
|
||||
}
|
||||
$output[$n] .= "|"; // \n";
|
||||
}
|
||||
$found = false;
|
||||
// % in parameter name
|
||||
if (strpos($exParm, '%') !== false) {
|
||||
// %% is a short form for inclusion of %PAGE% and %TITLE%
|
||||
$found = true;
|
||||
$output[$n] .= $lister->formatTemplateArg($exParm, $dplNr, $exParmKey, $firstCall, $maxlen, $article);
|
||||
}
|
||||
if (!$found) {
|
||||
// named parameter
|
||||
$exParmQuote = str_replace('/', '\/', $exParm);
|
||||
foreach ($parms as $parm) {
|
||||
if (!preg_match("/^\s*$exParmQuote\s*=/", $parm)) {
|
||||
continue;
|
||||
}
|
||||
$found = true;
|
||||
$output[$n] .= $lister->formatTemplateArg(preg_replace("/^$exParmQuote\s*=\s*/", "", $parm), $dplNr, $exParmKey, $firstCall, $maxlen, $article);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found && is_numeric($exParm) && intval($exParm) == $exParm) {
|
||||
// numeric parameter
|
||||
$np = 0;
|
||||
foreach ($parms as $parm) {
|
||||
if (strstr($parm, '=') === false) {
|
||||
++$np;
|
||||
}
|
||||
if ($np != $exParm) {
|
||||
continue;
|
||||
}
|
||||
$found = true;
|
||||
$output[$n] .= $lister->formatTemplateArg($parm, $dplNr, $exParmKey, $firstCall, $maxlen, $article);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
$output[$n] .= $lister->formatTemplateArg('', $dplNr, $exParmKey, $firstCall, $maxlen, $article);
|
||||
}
|
||||
$second = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$firstCall = false;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public static function spaceOrUnderscore($pattern) {
|
||||
// returns a pettern that matches underscores as well as spaces
|
||||
return str_replace(' ', '[ _]', $pattern);
|
||||
}
|
||||
}
|
80
classes/Logger.php
Normal file
80
classes/Logger.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
/**
|
||||
* DynamicPageList3
|
||||
* DPL Logger Class
|
||||
*
|
||||
* @author IlyaHaykinson, Unendlich, Dangerville, Algorithmix, Theaitetos, Alexia E. Smith
|
||||
* @license GPL-2.0-or-later
|
||||
* @package DynamicPageList3
|
||||
*
|
||||
**/
|
||||
namespace DPL;
|
||||
|
||||
class Logger {
|
||||
/**
|
||||
* Buffer of debug messages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $buffer = [];
|
||||
|
||||
/**
|
||||
* Function Documentation
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function addMessage($errorId) {
|
||||
$args = func_get_args();
|
||||
$args = array_map('htmlspecialchars', $args);
|
||||
return call_user_func_array([$this, 'msg'], $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the buffer of messages.
|
||||
*
|
||||
* @access public
|
||||
* @param boolean [Optional] Clear the message buffer.
|
||||
* @return array Messages in the order added.
|
||||
*/
|
||||
public function getMessages($clearBuffer = true) {
|
||||
$buffer = $this->buffer;
|
||||
if ($clearBuffer === true) {
|
||||
$this->buffer = [];
|
||||
}
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a message, with optional parameters
|
||||
* Parameters from user input must be escaped for HTML *before* passing to this function
|
||||
*
|
||||
* @access public
|
||||
* @param integer Message ID
|
||||
* @return string
|
||||
*/
|
||||
public function msg() {
|
||||
$args = func_get_args();
|
||||
$errorId = array_shift($args);
|
||||
$errorLevel = floor($errorId / 1000);
|
||||
$errorMessageId = $errorId % 1000;
|
||||
if (\DynamicPageListHooks::getDebugLevel() >= $errorLevel) {
|
||||
if (\DynamicPageListHooks::isLikeIntersection()) {
|
||||
if ($errorId == \DynamicPageListHooks::FATAL_TOOMANYCATS) {
|
||||
$text = wfMessage('intersection_toomanycats', $args)->text();
|
||||
} elseif ($errorId == \DynamicPageListHooks::FATAL_TOOFEWCATS) {
|
||||
$text = wfMessage('intersection_toofewcats', $args)->text();
|
||||
} elseif ($errorId == \DynamicPageListHooks::WARN_NORESULTS) {
|
||||
$text = wfMessage('intersection_noresults', $args)->text();
|
||||
} elseif ($errorId == \DynamicPageListHooks::FATAL_NOSELECTION) {
|
||||
$text = wfMessage('intersection_noincludecats', $args)->text();
|
||||
}
|
||||
}
|
||||
if (empty($text)) {
|
||||
$text = wfMessage('dpl_log_' . $errorMessageId, $args)->text();
|
||||
}
|
||||
$this->buffer[] = '<p>Extension:DynamicPageList (DPL), version ' . DPL_VERSION . ': ' . $text . '</p>';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
1332
classes/Parameters.php
Normal file
1332
classes/Parameters.php
Normal file
File diff suppressed because it is too large
Load diff
1379
classes/ParametersData.php
Normal file
1379
classes/ParametersData.php
Normal file
File diff suppressed because it is too large
Load diff
1006
classes/Parse.php
Normal file
1006
classes/Parse.php
Normal file
File diff suppressed because it is too large
Load diff
2142
classes/Query.php
Normal file
2142
classes/Query.php
Normal file
File diff suppressed because it is too large
Load diff
623
classes/UpdateArticle.php
Normal file
623
classes/UpdateArticle.php
Normal file
|
@ -0,0 +1,623 @@
|
|||
<?php
|
||||
/**
|
||||
* DynamicPageList3
|
||||
* DPL UpdateArticle Class
|
||||
*
|
||||
* @license GPL-2.0-or-later
|
||||
* @package DynamicPageList3
|
||||
*
|
||||
**/
|
||||
|
||||
namespace DPL;
|
||||
|
||||
class UpdateArticle {
|
||||
/**
|
||||
* this fucntion hast three tasks (depending on $exec):
|
||||
* (1) show an edit dialogue for template fields (exec = edit)
|
||||
* (2) set template parameters to values specified in the query (exec=set)v
|
||||
* (2) preview the source code including any changes of these parameters made in the edit form or with other changes (exec=preview)
|
||||
* (3) save the article with the changed value set or with other changes (exec=save)
|
||||
* "other changes" means that a regexp can be applied to the source text or arbitrary text can be
|
||||
* inserted before or after a pattern occuring in the text
|
||||
*/
|
||||
public static function updateArticleByRule($title, $text, $rulesText) {
|
||||
// we use ; as command delimiter; \; stands for a semicolon
|
||||
// \n is translated to a real linefeed
|
||||
$rulesText = str_replace(";", '°', $rulesText);
|
||||
$rulesText = str_replace('\°', ';', $rulesText);
|
||||
$rulesText = str_replace("\\n", "\n", $rulesText);
|
||||
$rules = explode('°', $rulesText);
|
||||
$exec = 'edit';
|
||||
$replaceThis = '';
|
||||
$replacement = '';
|
||||
$after = '';
|
||||
$insertionAfter = '';
|
||||
$before = '';
|
||||
$insertionBefore = '';
|
||||
$template = '';
|
||||
$parameter = [];
|
||||
$value = [];
|
||||
$afterparm = [];
|
||||
$format = [];
|
||||
$preview = [];
|
||||
$save = [];
|
||||
$tooltip = [];
|
||||
$optional = [];
|
||||
|
||||
$lastCmd = '';
|
||||
$message = '';
|
||||
$summary = '';
|
||||
$editForm = false;
|
||||
$action = '';
|
||||
$hidden = [];
|
||||
$legendPage = '';
|
||||
$instructionPage = '';
|
||||
$table = '';
|
||||
$fieldFormat = '';
|
||||
|
||||
// $message .= 'updaterules=<pre><nowiki>';
|
||||
$nr = -1;
|
||||
foreach ($rules as $rule) {
|
||||
if (preg_match('/^\s*#/', $rule) > 0) {
|
||||
continue; // # is comment symbol
|
||||
}
|
||||
|
||||
$rule = preg_replace('/^[\s]*/', '', $rule); // strip leading white space
|
||||
$cmd = preg_split("/ +/", $rule, 2);
|
||||
if (count($cmd) > 1) {
|
||||
$arg = $cmd[1];
|
||||
} else {
|
||||
$arg = '';
|
||||
}
|
||||
$cmd[0] = trim($cmd[0]);
|
||||
|
||||
// after ... insert ... , before ... insert ...
|
||||
if ($cmd[0] == 'before') {
|
||||
$before = $arg;
|
||||
$lastCmd = 'B';
|
||||
}
|
||||
if ($cmd[0] == 'after') {
|
||||
$after = $arg;
|
||||
$lastCmd = 'A';
|
||||
}
|
||||
if ($cmd[0] == 'insert' && $lastCmd != '') {
|
||||
if ($lastCmd == 'A') {
|
||||
$insertionAfter = $arg;
|
||||
}
|
||||
if ($lastCmd == 'B') {
|
||||
$insertionBefore = $arg;
|
||||
}
|
||||
}
|
||||
if ($cmd[0] == 'template') {
|
||||
$template = $arg;
|
||||
}
|
||||
|
||||
if ($cmd[0] == 'parameter') {
|
||||
$nr++;
|
||||
$parameter[$nr] = $arg;
|
||||
if ($nr > 0) {
|
||||
$afterparm[$nr] = [
|
||||
$parameter[$nr - 1]
|
||||
];
|
||||
$n = $nr - 1;
|
||||
while ($n > 0 && array_key_exists($n, $optional)) {
|
||||
$n--;
|
||||
$afterparm[$nr][] = $parameter[$n];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($cmd[0] == 'value') {
|
||||
$value[$nr] = $arg;
|
||||
}
|
||||
if ($cmd[0] == 'format') {
|
||||
$format[$nr] = $arg;
|
||||
}
|
||||
if ($cmd[0] == 'tooltip') {
|
||||
$tooltip[$nr] = $arg;
|
||||
}
|
||||
if ($cmd[0] == 'optional') {
|
||||
$optional[$nr] = true;
|
||||
}
|
||||
if ($cmd[0] == 'afterparm') {
|
||||
$afterparm[$nr] = [
|
||||
$arg
|
||||
];
|
||||
}
|
||||
if ($cmd[0] == 'legend') {
|
||||
$legendPage = $arg;
|
||||
}
|
||||
if ($cmd[0] == 'instruction') {
|
||||
$instructionPage = $arg;
|
||||
}
|
||||
if ($cmd[0] == 'table') {
|
||||
$table = $arg;
|
||||
}
|
||||
if ($cmd[0] == 'field') {
|
||||
$fieldFormat = $arg;
|
||||
}
|
||||
|
||||
if ($cmd[0] == 'replace') {
|
||||
$replaceThis = $arg;
|
||||
}
|
||||
if ($cmd[0] == 'by') {
|
||||
$replacement = $arg;
|
||||
}
|
||||
|
||||
if ($cmd[0] == 'editform') {
|
||||
$editForm = $arg;
|
||||
}
|
||||
if ($cmd[0] == 'action') {
|
||||
$action = $arg;
|
||||
}
|
||||
if ($cmd[0] == 'hidden') {
|
||||
$hidden[] = $arg;
|
||||
}
|
||||
if ($cmd[0] == 'preview') {
|
||||
$preview[] = $arg;
|
||||
}
|
||||
if ($cmd[0] == 'save') {
|
||||
$save[] = $arg;
|
||||
}
|
||||
|
||||
if ($cmd[0] == 'summary') {
|
||||
$summary = $arg;
|
||||
}
|
||||
if ($cmd[0] == 'exec') {
|
||||
$exec = $arg; // desired action (set or edit or preview)
|
||||
}
|
||||
}
|
||||
|
||||
if ($summary == '') {
|
||||
$summary .= "\nbulk update:";
|
||||
if ($replaceThis != '') {
|
||||
$summary .= "\n replace $replaceThis\n by $replacement";
|
||||
}
|
||||
if ($before != '') {
|
||||
$summary .= "\n before $before\n insertionBefore";
|
||||
}
|
||||
if ($after != '') {
|
||||
$summary .= "\n after $after\n insertionAfter";
|
||||
}
|
||||
}
|
||||
|
||||
// $message.= '</nowiki></pre>';
|
||||
|
||||
// perform changes to the wiki source text =======================================
|
||||
|
||||
if ($replaceThis != '') {
|
||||
$text = preg_replace("$replaceThis", $replacement, $text);
|
||||
}
|
||||
|
||||
if ($insertionBefore != '' && $before != '') {
|
||||
$text = preg_replace("/($before)/", $insertionBefore . '\1', $text);
|
||||
}
|
||||
|
||||
if ($insertionAfter != '' && $after != '') {
|
||||
$text = preg_replace("/($after)/", '\1' . $insertionAfter, $text);
|
||||
}
|
||||
|
||||
// deal with template parameters =================================================
|
||||
|
||||
global $wgRequest, $wgUser;
|
||||
|
||||
if ($template != '') {
|
||||
|
||||
if ($exec == 'edit') {
|
||||
$tpv = self::getTemplateParmValues($text, $template);
|
||||
$legendText = '';
|
||||
if ($legendPage != '') {
|
||||
$legendTitle = '';
|
||||
global $wgParser, $wgUser;
|
||||
$parser = clone $wgParser;
|
||||
LST::text($parser, $legendPage, $legendTitle, $legendText);
|
||||
$legendText = preg_replace('/^.*?\<section\s+begin\s*=\s*legend\s*\/\>/s', '', $legendText);
|
||||
$legendText = preg_replace('/\<section\s+end\s*=\s*legend\s*\/\>.*/s', '', $legendText);
|
||||
}
|
||||
$instructionText = '';
|
||||
$instructions = [];
|
||||
if ($instructionPage != '') {
|
||||
$instructionTitle = '';
|
||||
global $wgParser, $wgUser;
|
||||
$parser = clone $wgParser;
|
||||
LST::text($parser, $instructionPage, $instructionTitle, $instructionText);
|
||||
$instructions = self::getTemplateParmValues($instructionText, 'Template field');
|
||||
}
|
||||
// construct an edit form containing all template invocations
|
||||
$form = "<html><form method=post action=\"$action\" $editForm>\n";
|
||||
foreach ($tpv as $call => $tplValues) {
|
||||
$form .= "<table $table>\n";
|
||||
foreach ($parameter as $nr => $parm) {
|
||||
// try to extract legend from the docs of the template
|
||||
$myToolTip = '';
|
||||
if (array_key_exists($nr, $tooltip)) {
|
||||
$myToolTip = $tooltip[$nr];
|
||||
}
|
||||
$myInstruction = '';
|
||||
$myType = '';
|
||||
foreach ($instructions as $instruct) {
|
||||
if (array_key_exists('field', $instruct) && $instruct['field'] == $parm) {
|
||||
if (array_key_exists('doc', $instruct)) {
|
||||
$myInstruction = $instruct['doc'];
|
||||
}
|
||||
if (array_key_exists('type', $instruct)) {
|
||||
$myType = $instruct['type'];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
$myFormat = '';
|
||||
if (array_key_exists($nr, $format)) {
|
||||
$myFormat = $format[$nr];
|
||||
}
|
||||
$myOptional = array_key_exists($nr, $optional);
|
||||
if ($legendText != '' && $myToolTip == '') {
|
||||
$myToolTip = preg_replace('/^.*\<section\s+begin\s*=\s*' . preg_quote($parm, '/') . '\s*\/\>/s', '', $legendText);
|
||||
if (strlen($myToolTip) == strlen($legendText)) {
|
||||
$myToolTip = '';
|
||||
} else {
|
||||
$myToolTip = preg_replace('/\<section\s+end\s*=\s*' . preg_quote($parm, '/') . '\s*\/\>.*/s', '', $myToolTip);
|
||||
}
|
||||
}
|
||||
$myValue = '';
|
||||
if (array_key_exists($parm, $tpv[$call])) {
|
||||
$myValue = $tpv[$call][$parm];
|
||||
}
|
||||
$form .= self::editTemplateCall($text, $template, $call, $parm, $myType, $myValue, $myFormat, $myToolTip, $myInstruction, $myOptional, $fieldFormat);
|
||||
}
|
||||
$form .= "</table>\n<br/><br/>";
|
||||
}
|
||||
foreach ($hidden as $hide) {
|
||||
$form .= "<input type='hidden' " . $hide . " />";
|
||||
}
|
||||
$form .= "<input type='hidden' name='wpEditToken' value='{$wgUser->getEditToken()}'/>";
|
||||
foreach ($preview as $prev) {
|
||||
$form .= "<input type='submit' " . $prev . " /> ";
|
||||
}
|
||||
$form .= "</form></html>\n";
|
||||
return $form;
|
||||
} elseif ($exec == 'set' || $exec == 'preview') {
|
||||
// loop over all invocations and parameters, this could be improved to enhance performance
|
||||
$matchCount = 10;
|
||||
for ($call = 0; $call < 10; $call++) {
|
||||
foreach ($parameter as $nr => $parm) {
|
||||
// set parameters to values specified in the dpl source or get them from the http request
|
||||
if ($exec == 'set') {
|
||||
$myvalue = $value[$nr];
|
||||
} else {
|
||||
if ($call >= $matchCount) {
|
||||
break;
|
||||
}
|
||||
$myValue = $wgRequest->getVal(urlencode($call . '_' . $parm), '');
|
||||
}
|
||||
$myOptional = array_key_exists($nr, $optional);
|
||||
$myAfterParm = [];
|
||||
if (array_key_exists($nr, $afterparm)) {
|
||||
$myAfterParm = $afterparm[$nr];
|
||||
}
|
||||
$text = self::updateTemplateCall($matchCount, $text, $template, $call, $parm, $myValue, $myAfterParm, $myOptional);
|
||||
}
|
||||
if ($exec == 'set') {
|
||||
break; // values taken from dpl text only populate the first invocation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($exec == 'set') {
|
||||
return self::updateArticle($title, $text, $summary);
|
||||
} elseif ($exec == 'preview') {
|
||||
global $wgScriptPath, $wgRequest;
|
||||
$titleX = \Title::newFromText($title);
|
||||
$articleX = new \Article($titleX);
|
||||
$form = '<html>
|
||||
<form id="editform" name="editform" method="post" action="' . $wgScriptPath . '/index.php?title=' . urlencode($title) . '&action=submit" enctype="multipart/form-data">
|
||||
<input type="hidden" value="" name="wpSection" />
|
||||
<input type="hidden" value="' . wfTimestampNow() . '" name="wpStarttime" />
|
||||
<input type="hidden" value="' . $articleX->getTimestamp() . '" name="wpEdittime" />
|
||||
<input type="hidden" value="" name="wpScrolltop" id="wpScrolltop" />
|
||||
<textarea tabindex="1" accesskey="," name="wpTextbox1" id="wpTextbox1" rows="' . $wgUser->getIntOption('rows') . '" cols="' . $wgUser->getIntOption('cols') . '" >' . htmlspecialchars($text) . '</textarea>
|
||||
<input type="hidden" name="wpSummary value="' . $summary . '" id="wpSummary" />
|
||||
<input name="wpAutoSummary" type="hidden" value="" />
|
||||
<input id="wpSave" name="wpSave" type="submit" value="Save page" accesskey="s" title="Save your changes [s]" />
|
||||
<input type="hidden" value="' . $wgRequest->getVal('token') . '" name="wpEditToken" />
|
||||
</form>
|
||||
</html>';
|
||||
return $form;
|
||||
}
|
||||
return "exec must be one of the following: edit, preview, set";
|
||||
}
|
||||
|
||||
private static function updateArticle($title, $text, $summary) {
|
||||
global $wgUser, $wgRequest, $wgOut;
|
||||
|
||||
if (!$wgUser->matchEditToken($wgRequest->getVal('wpEditToken'))) {
|
||||
$wgOut->addWikiMsg('sessionfailure');
|
||||
return 'session failure';
|
||||
}
|
||||
|
||||
$titleX = \Title::newFromText($title);
|
||||
$permission_errors = $titleX->getUserPermissionsErrors('edit', $wgUser);
|
||||
if (count($permission_errors) == 0) {
|
||||
$articleX = \WikiPage::factory($titleX);
|
||||
$articleXContent = \ContentHandler::makeContent($text, $titleX);
|
||||
$articleX->doEditContent($articleXContent, $summary, EDIT_UPDATE | EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY);
|
||||
$wgOut->redirect($titleX->getFullUrl($articleX->isRedirect() ? 'redirect=no' : ''));
|
||||
return '';
|
||||
} else {
|
||||
$wgOut->showPermissionsErrorPage($permission_errors);
|
||||
return 'permission error';
|
||||
}
|
||||
}
|
||||
|
||||
private static function editTemplateCall($text, $template, $call, $parameter, $type, $value, $format, $legend, $instruction, $optional, $fieldFormat) {
|
||||
$matches = [];
|
||||
$nlCount = preg_match_all('/\n/', $value, $matches);
|
||||
if ($nlCount > 0) {
|
||||
$rows = $nlCount + 1;
|
||||
} else {
|
||||
$rows = floor(strlen($value) / 50) + 1;
|
||||
}
|
||||
if (preg_match('/rows\s*=/', $format) <= 0) {
|
||||
$format .= " rows=$rows";
|
||||
}
|
||||
$cols = 50;
|
||||
if (preg_match('/cols\s*=/', $format) <= 0) {
|
||||
$format .= " cols=$cols";
|
||||
}
|
||||
$textArea = "<textarea name=\"" . urlencode($call . '_' . $parameter) . "\" $format/>" . htmlspecialchars($value) . "</textarea>";
|
||||
return str_replace('%NAME%', htmlspecialchars(str_replace('_', ' ', $parameter)), str_replace('%TYPE%', $type, str_replace('%INPUT%', $textArea, str_replace('%LEGEND%', "</html>" . htmlspecialchars($legend) . "<html>", str_replace('%INSTRUCTION%', "</html>" . htmlspecialchars($instruction) . "<html>", $fieldFormat)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* return an array of template invocations; each element is an associative array of parameter and value
|
||||
*/
|
||||
private static function getTemplateParmValues($text, $template) {
|
||||
$matches = [];
|
||||
$noMatches = preg_match_all('/\{\{\s*' . preg_quote($template, '/') . '\s*[|}]/i', $text, $matches, PREG_OFFSET_CAPTURE);
|
||||
if ($noMatches <= 0) {
|
||||
return '';
|
||||
}
|
||||
$textLen = strlen($text);
|
||||
$tval = []; // the result array of template values
|
||||
$call = -1; // index for tval
|
||||
|
||||
foreach ($matches as $matchA) {
|
||||
foreach ($matchA as $matchB) {
|
||||
$match = $matchB[0];
|
||||
$start = $matchB[1];
|
||||
$tval[++$call] = [];
|
||||
$nr = 0; // number of parameter if no name given
|
||||
$parmValue = '';
|
||||
$parmName = '';
|
||||
$parm = '';
|
||||
|
||||
if ($match[strlen($match) - 1] == '}') {
|
||||
break; // template was called without parameters, continue with next invocation
|
||||
}
|
||||
|
||||
// search to the end of the template call
|
||||
$cbrackets = 2;
|
||||
for ($i = $start + strlen($match); $i < $textLen; $i++) {
|
||||
$c = $text[$i];
|
||||
if ($c == '{' || $c == '[') {
|
||||
$cbrackets++; // we count both types of brackets
|
||||
}
|
||||
if ($c == '}' || $c == ']') {
|
||||
$cbrackets--;
|
||||
}
|
||||
if (($cbrackets == 2 && $c == '|') || ($cbrackets == 1 && $c == '}')) {
|
||||
// parameter (name or value) found
|
||||
if ($parmName == '') {
|
||||
$tval[$call][++$nr] = trim($parm);
|
||||
} else {
|
||||
$tval[$call][$parmName] = trim($parmValue);
|
||||
}
|
||||
$parmName = '';
|
||||
$parmValue = '';
|
||||
$parm = '';
|
||||
continue;
|
||||
} else {
|
||||
if ($parmName == '') {
|
||||
if ($c == '=') {
|
||||
$parmName = trim($parm);
|
||||
}
|
||||
} else {
|
||||
$parmValue .= $c;
|
||||
}
|
||||
}
|
||||
$parm .= $c;
|
||||
if ($cbrackets == 0) {
|
||||
break; // end of parameter list
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $tval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Changes a single parameter value within a certain call of a template
|
||||
*/
|
||||
private static function updateTemplateCall(&$matchCount, $text, $template, $call, $parameter, $value, $afterParm, $optional) {
|
||||
// if parameter is optional and value is empty we leave everything as it is (i.e. we do not remove the parm)
|
||||
if ($optional && $value == '') {
|
||||
return $text;
|
||||
}
|
||||
|
||||
$matches = [];
|
||||
$noMatches = preg_match_all('/\{\{\s*' . preg_quote($template, '/') . '\s*[|}]/i', $text, $matches, PREG_OFFSET_CAPTURE);
|
||||
if ($noMatches <= 0) {
|
||||
return $text;
|
||||
}
|
||||
$beginSubst = -1;
|
||||
$endSubst = -1;
|
||||
$posInsertAt = 0;
|
||||
$apNrLast = 1000; // last (optional) predecessor
|
||||
|
||||
foreach ($matches as $matchA) {
|
||||
$matchCount = count($matchA);
|
||||
foreach ($matchA as $occurence => $matchB) {
|
||||
if ($occurence < $call) {
|
||||
continue;
|
||||
}
|
||||
$match = $matchB[0];
|
||||
$start = $matchB[1];
|
||||
|
||||
if ($match[strlen($match) - 1] == '}') {
|
||||
// template was called without parameters, add new parameter and value
|
||||
// append parameter and value
|
||||
$beginSubst = $i;
|
||||
$endSubst = $i;
|
||||
$substitution = "|$parameter = $value";
|
||||
break;
|
||||
} else {
|
||||
// there is already a list of parameters; we search to the end of the template call
|
||||
$cbrackets = 2;
|
||||
$parm = '';
|
||||
$pos = $start + strlen($match) - 1;
|
||||
$textLen = strlen($text);
|
||||
for ($i = $pos + 1; $i < $textLen; $i++) {
|
||||
$c = $text[$i];
|
||||
if ($c == '{' || $c == '[') {
|
||||
$cbrackets++; // we count both types of brackets
|
||||
}
|
||||
if ($c == '}' || $c == ']') {
|
||||
$cbrackets--;
|
||||
}
|
||||
if (($cbrackets == 2 && $c == '|') || ($cbrackets == 1 && $c == '}')) {
|
||||
// parameter (name / value) found
|
||||
|
||||
$token = explode('=', $parm, 2);
|
||||
if (count($token) == 2) {
|
||||
// we need a pair of name / value
|
||||
$parmName = trim($token[0]);
|
||||
if ($parmName == $parameter) {
|
||||
// we found the parameter, now replace the current value
|
||||
$parmValue = trim($token[1]);
|
||||
if ($parmValue == $value) {
|
||||
break; // no need to change when values are identical
|
||||
}
|
||||
// keep spaces;
|
||||
if ($parmValue == '') {
|
||||
if (strlen($token[1]) > 0 && $token[1][strlen($token[1]) - 1] == "\n") {
|
||||
$substitution = str_replace("\n", $value . "\n", $token[1]);
|
||||
} else {
|
||||
$substitution = $value . $token[1];
|
||||
}
|
||||
} else {
|
||||
$substitution = str_replace($parmValue, $value, $token[1]);
|
||||
}
|
||||
$beginSubst = $pos + strlen($token[0]) + 2;
|
||||
$endSubst = $i;
|
||||
break;
|
||||
} else {
|
||||
foreach ($afterParm as $apNr => $ap) {
|
||||
// store position for insertion
|
||||
if ($parmName == $ap && $apNr < $apNrLast) {
|
||||
$posInsertAt = $i;
|
||||
$apNrLast = $apNr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($c == '}') {
|
||||
// end of template call reached, insert at stored position or here
|
||||
if ($posInsertAt != 0) {
|
||||
$beginSubst = $posInsertAt;
|
||||
} else {
|
||||
$beginSubst = $i;
|
||||
}
|
||||
$substitution = "|$parameter = $value";
|
||||
if ($text[$beginSubst - 1] == "\n") {
|
||||
--$beginSubst;
|
||||
$substitution = "\n" . $substitution;
|
||||
}
|
||||
$endSubst = $beginSubst;
|
||||
break;
|
||||
}
|
||||
|
||||
$pos = $i;
|
||||
$parm = '';
|
||||
} else {
|
||||
$parm .= $c;
|
||||
}
|
||||
if ($cbrackets == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ($beginSubst < 0) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
return substr($text, 0, $beginSubst) . $substitution . substr($text, $endSubst);
|
||||
}
|
||||
|
||||
public function deleteArticleByRule($title, $text, $rulesText) {
|
||||
global $wgUser, $wgOut;
|
||||
|
||||
// return "deletion of articles by DPL is disabled.";
|
||||
|
||||
// we use ; as command delimiter; \; stands for a semicolon
|
||||
// \n is translated to a real linefeed
|
||||
$rulesText = str_replace(";", '°', $rulesText);
|
||||
$rulesText = str_replace('\°', ';', $rulesText);
|
||||
$rulesText = str_replace("\\n", "\n", $rulesText);
|
||||
$rules = explode('°', $rulesText);
|
||||
$exec = false;
|
||||
$message = '';
|
||||
$reason = '';
|
||||
|
||||
foreach ($rules as $rule) {
|
||||
if (preg_match('/^\s*#/', $rule) > 0) {
|
||||
continue; // # is comment symbol
|
||||
}
|
||||
|
||||
$rule = preg_replace('/^[\s]*/', '', $rule); // strip leading white space
|
||||
$cmd = preg_split("/ +/", $rule, 2);
|
||||
if (count($cmd) > 1) {
|
||||
$arg = $cmd[1];
|
||||
} else {
|
||||
$arg = '';
|
||||
}
|
||||
$cmd[0] = trim($cmd[0]);
|
||||
|
||||
if ($cmd[0] == 'reason') {
|
||||
$reason = $arg;
|
||||
}
|
||||
|
||||
// we execute only if "exec" is given, otherwise we merely show what would be done
|
||||
if ($cmd[0] == 'exec') {
|
||||
$exec = true;
|
||||
}
|
||||
}
|
||||
$reason .= "\nbulk delete by DPL query";
|
||||
|
||||
$titleX = \Title::newFromText($title);
|
||||
if ($exec) {
|
||||
# Check permissions
|
||||
$permission_errors = $titleX->getUserPermissionsErrors('delete', $wgUser);
|
||||
if (count($permission_errors) > 0) {
|
||||
$wgOut->showPermissionsErrorPage($permission_errors);
|
||||
return 'permission error';
|
||||
} elseif (wfReadOnly()) {
|
||||
$wgOut->readOnlyPage();
|
||||
return 'DPL: read only mode';
|
||||
} else {
|
||||
$articleX = new \Article($titleX);
|
||||
$articleX->doDelete($reason);
|
||||
}
|
||||
} else {
|
||||
$message .= "set 'exec yes' to delete     <big>'''$title'''</big>\n";
|
||||
}
|
||||
$message .= "<pre><nowiki>\n{$text}</nowiki></pre>"; // <pre><nowiki>\n"; // .$text."\n</nowiki></pre>\n";
|
||||
return $message;
|
||||
}
|
||||
}
|
136
classes/Variables.php
Normal file
136
classes/Variables.php
Normal file
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
/**
|
||||
* DynamicPageList3
|
||||
* DPL Variables Class
|
||||
*
|
||||
* @author IlyaHaykinson, Unendlich, Dangerville, Algorithmix, Theaitetos, Alexia E. Smith
|
||||
* @license GPL-2.0-or-later
|
||||
* @package DynamicPageList3
|
||||
*
|
||||
**/
|
||||
namespace DPL;
|
||||
|
||||
class Variables {
|
||||
/**
|
||||
* Memory storage for variables.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static public $memoryVar = [];
|
||||
|
||||
/**
|
||||
* Memory storage for arrays of variables.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static public $memoryArray = [];
|
||||
|
||||
// expects pairs of 'variable name' and 'value'
|
||||
// if the first parameter is empty it will be ignored {{#vardefine:|a|b}} is the same as {{#vardefine:a|b}}
|
||||
public static function setVar($arg) {
|
||||
$numargs = count($arg);
|
||||
if ($numargs >= 3 && $arg[2] == '') {
|
||||
$start = 3;
|
||||
} else {
|
||||
$start = 2;
|
||||
}
|
||||
for ($i = $start; $i < $numargs; $i++) {
|
||||
$var = $arg[$i];
|
||||
if (++$i <= $numargs - 1) {
|
||||
self::$memoryVar[$var] = $arg[$i];
|
||||
} else {
|
||||
self::$memoryVar[$var] = '';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function setVarDefault($arg) {
|
||||
$numargs = count($arg);
|
||||
if ($numargs > 3) {
|
||||
$value = $arg[3];
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
$var = $arg[2];
|
||||
if (!array_key_exists($var, self::$memoryVar) || self::$memoryVar[$var] == '') {
|
||||
self::$memoryVar[$var] = $value;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function getVar($var) {
|
||||
if (array_key_exists($var, self::$memoryVar)) {
|
||||
return self::$memoryVar[$var];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function setArray($arg) {
|
||||
$numargs = count($arg);
|
||||
if ($numargs < 5) {
|
||||
return '';
|
||||
}
|
||||
$var = trim($arg[2]);
|
||||
$value = $arg[3];
|
||||
$delimiter = $arg[4];
|
||||
if ($var == '') {
|
||||
return '';
|
||||
}
|
||||
if ($value == '') {
|
||||
self::$memoryArray[$var] = [];
|
||||
return;
|
||||
}
|
||||
if ($delimiter == '') {
|
||||
self::$memoryArray[$var] = [
|
||||
$value
|
||||
];
|
||||
return;
|
||||
}
|
||||
if (0 !== strpos($delimiter, '/') || (strlen($delimiter) - 1) !== strrpos($delimiter, '/')) {
|
||||
$delimiter = '/\s*' . $delimiter . '\s*/';
|
||||
}
|
||||
self::$memoryArray[$var] = preg_split($delimiter, $value);
|
||||
return "value={$value}, delimiter={$delimiter}," . count(self::$memoryArray[$var]);
|
||||
}
|
||||
|
||||
public static function dumpArray($arg) {
|
||||
$numargs = count($arg);
|
||||
if ($numargs < 3) {
|
||||
return '';
|
||||
}
|
||||
$var = trim($arg[2]);
|
||||
$text = " array {$var} = {";
|
||||
$n = 0;
|
||||
if (array_key_exists($var, self::$memoryArray)) {
|
||||
foreach (self::$memoryArray[$var] as $value) {
|
||||
if ($n++ > 0) {
|
||||
$text .= ', ';
|
||||
}
|
||||
$text .= "{$value}";
|
||||
}
|
||||
}
|
||||
return $text . "}\n";
|
||||
}
|
||||
|
||||
public static function printArray($var, $delimiter, $search, $subject) {
|
||||
$var = trim($var);
|
||||
if ($var == '') {
|
||||
return '';
|
||||
}
|
||||
if (!array_key_exists($var, self::$memoryArray)) {
|
||||
return '';
|
||||
}
|
||||
$values = self::$memoryArray[$var];
|
||||
$rendered_values = [];
|
||||
foreach ($values as $v) {
|
||||
$temp_result_value = str_replace($search, $v, $subject);
|
||||
$rendered_values[] = $temp_result_value;
|
||||
}
|
||||
return [
|
||||
implode($delimiter, $rendered_values),
|
||||
'noparse' => false,
|
||||
'isHTML' => false
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue