r54515 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r54514‎ | r54515 | r54516 >
Date:13:30, 6 August 2009
Author:shinjiman
Status:deferred
Tags:
Comment:
Update the DPL codebase to 1.8.7.
code based on Gero aka Algorithmix
Modified paths:
  • /trunk/extensions/DynamicPageList/DPL.php (modified) (history)
  • /trunk/extensions/DynamicPageList/DPLMain.php (modified) (history)
  • /trunk/extensions/DynamicPageList/DPLSetup.php (modified) (history)
  • /trunk/extensions/DynamicPageList/DynamicPageList.php (modified) (history)
  • /trunk/extensions/DynamicPageList/DynamicPageListInclude.php (modified) (history)
  • /trunk/extensions/DynamicPageList/DynamicPageListMigration.php (modified) (history)

Diff [purge]

Index: trunk/extensions/DynamicPageList/DynamicPageList.php
@@ -14,7 +14,7 @@
1515
1616 ExtDynamicPageList::setFunctionalRichness( <n> );
1717
18 - where <n> is a number between 0 and 3.
 18+ where <n> is a number between 0 and 4.
1919
2020 If your wiki has been using Extension:Intersection you must UNINSTALL that
2121 extension before you can use DynamicPageList (DPL).
@@ -36,7 +36,7 @@
3737 on your server / database. For wikis up to 10.000 pages this is normally not a problem,
3838 but with larger wikis some care is advisable.
3939
40 - By default the RichnessLevel is set to 3 (= activate whole set of functions).
 40+ By default the RichnessLevel is set to 4 (= activate whole set of functions).
4141
4242 Use a different value if you do not feel comfortable with this:
4343 - level=0 will not allow any additional functionality (compared to Extension:Intersection).
@@ -59,16 +59,16 @@
6060
6161 $wgHooks['LanguageGetMagic'][] = 'ExtDynamicPageList__languageGetMagic';
6262
63 -$DPLVersion = '1.8.6';
 63+$DPLVersion = '1.8.7';
6464
6565 $wgExtensionCredits['parserhook'][] = array(
66 - 'path' => __FILE__,
67 - 'name' => 'DynamicPageList',
68 - 'author' => '[http://de.wikipedia.org/wiki/Benutzer:Algorithmix Gero Scholz]',
69 - 'url' => 'http://www.mediawiki.org/wiki/Extension:DynamicPageList_(third-party)',
70 - 'description' => 'A highly flexible report generator for MediaWikis - manual and examples: see [http://semeb.com/dpldemo]',
71 - 'descriptionmsg' => 'dpl-desc',
72 - 'version' => $DPLVersion
 66+ 'path' => __FILE__,
 67+ 'name' => 'DynamicPageList',
 68+ 'author' => '[http://de.wikipedia.org/wiki/Benutzer:Algorithmix Gero Scholz]',
 69+ 'url' => 'http://www.mediawiki.org/wiki/Extension:DynamicPageList_(third-party)',
 70+ 'description' => 'A highly flexible report generator for MediaWikis - manual and examples: see [http://semeb.com/dpldemo]',
 71+ 'descriptionmsg' => 'dpl-desc',
 72+ 'version' => $DPLVersion
7373 );
7474
7575 require_once( 'DPLSetup.php' );
@@ -77,3 +77,5 @@
7878
7979 // use full functionality by default
8080 ExtDynamicPageList::setFunctionalRichness(4);
 81+
 82+// MyBug::trace('','','');
Index: trunk/extensions/DynamicPageList/DPL.php
@@ -30,6 +30,7 @@
3131 $listmode, $bescapelinks, $baddexternallink, $includepage, $includemaxlen, $includeseclabels, $includeseclabelsmatch,
3232 $includeseclabelsnotmatch, $includematchparsed, &$parser, $logger, $replaceInTitle, $iTitleMaxLen,
3333 $defaultTemplateSuffix, $aTableRow, $bIncludeTrim, $iTableSortCol, $updateRules, $deleteRules ) {
 34+
3435 global $wgContLang;
3536 $this->nameSpaces = $wgContLang->getNamespaces();
3637 $this->mArticles = $articles;
@@ -46,12 +47,22 @@
4748
4849 if (isset($includemaxlen)) $this->mIncMaxLen = $includemaxlen + 1;
4950 else $this->mIncMaxLen = 0;
50 - $this->mParser = $parser;
51 - $this->mParserOptions = $parser->mOptions;
52 - $this->mParserTitle = $parser->mTitle;
5351 $this->mLogger = $logger;
5452 $this->mReplaceInTitle = $replaceInTitle;
5553 $this->mTableRow = $aTableRow;
 54+
 55+ // cloning the parser in the following statement leads in some cases to a php error in MW 1.15
 56+ // You must apply the following patch to avoid this:
 57+ // add in LinkHoldersArray.php at the beginning of function 'merge' the following code lines:
 58+ // if (!isset($this->interwikis)) {
 59+ // $this->internals = array();
 60+ // $this->interwikis = array();
 61+ // $this->size = 0;
 62+ // $this->parent = $other->parent;
 63+ // }
 64+ $this->mParser = clone $parser;
 65+ $this->mParserOptions = $parser->mOptions;
 66+ $this->mParserTitle = $parser->mTitle;
5667
5768 if(!empty($headings)) {
5869 if ($iColumns!=1 || $iRows!=1) {
@@ -161,7 +172,9 @@
162173 } else {
163174 $this->mOutput .= $this->formatList(0, count($articles), $iTitleMaxLen, $defaultTemplateSuffix, $bIncludeTrim, $iTableSortCol, $updateRules, $deleteRules);
164175 }
165 -
 176+
 177+ // MyBug::trace(__CLASS__,'DPL end',$this->mOutput);
 178+
166179 }
167180
168181 function formatCount($numart) {
@@ -251,7 +264,14 @@
252265 if ($article->mNamespace==6) {
253266 // calculate URL for existing images
254267 $img = Image::newFromName($article->mTitle->getText());
255 - if ($img && $img->exists()) $imageUrl = $img->getURL();
 268+ if ($img && $img->exists()) {
 269+ $imageUrl = $img->getURL();
 270+ $imageUrl= preg_replace('~^.*images/(.*)~','\1',$imageUrl);
 271+ }
 272+ else {
 273+ $iTitle = Title::makeTitleSafe(6,$article->mTitle->getDBKey());
 274+ $imageUrl = preg_replace('~^.*images/(.*)~','\1',RepoGroup::singleton()->getLocalRepo()->newFile($iTitle)->getPath());
 275+ }
256276 }
257277 if ($this->mEscapeLinks && ($article->mNamespace==14 || $article->mNamespace==6) ) {
258278 // links to categories or images need an additional ":"
@@ -321,11 +341,14 @@
322342 if($sSecLabel[0] != '{') {
323343 $limpos = strpos($sSecLabel,'[');
324344 $cutLink='default';
 345+ $skipPattern='';
325346 if ($limpos>0 && $sSecLabel[strlen($sSecLabel)-1]==']') {
326 - $cutInfo=explode(" ",substr($sSecLabel,$limpos+1,strlen($sSecLabel)-$limpos-2),2);
 347+ $fmtSec=explode('~',substr($sSecLabel,$limpos+1,strlen($sSecLabel)-$limpos-2),2);
 348+ $cutInfo=explode(" ",$fmtSec[0],2);
327349 $sSecLabel=substr($sSecLabel,0,$limpos);
328350 $maxlen=intval($cutInfo[0]);
329351 if (isset($cutInfo[1])) $cutLink=$cutInfo[1];
 352+ if (isset($fmtSec[1])) $skipPattern=$fmtSec[1];
330353 }
331354 if ($maxlen<0) $maxlen = -1; // without valid limit include whole section
332355 }
@@ -344,7 +367,7 @@
345368 $sectionHeading[0]=substr($sSecLabel,1);
346369 // Uses DPLInclude::includeHeading() from LabeledSectionTransclusion extension to include headings from the page
347370 $secPieces = DPLInclude::includeHeading($this->mParser, $article->mTitle->getPrefixedText(), substr($sSecLabel, 1),'',
348 - $sectionHeading,false,$maxlen,$cutLink,$bIncludeTrim);
 371+ $sectionHeading,false,$maxlen,$cutLink,$bIncludeTrim,$skipPattern);
349372 if ($mustMatch!='' || $mustNotMatch!='') {
350373 $secPiecesTmp = $secPieces;
351374 $offset=0;
@@ -356,6 +379,7 @@
357380 }
358381 }
359382 }
 383+
