basic support for special page inclusions
authorTim Starling <tstarling@users.mediawiki.org>
Sat, 28 May 2005 11:09:22 +0000 (11:09 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Sat, 28 May 2005 11:09:22 +0000 (11:09 +0000)
includes/DefaultSettings.php
includes/OutputPage.php
includes/Parser.php
includes/SpecialAllpages.php
includes/SpecialContributions.php
includes/SpecialPage.php
includes/SpecialRecentchanges.php

index e2d361d..d8a6843 100644 (file)
@@ -1490,4 +1490,10 @@ $wgTrustedMediaFormats= array(
        #"application/x-shockwafe-flash", //flash/shockwave movie 
 );
 
+/**
+ * Allow special page inclusions such as {{Special:Allpages}}
+ */
+$wgAllowSpecialInclusion = true;
+
+
 ?>
index 3272713..879f5e8 100644 (file)
@@ -219,6 +219,7 @@ class OutputPage {
 
        function addHTML( $text ) { $this->mBodytext .= $text; }
        function clearHTML() { $this->mBodytext = ''; }
+       function getHTML() { return $this->mBodytext; }
        function debug( $text ) { $this->mDebugtext .= $text; }
 
        function setParserOptions( $options ) {
@@ -244,6 +245,9 @@ class OutputPage {
                $parserOutput = $wgParser->parse( $text, $title, $this->mParserOptions, $linestart );
                $this->mLanguageLinks += $parserOutput->getLanguageLinks();
                $this->mCategoryLinks += $parserOutput->getCategoryLinks();
+               if ( $parserOutput->getCacheTime() == -1 ) {
+                       $this->enableClientCache( false );
+               }
                $this->addHTML( $parserOutput->getText() );
        }       
                
@@ -258,12 +262,15 @@ class OutputPage {
 
                $text = $parserOutput->getText();
                
-               if ( $cacheArticle ) {
+               if ( $cacheArticle && $parserOutput->getCacheTime() != -1 ) {
                        $wgParserCache->save( $parserOutput, $cacheArticle, $wgUser );
                }
 
                $this->mLanguageLinks += $parserOutput->getLanguageLinks();
                $this->mCategoryLinks += $parserOutput->getCategoryLinks();
+               if ( $parserOutput->getCacheTime() == -1 ) {
+                       $this->enableClientCache( false );
+               }
                $this->addHTML( $text );
        }
 
@@ -467,35 +474,6 @@ class OutputPage {
                        $wgOutputEncoding = strtolower( $wgOutputEncoding );
                        return;
                }
-
-               /*
-               # This code is unused anyway!
-               # Commenting out. --bv 2003-11-15
-
-               $a = explode( ",", $_SERVER['HTTP_ACCEPT_CHARSET'] );
-               $best = 0.0;
-               $bestset = "*";
-
-               foreach ( $a as $s ) {
-                       if ( preg_match( "/(.*);q=(.*)/", $s, $m ) ) {
-                               $set = $m[1];
-                               $q = (float)($m[2]);
-                       } else {
-                               $set = $s;
-                               $q = 1.0;
-                       }
-                       if ( $q > $best ) {
-                               $bestset = $set;
-                               $best = $q;
-                       }
-               }
-               #if ( "*" == $bestset ) { $bestset = "iso-8859-1"; }
-               if ( "*" == $bestset ) { $bestset = $wgOutputEncoding; }
-               $wgOutputEncoding = strtolower( $bestset );
-
-# Disable for now
-#
-               */
                $wgOutputEncoding = $wgInputEncoding;
        }
 
index 4dee7f2..ca73400 100644 (file)
@@ -83,7 +83,7 @@ define( 'EXT_IMAGE_REGEX',
  * settings:
  *  $wgUseTex*, $wgUseDynamicDates*, $wgInterwikiMagic*,
  *  $wgNamespacesWithSubpages, $wgAllowExternalImages*,
- *  $wgLocaltimezone
+ *  $wgLocaltimezone, $wgAllowSpecialInclusion*
  *
  *  * only within ParserOptions
  * </pre>
@@ -2132,7 +2132,8 @@ class Parser
                }
 
                # Load from database
-               $itcamefromthedatabase = false;
+               $replaceHeadings = false;
+               $isHTML = false;
                $lastPathLevel = $this->mTemplatePath;
                if ( !$found ) {
                        $ns = NS_TEMPLATE;
@@ -2145,13 +2146,23 @@ class Parser
                                # Check for excessive inclusion
                                $dbk = $title->getPrefixedDBkey();
                                if ( $this->incrementIncludeCount( $dbk ) ) {
-                                       # This should never be reached.
-                                       $article = new Article( $title );
-                                       $articleContent = $article->getContentWithoutUsingSoManyDamnGlobals();
-                                       if ( $articleContent !== false ) {
-                                               $found = true;
-                                               $text = $linestart . $articleContent;
-                                               $itcamefromthedatabase = true;
+                                       if ( $title->getNamespace() == NS_SPECIAL && $this->mOptions->getAllowSpecialInclusion() ) {
+                                               # Capture special page output
+                                               $text = SpecialPage::capturePath( $title );
+                                               if ( $text && !is_object( $text ) ) {
+                                                       $found = true;
+                                                       $noparse = true;
+                                                       $isHTML = true;
+                                                       $this->mOutput->setCacheTime( -1 );
+                                               }
+                                       } else {
+                                               $article = new Article( $title );
+                                               $articleContent = $article->getContentWithoutUsingSoManyDamnGlobals();
+                                               if ( $articleContent !== false ) {
+                                                       $found = true;
+                                                       $text = $linestart . $articleContent;
+                                                       $replaceHeadings = true;
+                                               }
                                        }
                                }
 
@@ -2219,33 +2230,41 @@ class Parser
                        wfProfileOut( $fname );
                        return $matches[0];
                } else {
-                       # replace ==section headers==
-                       # XXX this needs to go away once we have a better parser.
-                       if ( $this->mOutputType != OT_WIKI && $itcamefromthedatabase ) {
-                               if( !is_null( $title ) )
-                                       $encodedname = base64_encode($title->getPrefixedDBkey());
-                               else
-                                       $encodedname = base64_encode("");
-                               $m = preg_split('/(^={1,6}.*?={1,6}\s*?$)/m', $text, -1,
-                                       PREG_SPLIT_DELIM_CAPTURE);
-                               $text = '';
-                               $nsec = 0;
-                               for( $i = 0; $i < count($m); $i += 2 ) {
-                                       $text .= $m[$i];
-                                       if (!isset($m[$i + 1]) || $m[$i + 1] == "") continue;
-                                       $hl = $m[$i + 1];
-                                       if( strstr($hl, "<!--MWTEMPLATESECTION") ) {
-                                               $text .= $hl;
-                                               continue;
+                       if ( $isHTML ) {
+                               # Replace raw HTML by a placeholder
+                               # Add a blank line preceding, to prevent it from mucking up 
+                               # immediately preceding headings
+                               $text = "\n\n" . $this->insertStripItem( $text, $this->mStripState );
+                       } else {
+                               # replace ==section headers==
+                               # XXX this needs to go away once we have a better parser.
+                               if ( $this->mOutputType != OT_WIKI && $replaceHeadings ) {
+                                       if( !is_null( $title ) )
+                                               $encodedname = base64_encode($title->getPrefixedDBkey());
+                                       else
+                                               $encodedname = base64_encode("");
+                                       $m = preg_split('/(^={1,6}.*?={1,6}\s*?$)/m', $text, -1,
+                                               PREG_SPLIT_DELIM_CAPTURE);
+                                       $text = '';
+                                       $nsec = 0;
+                                       for( $i = 0; $i < count($m); $i += 2 ) {
+                                               $text .= $m[$i];
+                                               if (!isset($m[$i + 1]) || $m[$i + 1] == "") continue;
+                                               $hl = $m[$i + 1];
+                                               if( strstr($hl, "<!--MWTEMPLATESECTION") ) {
+                                                       $text .= $hl;
+                                                       continue;
+                                               }
+                                               preg_match('/^(={1,6})(.*?)(={1,6})\s*?$/m', $hl, $m2);
+                                               $text .= $m2[1] . $m2[2] . "<!--MWTEMPLATESECTION="
+                                                       . $encodedname . "&" . base64_encode("$nsec") . "-->" . $m2[3];
+                                               
+                                               $nsec++;
                                        }
-                                       preg_match('/^(={1,6})(.*?)(={1,6})\s*?$/m', $hl, $m2);
-                                       $text .= $m2[1] . $m2[2] . "<!--MWTEMPLATESECTION="
-                                               . $encodedname . "&" . base64_encode("$nsec") . "-->" . $m2[3];
-                                       
-                                       $nsec++;
                                }
                        }
                }
+               
                # Prune lower levels off the recursion check path
                $this->mTemplatePath = $lastPathLevel;
                
@@ -3122,7 +3141,7 @@ class Parser
 class ParserOutput
 {
        var $mText, $mLanguageLinks, $mCategoryLinks, $mContainsOldMagic;
-       var $mCacheTime; # Used in ParserCache
+       var $mCacheTime; # Timestamp on this article, or -1 for uncacheable. Used in ParserCache.
        var $mVersion;   # Compatibility check
        var $mTitleText; # title text of the chosen language variant
 
@@ -3170,7 +3189,8 @@ class ParserOutput
         */
        function expired( $touched ) {
                global $wgCacheEpoch;
-               return $this->getCacheTime() <= $touched ||
+               return $this->getCacheTime() == -1 || // parser says it's uncacheable
+                      $this->getCacheTime() <= $touched ||
                       $this->getCacheTime() <= $wgCacheEpoch ||
                       !isset( $this->mVersion ) ||
                       version_compare( $this->mVersion, MW_PARSER_VERSION, "lt" );
@@ -3193,6 +3213,7 @@ class ParserOptions
        var $mDateFormat;                # Date format index
        var $mEditSection;               # Create "edit section" links
        var $mNumberHeadings;            # Automatically number headings
+       var $mAllowSpecialInclusion;     # Allow inclusion of special pages
 
        function getUseTeX()                        { return $this->mUseTeX; }
        function getUseDynamicDates()               { return $this->mUseDynamicDates; }
@@ -3202,6 +3223,8 @@ class ParserOptions
        function getDateFormat()                    { return $this->mDateFormat; }
        function getEditSection()                   { return $this->mEditSection; }
        function getNumberHeadings()                { return $this->mNumberHeadings; }
+       function getAllowSpecialInclusion()         { return $this->mAllowSpecialInclusion; }
+
 
        function setUseTeX( $x )                    { return wfSetVar( $this->mUseTeX, $x ); }
        function setUseDynamicDates( $x )           { return wfSetVar( $this->mUseDynamicDates, $x ); }
@@ -3210,6 +3233,7 @@ class ParserOptions
        function setDateFormat( $x )                { return wfSetVar( $this->mDateFormat, $x ); }
        function setEditSection( $x )               { return wfSetVar( $this->mEditSection, $x ); }
        function setNumberHeadings( $x )            { return wfSetVar( $this->mNumberHeadings, $x ); }
+       function setAllowSpecialInclusion( $x )     { return wfSetVar( $this->mAllowSpecialInclusion, $x ); }
 
        function setSkin( &$x ) { $this->mSkin =& $x; }
 
@@ -3230,7 +3254,8 @@ class ParserOptions
 
        /** Get user options */
        function initialiseFromUser( &$userInput ) {
-               global $wgUseTeX, $wgUseDynamicDates, $wgInterwikiMagic, $wgAllowExternalImages;
+               global $wgUseTeX, $wgUseDynamicDates, $wgInterwikiMagic, $wgAllowExternalImages, 
+                      $wgAllowSpecialInclusion;
                $fname = 'ParserOptions::initialiseFromUser';
                wfProfileIn( $fname );
                if ( !$userInput ) {
@@ -3250,6 +3275,7 @@ class ParserOptions
                $this->mDateFormat = $user->getOption( 'date' );
                $this->mEditSection = $user->getOption( 'editsection' );
                $this->mNumberHeadings = $user->getOption( 'numberheadings' );
+               $this->mAllowSpecialInclusion = $wgAllowSpecialInclusion;
                wfProfileOut( $fname );
        }
 }
index b4142aa..357f610 100644 (file)
@@ -8,7 +8,7 @@
  * Entry point : initialise variables and call subfunctions.
  * @param string $par Becomes "FOO" when called like Special:Allpages/FOO (default NULL)
  */
-function wfSpecialAllpages( $par=NULL ) {
+function wfSpecialAllpages( $par=NULL, $specialPage ) {
        global $indexMaxperpage, $toplevelMaxperpage, $wgRequest, $wgOut, $wgContLang;
        # Config
        $indexMaxperpage = 480;
@@ -36,11 +36,11 @@ function wfSpecialAllpages( $par=NULL ) {
        }
        
        if ( isset($par) ) {
-               indexShowChunk( $namespace, $par, $invert );
+               indexShowChunk( $namespace, $par, $invert, $specialPage->including() );
        } elseif ( isset($from) ) {
-               indexShowChunk( $namespace, $from, $invert );
+               indexShowChunk( $namespace, $from, $invert, $specialPage->including() );
        } else {
-               indexShowToplevel ( $namespace, $invert );
+               indexShowToplevel ( $namespace, $invert, $specialPage->including() );
        }
 }
 
@@ -50,7 +50,7 @@ function wfSpecialAllpages( $par=NULL ) {
  * @param string $from Article name we are starting listing at.
  * @param bool $invert true if we want the namespaces inverted (default false)
  */
-function namespaceForm ( $namespace = NS_MAIN, $from = '', $invert ) {
+function indexNamespaceForm ( $namespace = NS_MAIN, $from = '', $invert = false ) {
        global $wgContLang, $wgScript;
        $t = Title::makeTitle( NS_SPECIAL, "Allpages" );
 
@@ -97,7 +97,7 @@ function namespaceForm ( $namespace = NS_MAIN, $from = '', $invert ) {
  * @param integer $namespace (default NS_MAIN)
  * @param bool $invert true if we want the namespaces inverted (default false)
  */
-function indexShowToplevel ( $namespace = NS_MAIN, $invert ) {
+function indexShowToplevel ( $namespace = NS_MAIN, $invert = false,  $including = false ) {
        global $wgOut, $indexMaxperpage, $toplevelMaxperpage, $wgContLang, $wgRequest, $wgUser;
        $sk = $wgUser->getSkin();
        $fname = "indexShowToplevel";
@@ -120,7 +120,7 @@ function indexShowToplevel ( $namespace = NS_MAIN, $invert ) {
        if ( $sections < 3 ) {
                # If there are only two or less sections, don't even display them.
                # Instead, display the first section directly.
-               indexShowChunk( $namespace, '', $invert );
+               indexShowChunk( $namespace, '', $invert, $including );
                return;
        }
 
@@ -167,33 +167,37 @@ function indexShowToplevel ( $namespace = NS_MAIN, $invert ) {
        }
        $out .= '</table>';
        
-       $nsForm = namespaceForm ( $namespace, '', $invert );
-
+       $nsForm = indexNamespaceForm ( $namespace, '', $invert );
+       
        # Is there more?
-       $morelinks = '';
-       if ( $offset > 0 ) {
-               $morelinks = $sk->makeKnownLink (
-                       $wgContLang->specialPage ( 'Allpages' ),
-                       wfMsg ( 'allpagesprev' ),
-                       ( $offset > $toplevelMaxperpage ) ? 'offset='.($offset-$toplevelMaxperpage) : ''
-               );
-       }
-       if ( $stopat < $sections-1 ) {
-               if ( $morelinks != '' ) { $morelinks .= " | "; }
-               $morelinks .= $sk->makeKnownLink (
-                       $wgContLang->specialPage ( 'Allpages' ),
-                       wfMsg ( 'allpagesnext' ),
-                       'offset=' . ($offset + $toplevelMaxperpage)
-               );
-       }
-
-       if ( $morelinks != '' ) {
-               $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
-               $out2 .= '<tr valign="top"><td align="left">' . $nsForm;
-               $out2 .= '</td><td align="right" style="font-size: smaller; margin-bottom: 1em;">';
-               $out2 .= $morelinks . '</td></tr></table><hr />';
+       if ( $including ) {
+               $out2 = '';
        } else {
-               $out2 = $nsForm . '<hr />';
+               $morelinks = '';
+               if ( $offset > 0 ) {
+                       $morelinks = $sk->makeKnownLink (
+                               $wgContLang->specialPage ( 'Allpages' ),
+                               wfMsg ( 'allpagesprev' ),
+                               ( $offset > $toplevelMaxperpage ) ? 'offset='.($offset-$toplevelMaxperpage) : ''
+                       );
+               }
+               if ( $stopat < $sections-1 ) {
+                       if ( $morelinks != '' ) { $morelinks .= " | "; }
+                       $morelinks .= $sk->makeKnownLink (
+                               $wgContLang->specialPage ( 'Allpages' ),
+                               wfMsg ( 'allpagesnext' ),
+                               'offset=' . ($offset + $toplevelMaxperpage)
+                       );
+               }
+
+               if ( $morelinks != '' ) {
+                       $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
+                       $out2 .= '<tr valign="top"><td align="left">' . $nsForm;
+                       $out2 .= '</td><td align="right" style="font-size: smaller; margin-bottom: 1em;">';
+                       $out2 .= $morelinks . '</td></tr></table><hr />';
+               } else {
+                       $out2 = $nsForm . '<hr />';
+               }
        }
 
        $wgOut->addHtml( $out2 . $out );
@@ -229,7 +233,7 @@ function indexShowline( $inpoint, $outpoint, $namespace = NS_MAIN, $invert ) {
  * @param string $from list all pages from this name (default FALSE)
  * @param bool $invert true if we want the namespaces inverted (default false)
  */
-function indexShowChunk( $namespace = NS_MAIN, $from, $invert ) {
+function indexShowChunk( $namespace = NS_MAIN, $from, $invert = false, $including = false ) {
        global $wgOut, $wgUser, $indexMaxperpage, $wgContLang;
        $sk = $wgUser->getSkin();
        $maxPlusOne = $indexMaxperpage + 1;
@@ -277,21 +281,25 @@ function indexShowChunk( $namespace = NS_MAIN, $from, $invert ) {
        }
        $out .= '</table>';
        
-       $nsForm = namespaceForm ( $namespace, $from, $invert );
-       $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
-       $out2 .= '<tr valign="top"><td align="left">' . $nsForm;
-       $out2 .= '</td><td align="right" style="font-size: smaller; margin-bottom: 1em;">' .
-                       $sk->makeKnownLink( $wgContLang->specialPage( "Allpages" ),
-                               wfMsg ( 'allpages' ) );
-       if ( ($n == $indexMaxperpage) && ($s = $dbr->fetchObject( $res )) ) {
-               $namespaceparam = $namespace ? "&namespace=$namespace" : "";
-               $invertparam = $invert ? "&invert=$invert" : '';
-               $out2 .= " | " . $sk->makeKnownLink(
-                       $wgContLang->specialPage( "Allpages" ),
-                       wfMsg ( 'nextpage', $s->page_title ),
-                       "from=" . wfUrlEncode ( $s->page_title ) . $namespaceparam . $invertparam );
+       if ( $including ) {
+               $out2 = '';
+       } else {
+               $nsForm = indexNamespaceForm ( $namespace, $from, $invert );
+               $out2 = '<table style="background: inherit;" width="100%" cellpadding="0" cellspacing="0" border="0">';
+               $out2 .= '<tr valign="top"><td align="left">' . $nsForm;
+               $out2 .= '</td><td align="right" style="font-size: smaller; margin-bottom: 1em;">' .
+                               $sk->makeKnownLink( $wgContLang->specialPage( "Allpages" ),
+                                       wfMsg ( 'allpages' ) );
+               if ( ($n == $indexMaxperpage) && ($s = $dbr->fetchObject( $res )) ) {
+                       $namespaceparam = $namespace ? "&namespace=$namespace" : "";
+                       $invertparam = $invert ? "&invert=$invert" : '';
+                       $out2 .= " | " . $sk->makeKnownLink(
+                               $wgContLang->specialPage( "Allpages" ),
+                               wfMsg ( 'nextpage', $s->page_title ),
+                               "from=" . wfUrlEncode ( $s->page_title ) . $namespaceparam . $invertparam );
+               }
+               $out2 .= "</td></tr></table><hr />";
        }
-       $out2 .= "</td></tr></table><hr />";
 
        $wgOut->addHtml( $out2 . $out );
 }
index cabb915..430d889 100644 (file)
@@ -103,7 +103,7 @@ function wfSpecialContributions( $par = null ) {
        $res = $dbr->query( $sql, $fname );
        $numRows = $dbr->numRows( $res );
 
-       $wgOut->addHTML( namespaceForm( $target, $hideminor, $namespace, $invert ) );
+       $wgOut->addHTML( ucNamespaceForm( $target, $hideminor, $namespace, $invert ) );
 
        $top = wfShowingResults( $offset, $limit );
        $wgOut->addHTML( "<p>{$top}\n" );
@@ -216,7 +216,7 @@ function ucListEdit( $sk, $row ) {
  * @param      string  $namespace currently selected namespace, NULL for show all
  * @param      bool    $invert  inverts the namespace selection on true (default null)
  */
-function namespaceForm ( $target, $hideminor, $namespace, $invert ) {
+function ucNamespaceForm ( $target, $hideminor, $namespace, $invert ) {
        global $wgContLang, $wgScript;
 
        $namespaceselect = "<select name='namespace' id='nsselectbox'>";
index bdc1d92..abfbcb9 100644 (file)
@@ -34,7 +34,7 @@ $wgSpecialPages = array(
        'Preferences'       => new SpecialPage( 'Preferences' ),
        'Watchlist'         => new SpecialPage( 'Watchlist' ),
        
-       'Recentchanges'     => new SpecialPage( 'Recentchanges' ),
+       'Recentchanges'     => new IncludableSpecialPage( 'Recentchanges' ),
        'Upload'            => new SpecialPage( 'Upload' ),
        'Imagelist'         => new SpecialPage( 'Imagelist' ),
        'Newimages'         => new SpecialPage( 'Newimages' ),
@@ -51,7 +51,7 @@ $wgSpecialPages = array(
        'Newpages'              => new SpecialPage( 'Newpages' ),
        'Ancientpages'  => new SpecialPage( 'Ancientpages' ),
        'Deadendpages'  => new SpecialPage( 'Deadendpages' ),
-       'Allpages'              => new SpecialPage( 'Allpages' ),
+       'Allpages'              => new IncludableSpecialPage( 'Allpages' ),
        'Ipblocklist'   => new SpecialPage( 'Ipblocklist' ),
        'Specialpages'  => new UnlistedSpecialPage( 'Specialpages' ),
        'Contributions' => new UnlistedSpecialPage( 'Contributions' ),
@@ -144,8 +144,19 @@ class SpecialPage
         * File which needs to be included before the function above can be called
         */
        var $mFile;
+       /**
+        * Whether or not this special page is being included from an article
+        */
+       var $mIncluding;
+       /**
+        * Whether the special page can be included in an article
+        */
+       var $mIncludable;
+       
+
        /**#@-*/
 
+       
        /**
         * Add a page to the list of valid special pages
         * $obj->execute() must send HTML to $wgOut then return
@@ -221,9 +232,13 @@ class SpecialPage
         * The path     may contain parameters, e.g. Special:Name/Params
         * Extracts the special page name and call the execute method, passing the parameters
         *
-        * @param $title should be a title object
+        * Returns a title object if the page is redirected, false if there was no such special 
+        * page, and true if it was successful.
+        *
+        * @param $title          a title object
+        * @param $including      output is being captured for use in {{special:whatever}}
         */
-       function executePath( &$title ) {
+       function executePath( &$title, $including = false ) {
                global $wgSpecialPages, $wgOut, $wgTitle;
 
                $bits = split( "/", $title->getDBkey(), 2 );
@@ -242,20 +257,50 @@ class SpecialPage
                                        $wgOut->redirect( $redir->getFullURL() . '/' . $par );
                                else
                                        $wgOut->redirect( $redir->getFullURL() );
+                               $retVal = $redir;
                        } else {
                                $wgOut->setArticleRelated( false );
                                $wgOut->setRobotpolicy( "noindex,follow" );
                                $wgOut->errorpage( "nosuchspecialpage", "nospecialpagetext" );
+                               $retVal = false;
                        }
                } else {
+                       if ( $including && !$page->includable() ) {
+                               return false;
+                       }
                        if($par !== NULL) {
                                $wgTitle = Title::makeTitle( NS_SPECIAL, $name );
                        } else {
                                $wgTitle = $title;
                        }
+                       $page->including( $including );
 
                        $page->execute( $par );
+                       $retVal = true;
                }
+               return $retVal;
+       }
+
+       /**
+        * Just like executePath() except it returns the HTML instead of outputting it
+        * Returns false if there was no such special page, or a title object if it was
+        * a redirect.
+        * @static
+        */
+       function capturePath( &$title ) {
+               global $wgOut, $wgTitle;
+
+               $oldTitle = $wgTitle;
+               $oldOut = $wgOut;
+               $wgOut = new OutputPage;
+               
+               $ret = SpecialPage::executePath( $title, true );
+               if ( $ret === true ) {
+                       $ret = $wgOut->getHTML();
+               }
+               $wgTitle = $oldTitle;
+               $wgOut = $oldOut;
+               return $ret;
        }
 
        /**
@@ -274,10 +319,11 @@ class SpecialPage
         * @param string $function Function called by execute(). By default it is constructed from $name
         * @param string $file File which is included by execute(). It is also constructed from $name by default
         */
-       function SpecialPage( $name = '', $restriction = '', $listed = true, $function = false, $file = 'default' ) {
+       function SpecialPage( $name = '', $restriction = '', $listed = true, $function = false, $file = 'default', $includable = false ) {
                $this->mName = $name;
                $this->mRestriction = $restriction;
                $this->mListed = $listed;
+               $this->mIncludable = $includable;
                if ( $function == false ) {
                        $this->mFunction = 'wfSpecial'.$name;
                } else {
@@ -295,6 +341,8 @@ class SpecialPage
        function getRestriction() { return $this->mRestriction; }
        function isListed() { return $this->mListed; }
        function getFile() { return $this->mFile; }
+       function including( $x = NULL ) { return wfSetVar( $this->mIncluding, $x ); }
+       function includable( $x = NULL ) { return wfSetVar( $this->mIncludable, $x ); } 
 
        /**
         * Checks if the given user (identified by an object) can execute this
@@ -348,7 +396,7 @@ class SpecialPage
                                require_once( $this->mFile );
                        }
                        $func = $this->mFunction;
-                       $func( $par );
+                       $func( $par, $this );
                } else {
                        $this->displayRestrictionError();
                }
@@ -376,6 +424,7 @@ class SpecialPage
        function setListed( $listed ) {
                return wfSetVar( $this->mListed, $listed );
        }
+
 }
 
 /**
@@ -388,4 +437,14 @@ class UnlistedSpecialPage extends SpecialPage
                SpecialPage::SpecialPage( $name, $restriction, false, $function, $file );
        }
 }
+
+/**
+ * Shortcut to construct an includable special  page
+ */
+class IncludableSpecialPage extends SpecialPage
+{
+       function IncludableSpecialPage( $name, $restriction = '', $listed = true, $function = false, $file = 'default' ) {
+               SpecialPage::SpecialPage( $name, $restriction, $listed, $function, $file, true );
+       }
+}
 ?>
index 62867db..911bb9f 100644 (file)
@@ -15,7 +15,7 @@ require_once( 'Revision.php' );
 /**
  * Constructor
  */
-function wfSpecialRecentchanges( $par ) {
+function wfSpecialRecentchanges( $par, $specialPage ) {
        global $wgUser, $wgOut, $wgLang, $wgContLang, $wgTitle, $wgMemc, $wgDBname;
        global $wgRequest, $wgSitename, $wgLanguageCode, $wgContLanguageCode;
        global $wgFeedClasses, $wgUseRCPatrol;
@@ -50,7 +50,6 @@ function wfSpecialRecentchanges( $par ) {
 
        #       list( $limit, $offset ) = wfCheckLimits( 100, 'rclimit' );
        $limit = $wgRequest->getInt( 'limit', $limit );
-       if ( $limit < 0 || $limit > 5000 ) $limit = $defaults['limit'];
 
        /* order of selection: url > preferences > default */
        $hideminor = $wgRequest->getBool( 'hideminor', $wgUser->getOption( 'hideminor') ? true : $defaults['hideminor'] );      
@@ -75,15 +74,31 @@ function wfSpecialRecentchanges( $par ) {
                # Get query parameters from path
                if( $par ) {
                        $bits = preg_split( '/\s*,\s*/', trim( $par ) );
-                       if( in_array( 'hidebots', $bits ) ) $hidebots = 1;
-                       if( in_array( 'bots', $bits ) ) $hidebots = 0;
-                       if( in_array( 'hideminor', $bits ) ) $hideminor = 1;
-                       if( in_array( 'minor', $bits ) ) $hideminor = 0;
-                       if( in_array( 'hideliu', $bits) ) $hideliu = 1;
-                       if( in_array( 'hidepatrolled', $bits) ) $hidepatrolled = 1;
+                       foreach ( $bits as $bit ) {
+                               if ( 'hidebots' == $bit ) $hidebots = 1;
+                               if ( 'bots' == $bit ) $hidebots = 0;
+                               if ( 'hideminor' == $bit ) $hideminor = 1;
+                               if ( 'minor' == $bit ) $hideminor = 0;
+                               if ( 'hideliu' == $bit ) $hideliu = 1;
+                               if ( 'hidepatrolled' == $bit ) $hidepatrolled = 1;
+
+                               if ( is_numeric( $bit ) ) {
+                                       $limit = $bit;
+                               }
+
+                               if ( preg_match( '/^limit=(\d+)$/', $bit, $m ) ) {
+                                       $limit = $m[1];
+                               }
+
+                               if ( preg_match( '/^days=(\d+)$/', $bit, $m ) ) {
+                                       $days = $m[1];
+                               }
+                       }
                }
        }
 
+       if ( $limit < 0 || $limit > 5000 ) $limit = $defaults['limit'];
+
 
        # Database connection and caching
        $dbr =& wfGetDB( DB_SLAVE );
@@ -155,24 +170,26 @@ function wfSpecialRecentchanges( $par ) {
                # Web output...
 
                // Output header
-               $wgOut->addWikiText( wfMsgForContent( "recentchangestext" ) );
-       
-               // Dump everything here
-               $nondefaults = array();
-       
-               appendToArrayIfNotDefault( 'days', $days, $defaults, $nondefaults);
-               appendToArrayIfNotDefault( 'limit', $limit , $defaults, $nondefaults);
-               appendToArrayIfNotDefault( 'hideminor', $hideminor, $defaults, $nondefaults);
-               appendToArrayIfNotDefault( 'hidebots', $hidebots, $defaults, $nondefaults);
-               appendToArrayIfNotDefault( 'hideliu', $hideliu, $defaults, $nondefaults);
-               appendToArrayIfNotDefault( 'hidepatrolled', $hidepatrolled, $defaults, $nondefaults);
-               appendToArrayIfNotDefault( 'from', $from, $defaults, $nondefaults);
-               appendToArrayIfNotDefault( 'namespace', $namespace, $defaults, $nondefaults);
-               appendToArrayIfNotDefault( 'invert', $invert, $defaults, $nondefaults);
-       
-               // Add end of the texts
-               $wgOut->addHTML( '<div class="rcoptions">' . rcOptionsPanel( $defaults, $nondefaults ) );
-               $wgOut->addHTML( namespaceForm( $namespace, $invert, $nondefaults) . '</div>');
+               if ( !$specialPage->including() ) {
+                       $wgOut->addWikiText( wfMsgForContent( "recentchangestext" ) );
+               
+                       // Dump everything here
+                       $nondefaults = array();
+               
+                       appendToArrayIfNotDefault( 'days', $days, $defaults, $nondefaults);
+                       appendToArrayIfNotDefault( 'limit', $limit , $defaults, $nondefaults);
+                       appendToArrayIfNotDefault( 'hideminor', $hideminor, $defaults, $nondefaults);
+                       appendToArrayIfNotDefault( 'hidebots', $hidebots, $defaults, $nondefaults);
+                       appendToArrayIfNotDefault( 'hideliu', $hideliu, $defaults, $nondefaults);
+                       appendToArrayIfNotDefault( 'hidepatrolled', $hidepatrolled, $defaults, $nondefaults);
+                       appendToArrayIfNotDefault( 'from', $from, $defaults, $nondefaults);
+                       appendToArrayIfNotDefault( 'namespace', $namespace, $defaults, $nondefaults);
+                       appendToArrayIfNotDefault( 'invert', $invert, $defaults, $nondefaults);
+
+                       // Add end of the texts
+                       $wgOut->addHTML( '<div class="rcoptions">' . rcOptionsPanel( $defaults, $nondefaults ) );
+                       $wgOut->addHTML( rcNamespaceForm( $namespace, $invert, $nondefaults) . '</div>');
+               }
 
                // And now for the content
                $sk = $wgUser->getSkin();
@@ -438,7 +455,7 @@ function rcOptionsPanel( $defaults, $nondefaults ) {
  *
  * @return string
  */
-function namespaceForm ( $namespace, $invert, $nondefaults ) {
+function rcNamespaceForm ( $namespace, $invert, $nondefaults ) {
        global $wgContLang, $wgScript;
        $t = Title::makeTitle( NS_SPECIAL, 'Recentchanges' );