360384 $this->formatSingleItems($secPieces,$s);
361385 if (!array_key_exists(0,$secPieces)) break; # to avoid matching against a non-existing array element
362386 $secPiece[$s] = $secPieces[0];
@@ -375,8 +399,8 @@
376400
377401 } else if($sSecLabel[0] == '{') {
378402 // Uses DPLInclude::includeTemplate() from LabeledSectionTransclusion extension to include templates from the page
379 - $template1 = substr($sSecLabel,1,strpos($sSecLabel,'}')-1);
380 - $template2 = str_replace('}','',substr($sSecLabel,1));
 403+ $template1 = trim(substr($sSecLabel,1,strpos($sSecLabel,'}')-1));
 404+ $template2 = trim(str_replace('}','',substr($sSecLabel,1)));
381405 $secPieces = DPLInclude::includeTemplate($this->mParser, $this, $s, $article, $template1,
382406 $template2, $template2.$defaultTemplateSuffix,$mustMatch,
383407 $mustNotMatch,$this->mIncParsed,$iTitleMaxLen);
@@ -389,7 +413,7 @@
390414 }
391415 } else {
392416 // Uses DPLInclude::includeSection() from LabeledSectionTransclusion extension to include labeled sections from the page
393 - $secPieces = DPLInclude::includeSection($this->mParser, $article->mTitle->getPrefixedText(), $sSecLabel,'', false, $bIncludeTrim);
 417+ $secPieces = DPLInclude::includeSection($this->mParser, $article->mTitle->getPrefixedText(), $sSecLabel,'', false, $bIncludeTrim, $skipPattern);
394418 $secPiece[$s] = implode(isset($mode->aMultiSecSeparators[$s])?
395419 $this->substTagParm($mode->aMultiSecSeparators[$s], $pagename, $article, $imageUrl, $this->filteredCount, $iTitleMaxLen):'',$secPieces);
396420 if ($mode->iDominantSection>=0 && $s==$mode->iDominantSection && count($secPieces)>1) $dominantPieces=$secPieces;
@@ -518,8 +542,19 @@
519543 }
520544
521545 return $actStart . $rBody . $mode->sListEnd;
 546+
522547 }
523548
 549+ /**
 550+ * this fucntion hast three tasks (depending on $exec):
 551+ * (1) show an edit dialogue for template fields (exec = edit)
 552+ * (2) set template parameters to values specified in the query (exec=set)v
 553+ * (2) preview the source code including any changes of these parameters made in the edit form or with other changes (exec=preview)
 554+ * (3) save the article with the changed value set or with other changes (exec=save)
 555+
 556+ * "other changes" means that a regexp can be applied to the source text or arbitrary text can be
 557+ * inserted before or after a pattern occuring in the text
 558+ */
524559
525560 function updateArticleByRule($title,$text,$rulesText) {
526561 // we use ; as command delimiter; \; stands for a semicolon
@@ -528,18 +563,38 @@
529564 $rulesText = str_replace('\°',';',$rulesText);
530565 $rulesText = str_replace("\\n","\n",$rulesText);
531566 $rules=split('°',$rulesText);
532 - $exec=false;
 567+ $exec='edit';
533568 $replaceThis='';
534569 $replacement='';
535570 $after='';
536571 $insertionAfter='';
537572 $before='';
538573 $insertionBefore='';
 574+ $template='';
 575+ $parameter=array();
 576+ $value=array();
 577+ $afterparm=array();
 578+ $format=array();
 579+ $submit=array();
 580+ $commit=array();
 581+ $tooltip=array();
 582+ $optional=array();
 583+
539584 $lastCmd='';
540585 $message= '';
541586 $summary='';
 587+ $editForm=false;
 588+ $action='';
 589+ $hidden=array();
 590+ $legendPage='';
 591+ $table='';
 592+
542593 // $message .= 'updaterules=<pre><nowiki>';
 594+ $nr = -1;
543595 foreach ($rules as $rule) {
 596+ if (preg_match('/^\s*#/',$rule)>0) continue; // # is comment symbol
 597+
 598+ $rule=preg_replace('/^[\s]*/','',$rule); // strip leading white space
544599 $cmd = preg_split("/ +/",$rule,2);
545600 if (count($cmd)>1) $arg = $cmd[1];
546601 else $arg='';
@@ -547,44 +602,52 @@
548603
549604 // after ... insert ... , before ... insert ...
550605 if ($cmd[0] == 'before') {
551 - // $message.= "before = $arg\n";
552606 $before=$arg;
553607 $lastCmd='B';
554608 }
555609 if ($cmd[0] == 'after') {
556 - // $message.= "after = $arg\n";
557610 $after=$arg;
558611 $lastCmd='A';
559612 }
560613 if ($cmd[0] == 'insert' && $lastCmd!='') {
561 - // $message.= "insert $lastCmd = $arg\n";
562614 if ($lastCmd=='A') $insertionAfter=$arg;
563615 if ($lastCmd=='B') $insertionBefore=$arg;
564616 }
 617+ if ($cmd[0] == 'template') $template = $arg;
565618
566 - // replace ... by ...
567 - if ($cmd[0] == 'replace') {
568 - // $message.= "repl = $arg\n";
569 - $replaceThis=$arg;
 619+ if ($cmd[0] == 'parameter') {
 620+ $nr++;
 621+ $parameter[$nr] = $arg;
 622+ if ($nr>0) {
 623+ $afterparm[$nr] = array($parameter[$nr-1]);
 624+ $n=$nr-1;
 625+ while ($n>0 && array_key_exists($n,$optional)) {
 626+ $n--;
 627+ $afterparm[$nr][]=$parameter[$n];
 628+ }
 629+ }
570630 }
571 - if ($cmd[0] == 'by') {
572 - // $message.= "by = $arg\n";
573 - $replacement=$arg;
574 - }
575 -
576 - if ($cmd[0] == 'summary') {
577 - // $message.= "summary = $arg\n";
578 - $summary=$arg;
579 - }
 631+ if ($cmd[0] == 'value') $value[$nr] = $arg;
 632+ if ($cmd[0] == 'format') $format[$nr] = $arg;
 633+ if ($cmd[0] == 'tooltip') $tooltip[$nr]=$arg;
 634+ if ($cmd[0] == 'optional') $optional[$nr]=true;
 635+ if ($cmd[0] == 'afterparm') $afterparm[$nr] = array($arg);
 636+ if ($cmd[0] == 'legend') $legendPage = $arg;
 637+ if ($cmd[0] == 'table') $table = $arg;
580638
581 - // we execute only if "exec" is given, otherwise we merely show what would be done
582 - if ($cmd[0] == 'exec') {
583 - // $message.= "exec = true\n";
584 - $exec=true;
585 - }
 639+ if ($cmd[0] == 'replace') $replaceThis=$arg;
 640+ if ($cmd[0] == 'by') $replacement=$arg;
586641
 642+ if ($cmd[0] == 'editform') $editForm=$arg;
 643+ if ($cmd[0] == 'action') $action=$arg;
 644+ if ($cmd[0] == 'hidden') $hidden[]=$arg;
 645+ if ($cmd[0] == 'submit') $submit[]=$arg;
 646+ if ($cmd[0] == 'commit') $commit[]=$arg;
587647
 648+ if ($cmd[0] == 'summary') $summary=$arg;
 649+ if ($cmd[0] == 'exec') $exec=$arg; // we execute only if "exec" is 'save' or 'preview', otherwise we show an edit dialogue
588650 }
 651+
589652 if ($summary=='') {
590653 $summary .= "\nbulk update:";
591654 if ($replaceThis!='') $summary .= "\n replace $replaceThis\n by $replacement";
@@ -594,6 +657,8 @@
595658
596659 // $message.= '</nowiki></pre>';
597660
 661+ // perform changes to the wiki source text =======================================
 662+
598663 if ($replaceThis!='') {
599664 $text = preg_replace("$replaceThis",$replacement,$text);
600665 }
@@ -605,17 +670,275 @@
606671 if ($insertionAfter!='' && $after != '') {
607672 $text = preg_replace("/($after)/",'\1'.$insertionAfter,$text);
608673 }
 674+
 675+ // deal with template parameters =================================================
 676+
 677+ global $wgRequest;
609678
 679+ if ($template!='') {
 680+
 681+ if ($exec=='edit') {
 682+ $tpv = $this->getTemplateParmValues($text,$template);
 683+ $legendText='';
 684+ if ($legendPage!='') {
 685+ $legendTitle='';
 686+ global $wgParser;
 687+ $parser = clone $wgParser;
 688+ DPLInclude::text($parser, $legendPage, $legendTitle, $legendText);
 689+ $legendText = preg_replace('/^.*?\<section\s+begin\s*=\s*legend\s*\/\>/s','',$legendText);
 690+ $legendText = preg_replace('/\<section\s+end\s*=\s*legend\s*\/\>.*/s','',$legendText);
 691+ }
 692+ // construct an edit form containing all template invocations
 693+ $form="<html><form action=\"$action\" $editForm>\n";
 694+ foreach ($tpv as $call => $tplValues) {
 695+ $form .= "<table $table>\n";
 696+ foreach ($parameter as $nr => $parm) {
 697+ // try to extract legend from the docs of the template
 698+ $myToolTip=''; if (array_key_exists($nr,$tooltip)) $myToolTip = $tooltip[$nr];
 699+ $myFormat='' ; if (array_key_exists($nr,$format)) $myFormat = $format[$nr];
 700+ $myOptional=array_key_exists($nr,$optional);
 701+ if ($legendText !='' && $myToolTip=='') {
 702+ $myToolTip=preg_replace('/^.*\<section\s+begin\s*=\s*'.preg_quote($parm,'/').'\s*\/\>/s','',$legendText);
 703+ if (strlen($myToolTip)==strlen($legendText)) {
 704+ $myToolTip='';
 705+ } else {
 706+ $myToolTip=preg_replace('/\<section\s+end\s*=\s*'.preg_quote($parm,'/').'\s*\/\>.*/s','',$myToolTip);
 707+ }
 708+ }
 709+ $myValue=''; if (array_key_exists($parm,$tpv[$call])) $myValue=$tpv[$call][$parm];
 710+ $form .= $this->editTemplateCall($text,$template,$call,$parm,$myValue,$myFormat,$myToolTip,$myOptional);
 711+ }
 712+ $form .= "</table>\n<br/><br/>";
 713+ }
 714+ foreach($hidden as $hide) {
 715+ $form.= "<input type=hidden ".$hide." /> ";
 716+ }
 717+ foreach($submit as $subm) {
 718+ $form.= "<input type=submit ".$subm." /> ";
 719+ }
 720+ $form .= "</form></html>\n";
 721+ return $form;
 722+ }
 723+ else if ($exec=='set' || $exec=='save' || $exec=='preview') {
 724+ // loop over all invocations and parameters, this could be improved to enhance performance
 725+ $matchCount=10;
 726+ for ($call=0; $call<10; $call++) {
 727+ foreach ($parameter as $nr => $parm) {
 728+ // set parameters to values specified in the dpl source or get them from the http request
 729+ if ($exec=='set') $myvalue=$value[$nr];
 730+ else {
 731+ if ($call>= $matchCount) break;
 732+ $myValue= $wgRequest->getVal(urlencode($call.'_'.$parm),'');
 733+ }
 734+ $myOptional= array_key_exists($nr,$optional);
 735+ $myAfterParm=array(); if (array_key_exists($nr,$afterparm)) $myAfterParm = $afterparm[$nr];
 736+ $text = $this->updateTemplateCall($matchCount,$text,$template,$call,$parm,$myValue,$myAfterParm,$myOptional);
 737+ }
 738+ if ($exec=='set') break; // values taken from dpl text only populate the first invocation
 739+ }
 740+ }
 741+ else if ($exec=='commit') {
 742+ // we expect the contents of an article to be saved
 743+ $text=$wgRequest->getVal('pageText','');
 744+ if ($text=='') return "DPL: no 'pageText' found.";
 745+ else {
 746+ $titleX = Title::newFromText($title);
 747+ global $wgArticle;
 748+ $wgArticle = $articleX = new Article($titleX);
 749+ $articleX->updateArticle($text, $summary, false, $titleX->userIsWatching());
 750+ return '';
 751+ }
 752+ }
 753+ }
 754+
610755 $titleX = Title::newFromText($title);
611756 global $wgArticle;
612757 $wgArticle = $articleX = new Article($titleX);
613 - if ($exec) $articleX->updateArticle($text, $summary, false, $titleX->userIsWatching());
614 - else $message .= "set 'exec yes' to perform the following modification to &nbsp; &nbsp; <big>'''$title'''</big>\n";
615 - $message .= "<pre><nowiki>"
616 - ."\n".$text."</nowiki></pre>"; // <pre><nowiki>\n"; // .$text."\n</nowiki></pre>\n";
617 - return $message;
 758+ if ($exec=='save' || $exec=='set') {
 759+ $articleX->updateArticle($text, $summary, false, $titleX->userIsWatching());
 760+ return '';
 761+ }
 762+ else if ($exec=='preview'){
 763+ $form ="<html><form action=\"$action\" $editForm>\n";
 764+ $form.= "<textarea name=pageText rows=30 cols=100>".htmlspecialchars($text)."</textarea>";
 765+ foreach($hidden as $hide) {
 766+ $form.= "<input type=hidden ".$hide." /> ";
 767+ }
 768+ foreach($commit as $comm) {
 769+ $form.= "<input type=submit ".$comm." /> ";
 770+ }
 771+ $form .= "</form></html>\n";
 772+ return $form;
 773+ }
 774+ return "exec must be one of the following: edit, preview, save, set, commit";
618775 }
619776
 777+ function editTemplateCall($text,$template,$call,$parameter,$value,$format,$tooltip,$optional) {
 778+ return "<tr><td align=\"right\" title=\"".htmlspecialchars($tooltip)."\">".str_replace('_',' ',$parameter)."</td><td><textarea name=\"".
 779+ urlencode($call.'_'.$parameter)."\" $format/>".htmlspecialchars($value)."</textarea></td>".
 780+ "<td><small>$tooltip</small></td></tr>";
 781+ }
 782+
 783+ /**
 784+ * return an array of template invocations; each element is an associative array of parameter and value
 785+ */
 786+ function getTemplateParmValues($text,$template) {
 787+ $matches=array();
 788+ $noMatches = preg_match_all('/\{\{\s*'.preg_quote($template,'/').'\s*[|}]/i',$text,$matches,PREG_OFFSET_CAPTURE);
 789+ if ($noMatches<=0) return '';
 790+ $textLen = strlen($text);
 791+ $tval=array(); // the result array of template values
 792+ $call=-1; // index for tval
 793+
 794+ foreach($matches as $matchA) {
 795+ foreach($matchA as $matchB) {
 796+ $match=$matchB[0];
 797+ $start=$matchB[1];
 798+
 799+ $tval[++$call]=array();
 800+ $nr=0; // number of parameter if no name given
 801+ $parmValue='';
 802+ $parmName='';
 803+ $parm='';
 804+
 805+ if ($match[strlen($match)-1]=='}') break; // template was called without parameters, continue with next invocation
 806+
 807+ // search to the end of the template call
 808+ $cbrackets=2;
 809+ for ($i=$start+strlen($match); $i<$textLen;$i++) {
 810+ $c = $text[$i];
 811+ if ($c == '{' || $c=='[') $cbrackets++; // we count both types of brackets
 812+ if ($c == '}' || $c==']') $cbrackets--;
 813+ if (($cbrackets==2 && $c=='|') || ($cbrackets==1 && $c=='}')) {
 814+ // parameter (name or value) found
 815+ if ($parmName=='') $tval[$call][++$nr] = trim($parm);
 816+ else $tval[$call][$parmName] = trim($parmValue);
 817+ $parmName='';
 818+ $parmValue='';
 819+ $parm='';
 820+ continue;
 821+ }
 822+ else {
 823+ if ($parmName=='') {
 824+ if ($c=='=') $parmName = trim($parm);
 825+ }
 826+ else {
 827+ $parmValue.=$c;
 828+ }
 829+ }
 830+ $parm.=$c;
 831+ if ($cbrackets==0) break; // end of parameter list
 832+ }
 833+ }
 834+ }
 835+ return $tval;
 836+ }
 837+
 838+ /*
 839+ * Changes a single parameter value within a certain call of a tempplate
 840+ */
 841+ function updateTemplateCall(&$matchCount, $text,$template,$call,$parameter,$value,$afterParm,$optional) {
 842+
 843+ // if parameter is optional and value is empty we leave everything as it is (i.e. we do not remove the parm)
 844+ if ($optional && $value=='') return $text;
 845+
 846+ $matches=array();
 847+ $noMatches = preg_match_all('/\{\{\s*'.preg_quote($template,'/').'\s*[|}]/i',$text,$matches,PREG_OFFSET_CAPTURE);
 848+ if ($noMatches<=0) return $text;
 849+ $rText='';
 850+ $beginSubst=-1;
 851+ $endSubst=-1;
 852+ $posInsertAt=0;
 853+ $apNrLast=1000; // last (optional) predecessor
 854+
 855+ foreach($matches as $matchA) {
 856+ $matchCount=count($matchA);
 857+ foreach($matchA as $occurence => $matchB) {
 858+ if ($occurence < $call) continue;
 859+ $match=$matchB[0];
 860+ $start=$matchB[1];
 861+
 862+ if ($match[strlen($match)-1]=='}') {
 863+ // template was called without parameters, add new parameter and value
 864+ // append parameter and value
 865+ $beginSubst=$i;
 866+ $endSubst=$i;
 867+ $substitution="|$parameter = $value";
 868+ break;
 869+ }
 870+ else {
 871+ // there is already a list of parameters; we search to the end of the template call
 872+ $cbrackets=2;
 873+ $parm='';
 874+ $pos=$start+strlen($match);
 875+ $textLen = strlen($text);
 876+ for ($i=$pos; $i<$textLen;$i++) {
 877+ $c = $text[$i];
 878+ if ($c == '{' || $c=='[') $cbrackets++; // we count both types of brackets
 879+ if ($c == '}' || $c==']') $cbrackets--;
 880+ if (($cbrackets==2 && $c=='|') || ($cbrackets==1 && $c=='}')) {
 881+ // parameter (name / value) found
 882+
 883+ $token = split('=',$parm,2);
 884+ if (count($token)==2) {
 885+ // we need a pair of name / value
 886+ $parmName=trim($token[0]);
 887+ if ($parmName == $parameter) {
 888+ // we found the parameter, now replace the current value
 889+ $parmValue=trim($token[1]);
 890+ if ($parmValue==$value) break; // no need to change when values are identical
 891+ // keep spaces;
 892+ $substitution = str_replace($parmValue,$value,$token[1]);
 893+ $beginSubst=$pos+strlen($token[0])+1;
 894+ $endSubst=$i;
 895+ break;
 896+ }
 897+ else {
 898+ foreach ($afterParm as $apNr => $ap) {
 899+ // store position for insertion
 900+ if ($parmName==$ap && $apNr<$apNrLast) {
 901+ $posInsertAt = $i;
 902+ $apNrLast = $apNr;
 903+ break;
 904+ }
 905+ }
 906+ }
 907+ }
 908+
 909+ if ($c=='}') {
 910+ // end of template call reached, insert at stored position or here
 911+ if ($posInsertAt !=0) $beginSubst=$posInsertAt;
 912+ else $beginSubst=$i;
 913+ $substitution= "|$parameter = $value";
 914+ if ($text[$beginSubst-1]=="\n") {
 915+ --$beginSubst;
 916+ $substitution="\n".$substitution;
 917+ }
 918+ $endSubst=$beginSubst;
 919+ break;
 920+ }
 921+
 922+ $pos=$i;
 923+ $parm='';
 924+ }
 925+ else {
 926+ $parm .= $c;
 927+ }
 928+ if ($cbrackets==0) {
 929+ break;
 930+ }
 931+ }
 932+ }
 933+ break;
 934+ }
 935+ break;
 936+ }
 937+
 938+ if ($beginSubst<0) return $text;
 939+ return substr($text,0,$beginSubst).$substitution.substr($text,$endSubst);
 940+
 941+ }
 942+
620943 function deleteArticleByRule($title,$text,$rulesText) {
621944 // we use ; as command delimiter; \; stands for a semicolon
622945 // \n is translated to a real linefeed
Index: trunk/extensions/DynamicPageList/DPLSetup.php
@@ -346,10 +346,22 @@
347347 * removed replacement of card suit symbols in SQL query due to collation incompatibilities
348348 * added special logic to DPL_fromTitle: reversed sort order for backward scrolling
349349 * changed default sort in DPL to 'titlewithoutnamespace (as this is more efficient than 'title')
350 - * bugfix at ordermethod = titlewithoutnamespace (led to invalid SQL statements)
351350 * @version 1.8.6
 351+ * bugfix at ordermethod = titlewithoutnamespace (led to invalid SQL statements)
 352+ * @version 1.8.7
 353+ * experimental calls to the CacheAPI; can be switched off by $useCacheAPI = false;
 354+ * one can set option[eliminate] to 'all' in LocalSettings now as a default
 355+ * editrulesnow takes several triples of 'parameter', 'value' and 'afterparm'
 356+ * editrules can now produce a screen form to change template values
 357+ * title< and title> now test for greater or less; if you want greater/equal the argument must start with "= "
 358+ * the majority of the php modules are now only loaded if a page contains a DPL statement
 359+ * added %DPL_findTitle%
 360+ * first letter changed toUpper in %DPL_fromTitle%, %DPL_toTitle%, %DPL_findTitle%,
 361+ * enhanced syntax for include : [limit text~skipPattern]
 362+ * UNIQ-QINU Bug resolved
 363+ * convert spaces to underscores in all category (regexp) statements
 364+ * we convert html entities in the category command to avoid false interpretation of & as AND
352365 *
353 - *
354366 * ! when making changes here you must update the version field in DynamicPageList.php and DynamicPageListMigration.php !
355367 */
356368
@@ -370,7 +382,11 @@
371383
372384 public static $DPLVersion = '?'; // current version is set by DynamicPageList.php and DynamicPageListMigration.php
373385
 386+ public static $useCacheAPI = true; // decide whether we use another extension called CachePI which can help us
 387+ // to invalidate MediaWiki´s ParserCache if suitable
374388
 389+ public static $modulesLoaded = false; // php require_once control
 390+
375391 /**
376392 * Extension options
377393 */
@@ -1040,8 +1056,6 @@
10411057
10421058 global $wgParser;
10431059
1044 - self::loadModules();
1045 -
10461060 // DPL offers the same functionality as Intersection; so we register the <DynamicPageList> tag
10471061 // in case LabeledSection Extension is not installed we need to remove section markers
10481062
@@ -1057,7 +1071,6 @@
10581072 }
10591073
10601074 public static function setupMigration() {
1061 - self::loadModules();
10621075
10631076 // DPL offers the same functionality as Intersection under the tag name <Intersection>
10641077 global $wgParser;
@@ -1067,7 +1080,30 @@
10681081 }
10691082
10701083 private static function commonSetup() {
 1084+
 1085+ if (!isset(self::$createdLinks)) {
 1086+ self::$createdLinks=array(
 1087+ 'resetLinks'=> false, 'resetTemplates' => false,
 1088+ 'resetCategories' => false, 'resetImages' => false, 'resetdone' => false , 'elimdone' => false );
 1089+ }
10711090
 1091+ // make sure page "Template:Extension DPL" exists
 1092+ $title = Title::newFromText('Template:Extension DPL');
 1093+ global $wgUser;
 1094+ if (!$title->exists() && $wgUser->isAllowed('edit')) {
 1095+ $article = new Article($title);
 1096+ $article->doEdit( "<noinclude>This page was automatically created. It serves as an anchor page for ".
 1097+ "all '''[[Special:WhatLinksHere/Template:Extension_DPL|invocations]]''' ".
 1098+ "of [http://mediawiki.org/wiki/Extension:DynamicPageList Extension:DynamicPageList (DPL)].</noinclude>",
 1099+ $title, EDIT_NEW | EDIT_FORCE_BOT );
 1100+ die(header('Location: '.Title::newFromText('Template:Extension DPL')->getFullURL()));
 1101+ }
 1102+
 1103+ }
 1104+
 1105+ private static function loadMessages() {
 1106+
 1107+ require_once( 'DynamicPageList.i18n.php' );
10721108 global $wgMessageCache;
10731109
10741110
@@ -1088,36 +1124,22 @@
10891125 self::$debugMinLevels[$i] = $minlevel;
10901126 }
10911127
1092 - if (!isset(self::$createdLinks)) {
1093 - self::$createdLinks=array(
1094 - 'resetLinks'=> false, 'resetTemplates' => false,
1095 - 'resetCategories' => false, 'resetImages' => false, 'resetdone' => false );
1096 - }
1097 -
1098 - // make sure page "Template:Extension DPL" exists
1099 - $title = Title::newFromText('Template:Extension DPL');
1100 - global $wgUser;
1101 - if (!$title->exists() && $wgUser->isAllowed('edit')) {
1102 - $article = new Article($title);
1103 - $article->doEdit( "<noinclude>This page was automatically created. It serves as an anchor page for ".
1104 - "all '''[[Special:WhatLinksHere/Template:Extension_DPL|invocations]]''' ".
1105 - "of [http://mediawiki.org/wiki/Extension:DynamicPageList Extension:DynamicPageList (DPL)].</noinclude>",
1106 - $title, EDIT_NEW | EDIT_FORCE_BOT );
1107 - die(header('Location: '.Title::newFromText('Template:Extension DPL')->getFullURL()));
1108 - }
1109 -
11101128 }
11111129
11121130 private static function loadModules() {
 1131+
 1132+ if (self::$modulesLoaded == true) return;
11131133
1114 - // Page Transclusion, adopted from Steve Sanbeg´s LabeledSectionTransclusion
 1134+ self::loadMessages();
 1135+
11151136 require_once( 'DynamicPageListInclude.php' );
1116 - require_once( 'DynamicPageList.i18n.php' );
11171137 require_once( 'DPL.php' );
11181138 require_once( 'DPLMain.php' );
11191139 require_once( 'DPLArticle.php' );
11201140 require_once( 'DPLListMode.php' );
11211141 require_once( 'DPLLogger.php' );
 1142+
 1143+ self::$modulesLoaded = true;
11221144 }
11231145
11241146 public static function languageGetMagic( &$magicWords, $langCode ) {
@@ -1148,6 +1170,9 @@
11491171 // The callback function wrapper for converting the input text to HTML output
11501172 private static function executeTag( $input, $params, &$parser ) {
11511173
 1174+ // late loading of php modules, only if needed
 1175+ self::loadModules();
 1176+
11521177 // entry point for user tag <dpl> or <DynamicPageList>
11531178 // create list and do a recursive parse of the output
11541179
@@ -1183,6 +1208,9 @@
11841209 //------------------------------------------------------------------------------------- ENTRY parser FUNCTION #dpl
11851210 public static function dplParserFunction(&$parser) {
11861211
 1212+ // late loading of php modules, only if needed
 1213+ self::loadModules();
 1214+
11871215 self::behaveLikeIntersection(false);
11881216
11891217 // callback for the parser function {{#dpl: or {{DynamicPageList::
@@ -1302,74 +1330,13 @@
13031331 }
13041332
13051333 private static function dumpParsedRefs($parser,$label) {
1306 - if (!preg_match("/Query Q/",$parser->mTitle->getText())) return '';
1307 - $text="\n<pre>$label:\n";
1308 - /*
1309 - $text.=" control:";
1310 - foreach (self::$createdLinks as $key => $val) {
1311 - if (is_array($val)) continue;
1312 - $text.= "$val($key),";
1313 - }
1314 - $text.="\n";
1315 - */
1316 - $text.=" categories:";
1317 - foreach ($parser->mOutput->mCategories as $key => $val ) {
1318 - $text .= "$val($key),";
1319 - }
1320 - $text.="\n";
1321 - if (array_key_exists(2,self::$createdLinks)) {
1322 - $text.=" CATEGORIES:";
1323 - foreach (self::$createdLinks[2] as $val ) {
1324 - $text .= "$val,";
1325 - }
1326 - $text.="\n";
1327 - }
1328 - $text.=" links:";
1329 - foreach ($parser->mOutput->mLinks as $lkey => $lval ) {
1330 - $text .= "$lval($lkey)={";
1331 - foreach ($lval as $key => $val ) {
1332 - $text .= "$val($key),";
1333 - }
1334 - $text .= "},";
1335 - }
1336 - $text.="\n";
1337 - if (array_key_exists(0,self::$createdLinks)) {
1338 - $text.=" LINKS:";
1339 - foreach (self::$createdLinks[0] as $val ) {
1340 - $text .= "$val,";
1341 - }
1342 - $text.="\n";
1343 - }
1344 - $text.=" templates:";
1345 - foreach ($parser->mOutput->mTemplates as $tkey => $tval ) {
1346 - $text .= "$tval($tkey)={";
1347 - foreach ($tval as $key => $val ) {
1348 - $text .= "$val($key),";
1349 - }
1350 - $text .= "},";
1351 - }
1352 - $text.="\n";
1353 - if (array_key_exists(1,self::$createdLinks)) {
1354 - $text.=" TEMPLATES:";
1355 - foreach (self::$createdLinks[1] as $val ) {
1356 - $text .= "$val,";
1357 - }
1358 - $text.="\n";
1359 - }
1360 - $text.=" images:";
1361 - foreach ($parser->mOutput->mImages as $key => $val ) {
1362 - $text .= "$val($key),";
1363 - }
1364 - $text.="\n";
1365 - if (array_key_exists(3,self::$createdLinks)) {
1366 - $text.=" IMAGES:";
1367 - foreach (self::$createdLinks[3] as $val ) {
1368 - $text .= "$val,";
1369 - }
1370 - $text.="\n";
1371 - }
1372 - $text.="</pre>\n";
1373 - return $text;
 1334+ //if (!preg_match("/Query Q/",$parser->mTitle->getText())) return '';
 1335+ echo '<pre>parser mLinks: ';
 1336+ ob_start(); var_dump($parser->mOutput->mLinks); $a=ob_get_contents(); ob_end_clean(); echo htmlspecialchars($a,ENT_QUOTES);
 1337+ echo '</pre>';
 1338+ echo '<pre>parser mTemplates: ';
 1339+ ob_start(); var_dump($parser->mOutput->mTemplates); $a=ob_get_contents(); ob_end_clean(); echo htmlspecialchars($a,ENT_QUOTES);
 1340+ echo '</pre>';
13741341 }
13751342
13761343 //remove section markers in case the LabeledSectionTransclusion extension is not installed.
@@ -1391,54 +1358,59 @@
13921359 }
13931360
13941361 public static function endEliminate( &$parser, &$text ) {
 1362+
13951363 // called during the final output phase; removes links created by DPL
1396 - if (isset(self::$createdLinks) || !self::$createdLinks['elimdone']) {
1397 - self::$createdLinks['elimdone'] = true;
1398 - // $text .= self::dumpParsedRefs($parser,"before final eliminate");
1399 - if (isset(self::$createdLinks) && array_key_exists(0,self::$createdLinks)) {
1400 - foreach ($parser->mOutput->getLinks() as $linkKey => $link) {
1401 - foreach ($link as $key => $val) {
1402 - if (array_key_exists($key,self::$createdLinks[0])) {
1403 - unset($parser->mOutput->mLinks[$linkKey][$key]);
1404 - // $text .= "removing link: $val($key);";
1405 - }
1406 - }
1407 - if (count($parser->mOutput->mLinks[$linkKey])==0) {
1408 - unset ($parser->mOutput->mLinks[$linkKey]);
1409 - }
 1364+ if (isset(self::$createdLinks)) {
 1365+ // self::dumpParsedRefs($parser,"before final eliminate");
 1366+ if (array_key_exists(0,self::$createdLinks)) {
 1367+ foreach ($parser->mOutput->getLinks() as $nsp => $link) {
 1368+ if (!array_key_exists($nsp,self::$createdLinks[0])) continue;
 1369+ // echo ("<pre> elim: created Links [$nsp] = ". count(ExtDynamicPageList::$createdLinks[0][$nsp])."</pre>\n");
 1370+ // echo ("<pre> elim: parser Links [$nsp] = ". count($parser->mOutput->mLinks[$nsp]) ."</pre>\n");
 1371+ $parser->mOutput->mLinks[$nsp] = array_diff_assoc($parser->mOutput->mLinks[$nsp],self::$createdLinks[0][$nsp]);
 1372+ // echo ("<pre> elim: parser Links [$nsp] nachher = ". count($parser->mOutput->mLinks[$nsp]) ."</pre>\n");
 1373+ if (count($parser->mOutput->mLinks[$nsp])==0) unset ($parser->mOutput->mLinks[$nsp]);
14101374 }
14111375 }
14121376 if (isset(self::$createdLinks) && array_key_exists(1,self::$createdLinks)) {
1413 - foreach ($parser->mOutput->getTemplates() as $tplKey => $tpl) {
1414 - foreach ($tpl as $key => $val) {
1415 - if (in_array($val,self::$createdLinks[1])) {
1416 - unset($parser->mOutput->mTemplates[$tplKey][$key]);
1417 - // $text .= "removing use of template: $val($key);";
1418 - }
1419 - }
1420 - if (count($parser->mOutput->mTemplates[$tplKey])==0) {
1421 - unset ($parser->mOutput->mTemplates[$tplKey]);
1422 - }
 1377+ foreach ($parser->mOutput->mTemplates as $nsp => $tpl) {
 1378+ if (!array_key_exists($nsp,self::$createdLinks[1])) continue;
 1379+ // echo ("<pre> elim: created Tpls [$nsp] = ". count(ExtDynamicPageList::$createdLinks[1][$nsp])."</pre>\n");
 1380+ // echo ("<pre> elim: parser Tpls [$nsp] = ". count($parser->mOutput->mTemplates[$nsp]) ."</pre>\n");
 1381+ $parser->mOutput->mTemplates[$nsp] = array_diff_assoc($parser->mOutput->mTemplates[$nsp],self::$createdLinks[1][$nsp]);
 1382+ // echo ("<pre> elim: parser Tpls [$nsp] nachher = ". count($parser->mOutput->mTemplates[$nsp]) ."</pre>\n");
 1383+ if (count($parser->mOutput->mTemplates[$nsp])==0) unset ($parser->mOutput->mTemplates[$nsp]);
14231384 }
14241385 }
14251386 if (isset(self::$createdLinks) && array_key_exists(2,self::$createdLinks)) {
1426 - foreach (self::$createdLinks[2] as $cat) {
1427 - unset($parser->mOutput->mCategories[$cat]);
1428 - // $text .= "removing cat: $cat;";
1429 - }
 1387+ $parser->mOutput->mCategories = array_diff_assoc($parser->mOutput->mCategories,self::$createdLinks[2]);
14301388 }
14311389 if (isset(self::$createdLinks) && array_key_exists(3,self::$createdLinks)) {
1432 - foreach (self::$createdLinks[3] as $img) {
1433 - unset($parser->mOutput->mImages[$img]);
1434 - // $text .= "removing img: $img;";
1435 - }
 1390+ $parser->mOutput->mImages = array_diff_assoc($parser->mOutput->mImages,self::$createdLinks[3]);
14361391 }
14371392 // $text .= self::dumpParsedRefs($parser,"after final eliminate".$parser->mTitle->getText());
14381393 }
1439 - self::$createdLinks=array(
1440 - 'resetLinks'=> false, 'resetTemplates' => false,
1441 - 'resetCategories' => false, 'resetImages' => false, 'resetdone' => false );
 1394+
 1395+ //self::$createdLinks=array(
 1396+ // 'resetLinks'=> false, 'resetTemplates' => false,
 1397+ // 'resetCategories' => false, 'resetImages' => false, 'resetdone' => false );
14421398 return true;
14431399 }
14441400
14451401 }
 1402+
 1403+class MyBug {
 1404+
 1405+ static function trace($class,$label,$msg) {
 1406+ $fileName = dirname(__FILE__).'/MyBug';
 1407+ if ($class=='') {
 1408+ if (file_exists($fileName)) unlink(dirname(__FILE__).'/MyBug');
 1409+ return;
 1410+ }
 1411+ $bugFile=fopen($fileName,'a');
 1412+ fwrite($bugFile,"$class -------------------------------------------------------------------------------------------- $label\n");
 1413+ fwrite($bugFile,$msg."\n");
 1414+ fclose($bugFile);
 1415+ }
 1416+
 1417+}
\ No newline at end of file
Index: trunk/extensions/DynamicPageList/DynamicPageListInclude.php
@@ -93,6 +93,8 @@
9494 * removal of html-comments within template calls
9595 * @version 1.8.5
9696 * includeTemplate understands parser function syntax now
 97+ * @version 1.8.7
 98+ * UNIQ-QINU-Bug: replaced parser->replaceVariables by parser->preprocess
9799
98100 */
99101
@@ -133,7 +135,7 @@
134136 * Handle recursive substitution here, so we can break cycles, and set up
135137 * return values so that edit sections will resolve correctly.
136138 **/
137 - private static function parse($parser, $title, $text, $part1, $skiphead=0, $recursionCheck=true, $maxLength=-1, $link='', $trim=false)
 139+ private static function parse($parser, $title, $text, $part1, $skiphead=0, $recursionCheck=true, $maxLength=-1, $link='', $trim=false, $skipPattern='')
138140 {
139141 global $wgVersion;
140142
@@ -141,6 +143,11 @@
142144 // text, may as well do the right thing.
143145 $text = str_replace('</section>', '', $text);
144146
 147+ // if desired we remove portions of the text, esp. template calls
 148+ if ($skipPattern!='') {
 149+ $text=preg_replace($skipPattern,'',$text);
 150+ }
 151+
145152
146153 if (self::open($parser, $part1)) {
147154
@@ -150,10 +157,11 @@
151158 //release, so this is close enough.
152159
153160 if(version_compare( $wgVersion, "1.9" ) < 0 || $recursionCheck == false) {
154 - $text = $parser->replaceVariables($text);
155 - self::close($parser, $part1);
 161+
 162+ $text = $parser->preprocess($text,$parser->mTitle,$parser->mOptions);
 163+ self::close($parser, $part1);
156164 }
157 -
 165+
158166 if ($maxLength>0) {
159167 $text = self::limitTranscludedText($text,$maxLength,$link);
160168 }
@@ -214,7 +222,7 @@
215223 return preg_match_all( "/$pat/im", substr($text,0,$limit), $m);
216224 }
217225
218 - private static function text($parser, $page, &$title, &$text)
 226+ public static function text($parser, $page, &$title, &$text)
219227 {
220228 $title = Title::newFromText($page);
221229
@@ -235,7 +243,7 @@
236244 }
237245
238246 ///section inclusion - include all matching sections
239 - public static function includeSection($parser, $page='', $sec='', $to='', $recursionCheck=true, $trim=false) {
 247+ public static function includeSection($parser, $page='', $sec='', $to='', $recursionCheck=true, $trim=false, $skipPattern='') {
240248 $output = array();
241249 if (self::text($parser, $page, $title, $text) == false) {
242250 $output[] = $text;
@@ -247,7 +255,7 @@
248256 preg_match_all( $pat, $text, $m, PREG_PATTERN_ORDER);
249257
250258 foreach ($m[2] as $nr=>$piece) {
251 - $piece = self::parse($parser,$title,$piece, "#lst:${page}|${sec}", 0, $recursionCheck, $trim);
 259+ $piece = self::parse($parser,$title,$piece, "#lst:${page}|${sec}", 0, $recursionCheck, $trim, $skipPattern);
252260 if ($any) $output[] = $m[1][$nr].'::'.$piece;
253261 else $output[] = $piece;
254262 }
@@ -297,7 +305,7 @@
298306 }
299307
300308 public static function includeHeading($parser, $page='', $sec='', $to='', &$sectionHeading, $recursionCheck=true, $maxLength=-1,
301 - $link='default', $trim=false)
 309+ $link='default', $trim=false, $skipPattern='')
302310 {
303311 $output=array();
304312 if (self::text($parser, $page, $title, $text) == false) {
@@ -305,12 +313,12 @@
306314 return $output;
307315 }
308316
309 - return self::extractHeadingFromText($parser, $page, $title, $text, $sec, $to, $sectionHeading, $recursionCheck, $maxLength, $link, $trim);
 317+ return self::extractHeadingFromText($parser, $page, $title, $text, $sec, $to, $sectionHeading, $recursionCheck, $maxLength, $link, $trim, $skipPattern);
310318 }
311319
312320 //section inclusion - include all matching sections (return array)
313321 public static function extractHeadingFromText($parser, $page, $title, $text, $sec='', $to='', &$sectionHeading, $recursionCheck=true,
314 - $maxLength=-1, $link='default', $trim=false) {
 322+ $maxLength=-1, $link='default', $trim=false, $skipPattern='' ) {
315323
316324 // create a link symbol (arrow, img, ...) in case we have to cut the text block to maxLength
317325 if ($link=='default') $link = ' [['.$page.'#'.$sec.'|..&rarr;]]';
@@ -355,7 +363,7 @@
356364 if ($nr==-2) {
357365 // output text before first section and done
358366 $piece = substr($text,0,$m[1][1]-1);
359 - $output[0] = self::parse($parser,$title,$piece, "#lsth:${page}|${sec}", 0, $recursionCheck, $maxLength, $link, $trim);
 367+ $output[0] = self::parse($parser,$title,$piece, "#lsth:${page}|${sec}", 0, $recursionCheck, $maxLength, $link, $trim, $skipPattern);
360368 return $output;
361369 }
362370
@@ -404,20 +412,21 @@
405413 else $sectionHeading[$n] = '';
406414 if ($nr==1) {
407415 // output n-th section and done
408 - $output[0] = self::parse($parser,$title,$piece, "#lsth:${page}|${sec}", $nhead, $recursionCheck, $maxLength, $link, $trim);
 416+ $output[0] = self::parse($parser,$title,$piece, "#lsth:${page}|${sec}", $nhead, $recursionCheck, $maxLength, $link, $trim, $skipPattern);
409417 break;
410418 }
411419 if ($nr==-1) {
412420 if (!isset($end_off)) {
413421 // output last section and done
414 - $output[0] = self::parse($parser,$title,$piece, "#lsth:${page}|${sec}", $nhead, $recursionCheck, $maxLength, $link, $trim);
 422+ $output[0] = self::parse($parser,$title,$piece, "#lsth:${page}|${sec}", $nhead, $recursionCheck, $maxLength, $link, $trim, $skipPattern);
415423 break;
416424 }
417425 } else {
418426 // output section by name and continue search for another section with the same name
419 - $output[$n++] = self::parse($parser,$title,$piece, "#lsth:${page}|${sec}", $nhead, $recursionCheck, $maxLength, $link, $trim);
 427+ $output[$n++] = self::parse($parser,$title,$piece, "#lsth:${page}|${sec}", $nhead, $recursionCheck, $maxLength, $link, $trim, $skipPattern);
420428 }
421429 } while ($continueSearch);
 430+
422431 return $output;
423432 }
424433
@@ -436,7 +445,7 @@
437446 $user = $article->mUserLink;
438447 $title = Title::newFromText($page);
439448 $text = $parser->fetchTemplate($title);
440 -
 449+
441450 if ($template1 != '' && $template1[0]=='#') {
442451 $template1=substr($template1,1);
443452 $template2=substr($template2,1);
@@ -490,7 +499,9 @@
491500 else $output[0]=$dpl->formatTemplateArg('',$dplNr,0,true,-1);
492501 } else {
493502 // put a red link into the output
494 - $output[0]= $parser->replaceVariables('{{'.$defaultTemplate.'|%PAGE%='.$page.'|%TITLE%='.$title->getText().'|%DATE%='.$date.'|%USER%='.$user.'}}');
 503+ $output[0]= $parser->preprocess(
 504+ '{{'.$defaultTemplate.'|%PAGE%='.$page.'|%TITLE%='.$title->getText().'|%DATE%='.$date.'|%USER%='.$user.'}}',
 505+ $parser->mTitle,$parser->mOptions);
495506 }
496507 return $output;
497508 }
@@ -519,9 +530,9 @@
520531 // if we must match a condition: test against it
521532 if (($mustMatch =='' || preg_match($mustMatch,substr($templateCall,0,$i-1))) &&
522533 ($mustNotMatch=='' || !preg_match($mustNotMatch,substr($templateCall,0,$i-1)))) {
523 - $output[++$n] = $parser->replaceVariables(substr($templateCall,0,$i-1).
524 - '|%PAGE%='.$page.'|%TITLE%='.$title->getText().'|%DATE%='.$date.'|%USER%='.$user.'}}');
525 - }
 534+ $output[++$n] = $parser->preprocess(substr($templateCall,0,$i-1).
 535+ '|%PAGE%='.$page.'|%TITLE%='.$title->getText().'|%DATE%='.$date.'|%USER%='.$user.'}}',$parser->mTitle,$parser->mOptions);
 536+ }
526537 break;
527538 }
528539 }
@@ -534,6 +545,7 @@
535546 $parms=array();
536547 $parm='';
537548 $hasParm=false;
 549+
538550 for ($i=0; $i<$size;$i++) {
539551 $c = $templateCall[$i];
540552 if ($c == '{' || $c=='[') $cbrackets++; // we count both types of brackets
Index: trunk/extensions/DynamicPageList/DPLMain.php
@@ -19,7 +19,7 @@
2020 error_reporting(E_ALL);
2121
2222 global $wgUser, $wgLang, $wgContLang, $wgRequest, $wgRawHtml;
23 - global $wgTitle, $wgNonincludableNamespaces;
 23+ global $wgTitle, $wgArticle, $wgNonincludableNamespaces;
2424
2525 // we use "makeKnownLinkObject" to create hyperlinbks;
2626 // the code we store in the dplcache may contain <html>....</html> sequences
@@ -50,8 +50,13 @@
5151 // check if DPL shall only be executed from protected pages
5252 if (array_key_exists('RunFromProtectedPagesOnly',ExtDynamicPageList::$options) &&
5353 ExtDynamicPageList::$options['RunFromProtectedPagesOnly']==true && !($parser->mTitle->isProtected('edit'))) {
 54+
 55+ // Ideally we would like to allow using a DPL query if the query istelf is coded on a template page
 56+ // which is protected. Then there would be no need for the article to be protected.
 57+ // BUT: How can one find out from which wiki source an extension has been invoked???
 58+
5459 return (ExtDynamicPageList::$options['RunFromProtectedPagesOnly']);
55 - }
 60+ }
5661
5762 // get database access
5863 $dbr =& wfGetDB( DB_SLAVE );
@@ -95,10 +100,19 @@
96101 $input = self::resolveUrlArg($input,'DPL_offset');
97102 $input = self::resolveUrlArg($input,'DPL_count');
98103 $input = self::resolveUrlArg($input,'DPL_fromTitle');
 104+ $input = self::resolveUrlArg($input,'DPL_findTitle');
99105 $input = self::resolveUrlArg($input,'DPL_toTitle');
100106
101107 $sTitleGE = $wgRequest->getVal('DPL_fromTitle','');
 108+ if (strlen($sTitleGE)>0) $sTitleGE[0] = strtoupper($sTitleGE[0]);
 109+ // findTitle has priority over fromTitle
 110+ $findTitle = $wgRequest->getVal('DPL_findTitle','');
 111+ if (strlen($findTitle)>0) $findTitle[0] = strtoupper($findTitle[0]);
 112+ if ($findTitle !='') $sTitleGE = '=_'.$findTitle;
102113 $sTitleLE = $wgRequest->getVal('DPL_toTitle','');
 114+ if (strlen($sTitleLE)>0) $sTitleLE[0] = strtoupper($sTitleLE[0]);
 115+ $sTitleGE = str_replace(' ','_',$sTitleGE);
 116+ $sTitleLE = str_replace(' ','_',$sTitleLE);
103117 $scrollDir = $wgRequest->getVal('DPL_scrollDir','');
104118
105119 $originalInput = $input;
@@ -119,8 +133,9 @@
120134 $bSelectionCriteriaFound=false;
121135 $bConflictsWithOpenReferences=false;
122136 // array for LINK / TEMPLATE / CATGEORY / IMAGE by RESET / ELIMINATE
123 - $bReset = array ( false, false, false, false, false, false, false, false );
124 -
 137+ if (ExtDynamicPageList::$options['eliminate'] == 'all') $bReset = array ( false, false, false, false, true, true, true, true );
 138+ else $bReset = array ( false, false, false, false, false, false, false, false );
 139+
125140 // we allow " like " or "="
126141 $sCategoryComparisonMode = '=';
127142 $sNotCategoryComparisonMode = '=';
@@ -389,7 +404,9 @@
390405 $sArg[0] = '';
391406 }
392407 $op='OR';
393 - if (strpos($sArg,'&')!==false) {
 408+ // we expand html entities because they contain an '& 'which would be interpreted as an AND condition
 409+ $sArg=html_entity_decode($sArg,ENT_QUOTES);
 410+ if (strpos($sArg,'&')!==false) {
394411 $aParams = explode('&', $sArg);
395412 $op = 'AND';
396413 } else {
@@ -429,7 +446,7 @@
430447 if($bHeading) $aCatHeadings = array_unique($aCatHeadings + $aCategories);
431448 if($bNotHeading) $aCatNotHeadings = array_unique($aCatNotHeadings + $aCategories);
432449 $bConflictsWithOpenReferences=true;
433 - }
 450+ }
434451 break;
435452 case 'notcategory':
436453 $title = Title::newFromText($localParser->transformMsg($sArg, $pOptions));
@@ -515,7 +532,7 @@
516533 }
517534 if ( !$breakaway ) {
518535 $aOrderMethods = $methods;
519 - $bConflictsWithOpenReferences=true;
 536+ if ($methods[0]!='none') $bConflictsWithOpenReferences=true;
520537 }
521538 break;
522539
@@ -1251,7 +1268,6 @@
12521269
12531270 case 'dplcache':
12541271 if ($sArg!='') {
1255 - global $wgArticle;
12561272 if (isset($wgArticle)) {
12571273 $DPLCache = $wgArticle->getID().'_'.$sArg.'.txt';
12581274 $DPLCachePath = $wgArticle->getID() % 10;
@@ -1301,7 +1317,9 @@
13021318 else if ($arg=='all') {
13031319 $bReset[4]=true; $bReset[5]=true; $bReset[6]=true; $bReset[7]=true;
13041320 }
1305 - else if ($arg=='none') ; // do nothing
 1321+ else if ($arg=='none') {
 1322+ $bReset[4]=false;$bReset[5]=false;$bReset[6]=false;$bReset[7]=false;
 1323+ }
13061324 }
13071325 break;
13081326
@@ -1711,7 +1729,6 @@
17121730 // backward scrolling: if the user specified titleLE and wants ascending order we reverse the SQL sort order
17131731 if ($sTitleLE != '' && $sTitleGE =='') {
17141732 if ($sOrder == 'ascending' ) $sOrder='descending';
1715 - else if ($sOrder == 'descending') $sOrder='ascending';
17161733 }
17171734
17181735 $output.='{{Extension DPL}}';
@@ -2167,9 +2184,9 @@
21682185 // If we want the Uncategorized
21692186 $sSqlSelectFrom .= ' INNER JOIN ' . ( in_array('', $aIncludeCategories[$i]) ? $sDplClView : $sCategorylinksTable ) .
21702187 ' AS cl' . $iClTable . ' ON '.$sPageTable.'.page_id=cl' . $iClTable . '.cl_from AND (cl' . $iClTable . '.cl_to'.
2171 - $sCategoryComparisonMode . $dbr->addQuotes($aIncludeCategories[$i][0]);
 2188+ $sCategoryComparisonMode . $dbr->addQuotes(str_replace(' ','_',$aIncludeCategories[$i][0]));
21722189 for ($j = 1; $j < count($aIncludeCategories[$i]); $j++)
2173 - $sSqlSelectFrom .= ' OR cl' . $iClTable . '.cl_to' . $sCategoryComparisonMode . $dbr->addQuotes($aIncludeCategories[$i][$j]);
 2190+ $sSqlSelectFrom .= ' OR cl' . $iClTable . '.cl_to' . $sCategoryComparisonMode . $dbr->addQuotes(str_replace(' ','_',$aIncludeCategories[$i][$j]));
21742191 $sSqlSelectFrom .= ') ';
21752192 $iClTable++;
21762193 }
@@ -2179,7 +2196,7 @@
21802197 $sSqlSelectFrom .=
21812198 ' LEFT OUTER JOIN ' . $sCategorylinksTable . ' AS cl' . $iClTable .
21822199 ' ON '.$sPageTable.'.page_id=cl' . $iClTable . '.cl_from' .
2183 - ' AND cl' . $iClTable . '.cl_to'. $sNotCategoryComparisonMode . $dbr->addQuotes($aExcludeCategories[$i]);
 2200+ ' AND cl' . $iClTable . '.cl_to'. $sNotCategoryComparisonMode . $dbr->addQuotes(str_replace(' ','_',$aExcludeCategories[$i]));
21842201 $sSqlWhere .= ' AND cl' . $iClTable . '.cl_to IS NULL';
21852202 $iClTable++;
21862203 }
@@ -2209,16 +2226,26 @@
22102227 // TitleGE ...
22112228 if ( $sTitleGE != '' ) {
22122229 $sSqlWhere .= ' AND (';
2213 - if ($acceptOpenReferences) $sSqlWhere .= 'pl_title >=' . $dbr->addQuotes($sTitleGE) ;
2214 - else $sSqlWhere .= $sPageTable.'.page_title >=' . $dbr->addQuotes($sTitleGE) ;
 2230+ if (substr($sTitleGE,0,2)=='=_') {
 2231+ if ($acceptOpenReferences) $sSqlWhere .= 'pl_title >=' . $dbr->addQuotes(substr($sTitleGE,2)) ;
 2232+ else $sSqlWhere .= $sPageTable.'.page_title >=' . $dbr->addQuotes(substr($sTitleGE,2)) ;
 2233+ } else {
 2234+ if ($acceptOpenReferences) $sSqlWhere .= 'pl_title >' . $dbr->addQuotes($sTitleGE) ;
 2235+ else $sSqlWhere .= $sPageTable.'.page_title >' . $dbr->addQuotes($sTitleGE) ;
 2236+ }
22152237 $sSqlWhere .= ')';
22162238 }
22172239
22182240 // TitleLE ...
22192241 if ( $sTitleLE != '' ) {
22202242 $sSqlWhere .= ' AND (';
2221 - if ($acceptOpenReferences) $sSqlWhere .= 'pl_title <=' . $dbr->addQuotes($sTitleLE) ;
2222 - else $sSqlWhere .= $sPageTable.'.page_title <=' . $dbr->addQuotes($sTitleLE) ;
 2243+ if (substr($sTitleLE,0,2)=='=_') {
 2244+ if ($acceptOpenReferences) $sSqlWhere .= 'pl_title <=' . $dbr->addQuotes(substr($sTitleLE,2)) ;
 2245+ else $sSqlWhere .= $sPageTable.'.page_title <=' . $dbr->addQuotes(substr($sTitleLE,2)) ;
 2246+ } else {
 2247+ if ($acceptOpenReferences) $sSqlWhere .= 'pl_title <' . $dbr->addQuotes($sTitleLE) ;
 2248+ else $sSqlWhere .= $sPageTable.'.page_title <' . $dbr->addQuotes($sTitleLE) ;
 2249+ }
22232250 $sSqlWhere .= ')';
22242251 }
22252252
@@ -2416,7 +2443,8 @@
24172444 if ($sOrder == 'descending') $sSqlWhere .= ' ) order by cl3.cl_to DESC';
24182445 else $sSqlWhere .= ' ) order by cl3.cl_to ASC';
24192446 }
2420 -
 2447+
 2448+
24212449 // ###### DUMP SQL QUERY ######
24222450 if ($logger->iDebugLevel >=3) {
24232451 //DEBUG: output SQL query
@@ -2428,6 +2456,7 @@
24292457 return $output;
24302458 }
24312459
 2460+
24322461 // ###### PROCESS SQL QUERY ######
24332462
24342463 try {
@@ -2663,7 +2692,7 @@
26642693 }
26652694
26662695 // backward scrolling: if the user specified titleLE we reverse the output order
2667 - if ($sTitleLE != '' && $sTitleGE =='') $aArticles = array_reverse($aArticles);
 2696+ if ($sTitleLE != '' && $sTitleGE =='' && $sOrder=='descending' ) $aArticles = array_reverse($aArticles);
26682697
26692698
26702699 // ###### SHOW OUTPUT ######
@@ -2752,8 +2781,39 @@
27532782 $parser->disableCache();
27542783 }
27552784
 2785+ // update dependencies to CacheAPI if DPL is to respect the MW ParserCache and the page containing the DPL query is changed
 2786+
 2787+ if (ExtDynamicPageList::$useCacheAPI && $bAllowCachedResults && $wgRequest->getVal('action','view')=='submit') {
 2788+/*
 2789+ CacheAPI::remDependencies ( $wgArticle->getID());
 2790+
 2791+ // add category dependencies
 2792+
 2793+ $conditionTypes = array ( CACHETYPE_CATEGORY );
 2794+ $conditions = array();
 2795+ $conditions[0] = array();
 2796+ $categorylist = array();
 2797+ foreach ($aIncludeCategories as $categorygroup) {
 2798+ $c=0;
 2799+ foreach ($categorygroup as $category) {
 2800+ if ($c==0) $conditions[0][]= $category;
 2801+ $c++;
 2802+ }
 2803+ }
 2804+
 2805+ // add template dependencies
 2806+
 2807+ // add link dependencies
 2808+
 2809+ // add general dependencies
 2810+
 2811+ // CacheAPI::addDependencies ( $wgArticle->getID(), $conditionTypes, $conditions);
 2812+*/
 2813+ }
 2814+
 2815+
27562816 // The following requires an extra parser step which may consume some time
2757 - // we parse the DPL output and save all referenced found in that output in a global list
 2817+ // we parse the DPL output and save all references found in that output in a global list
27582818 // in a final user exit after the whole document processing we eliminate all these links
27592819 // we use a local parser to avoid interference with the main parser
27602820
@@ -2771,32 +2831,30 @@
27722832 // we trigger the mediawiki parser to find links, images, categories etc. which are contained in the DPL output
27732833 // this allows us to remove these links from the link list later
27742834 // If the article containing the DPL statement itself uses one of these links they will be thrown away!
2775 - foreach ($parserOutput->getLinks() as $link) {
2776 - foreach ($link as $key => $val) {
2777 - ExtDynamicPageList::$createdLinks[0][$key]=$val;
2778 - // $output.= "storing link $val($key).";
2779 - }
 2835+ ExtDynamicPageList::$createdLinks[0]=array();
 2836+ foreach ($parserOutput->getLinks() as $nsp => $link) {
 2837+ ExtDynamicPageList::$createdLinks[0][$nsp]=$link;
27802838 }
27812839 }
27822840 if ($bReset[5]) { // TEMPLATES
2783 - foreach ($parserOutput->getTemplates() as $tpl) {
2784 - foreach ($tpl as $key => $val) {
2785 - ExtDynamicPageList::$createdLinks[1][$key]=$val;
2786 - // $output.= "storing use of template $val($key).";
2787 - }
 2841+ ExtDynamicPageList::$createdLinks[1]=array();
 2842+ foreach ($parserOutput->getTemplates() as $nsp => $tpl) {
 2843+ ExtDynamicPageList::$createdLinks[1][$nsp]=$tpl;
27882844 }
27892845 }
27902846 if ($bReset[6]) { // CATEGORIES
2791 - foreach ($parserOutput->mCategories as $catname => $catkey) {
2792 - ExtDynamicPageList::$createdLinks[2][$catname] = $catname;
2793 - }
 2847+ ExtDynamicPageList::$createdLinks[2] = $parserOutput->mCategories;
27942848 }
27952849 if ($bReset[7]) { // IMAGES
2796 - foreach ($parserOutput->mImages as $imgid => $dummy) {
2797 - ExtDynamicPageList::$createdLinks[3][$imgid] = $imgid;
2798 - }
 2850+ ExtDynamicPageList::$createdLinks[3] = $parserOutput->mImages;
27992851 }
28002852
 2853+ // $file=fopen("d:/a1",'a');
 2854+ // fwrite($file,$parser->mTitle->getPrefixedText().' '.microtime()."\n");
 2855+ // fclose($file);
 2856+
 2857+ // MyBug::trace(__CLASS__,'main END',$output);
 2858+
28012859 return $output;
28022860
28032861 }
@@ -2897,7 +2955,7 @@
28982956 if (self::mkdirr($next_pathname)) {
28992957 if (!file_exists($pathname)) return mkdir($pathname);
29002958 }
2901 - return false;
 2959+ return false;
29022960 }
29032961
29042962 private static function resolveUrlArg($input,$arg) {
Index: trunk/extensions/DynamicPageList/DynamicPageListMigration.php
@@ -40,7 +40,7 @@
4141
4242 $wgHooks['LanguageGetMagic'][] = 'ExtDynamicPageList__languageGetMagic';
4343
44 -$DPLVersion = '1.8.6';
 44+$DPLVersion = '1.8.7';
4545
4646 $wgExtensionCredits['parserhook'][] = array(
4747 'path' => __FILE__,
@@ -60,4 +60,3 @@
6161 // be extremely restrictive by default: do not allow anything that goes beyond Extension:Intersection
6262 // can be extended by a different call to this function in LocalSettings.php after the require_once()
6363 ExtDynamicPageList::setFunctionalRichness(0);
64 -

Status & tagging log