merged master
[lhc/web/wiklou.git] / includes / diff / DifferenceEngine.php
index 6e1b1f1..fc95e8d 100644 (file)
@@ -1,6 +1,21 @@
 <?php
 /**
- * User interface for the difference engine
+ * User interface for the difference engine.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
  *
  * @file
  * @ingroup DifferenceEngine
@@ -198,7 +213,7 @@ class DifferenceEngine extends ContextSource {
                # If external diffs are enabled both globally and for the user,
                # we'll use the application/x-external-editor interface to call
                # an external diff tool like kompare, kdiff3, etc.
-               if ( ExternalEdit::useExternalEngine( $this->getContext(), 'diff' ) ) {
+               if ( ExternalEdit::useExternalEngine( $this->getContext(), 'diff' ) ) { #FIXME: how to handle this for non-text content?
                        $urls = array(
                                'File' => array( 'Extension' => 'wiki', 'URL' =>
                                        # This should be mOldPage, but it may not be set, see below.
@@ -239,8 +254,7 @@ class DifferenceEngine extends ContextSource {
                # a diff between a version V and its previous version V' AND the version V
                # is the first version of that article. In that case, V' does not exist.
                if ( $this->mOldRev === false ) {
-                       $out->setPageTitle( $this->mNewPage->getPrefixedText() );
-                       $out->addSubtitle( $this->msg( 'difference' ) );
+                       $out->setPageTitle( $this->msg( 'difference-title', $this->mNewPage->getPrefixedText() ) );
                        $samePage = true;
                        $oldHeader = '';
                } else {
@@ -252,16 +266,16 @@ class DifferenceEngine extends ContextSource {
                        }
 
                        if ( $this->mNewPage->equals( $this->mOldPage ) ) {
-                               $out->setPageTitle( $this->mNewPage->getPrefixedText() );
-                               $out->addSubtitle( $this->msg( 'difference' ) );
+                               $out->setPageTitle( $this->msg( 'difference-title', $this->mNewPage->getPrefixedText() ) );
                                $samePage = true;
                        } else {
-                               $out->setPageTitle( $this->mOldPage->getPrefixedText() . ', ' . $this->mNewPage->getPrefixedText() );
+                               $out->setPageTitle( $this->msg( 'difference-title-multipage', $this->mOldPage->getPrefixedText(),
+                                       $this->mNewPage->getPrefixedText() ) );
                                $out->addSubtitle( $this->msg( 'difference-multipage' ) );
                                $samePage = false;
                        }
 
-                       if ( $samePage && $this->mNewPage->userCan( 'edit', $user ) ) {
+                       if ( $samePage && $this->mNewPage->quickUserCan( 'edit', $user ) ) {
                                if ( $this->mNewRev->isCurrent() && $this->mNewPage->userCan( 'rollback', $user ) ) {
                                        $out->preventClickjacking();
                                        $rollback = '&#160;&#160;&#160;' . Linker::generateRollback( $this->mNewRev );
@@ -403,7 +417,7 @@ class DifferenceEngine extends ContextSource {
 
                if ( $this->mMarkPatrolledLink === null ) {
                        // Prepare a change patrol link, if applicable
-                       if ( $wgUseRCPatrol && $this->mNewPage->userCan( 'patrol', $this->getUser() ) ) {
+                       if ( $wgUseRCPatrol && $this->mNewPage->quickUserCan( 'patrol', $this->getUser() ) ) {
                                // If we've been given an explicit change identifier, use it; saves time
                                if ( $this->mRcidMarkPatrolled ) {
                                        $rcid = $this->mRcidMarkPatrolled;
@@ -486,19 +500,20 @@ class DifferenceEngine extends ContextSource {
                        $out->setRevisionTimestamp( $this->mNewRev->getTimestamp() );
                        $out->setArticleFlag( true );
 
-                       if ( $this->mNewPage->isCssJsSubpage() || $this->mNewPage->isCssOrJsPage() ) { #FIXME: don't do this, use the content handler instead!!
+                       if ( $this->mNewPage->isCssJsSubpage() || $this->mNewPage->isCssOrJsPage() ) { #NOTE: only needed for B/C: custom rendering of JS/CSS via hook
                                // Stolen from Article::view --AG 2007-10-11
                                // Give hooks a chance to customise the output
                                // @TODO: standardize this crap into one function
-                               if ( wfRunHooks( 'ShowRawCssJs', array( $this->mNewtext, $this->mNewPage, $out ) ) ) { #FIXME: what to do with this hook??
-                                       // Wrap the whole lot in a <pre> and don't parse
-                                       $m = array();
-                                       preg_match( '!\.(css|js)$!u', $this->mNewPage->getText(), $m );
-                                       $out->addHTML( "<pre class=\"mw-code mw-{$m[1]}\" dir=\"ltr\">\n" );
-                                       $out->addHTML( htmlspecialchars( $this->mNewtext ) );
-                                       $out->addHTML( "\n</pre>\n" );
+                               if ( !Hook::isRegistered( 'ShowRawCssJs' )
+                                       || wfRunHooks( 'ShowRawCssJs', array( ContentHandler::getContentText( $this->mNewContent ), $this->mNewPage, $out ) ) ) { #NOTE: deperecated hook, B/C only
+                                       // use the content object's own rendering
+                                       $po = $this->mContentObject->getParserOutput();
+                                       $out->addHTML( $po->getText() );
                                }
-                       } elseif ( !wfRunHooks( 'ArticleViewCustom', array( $this->mNewtext, $this->mNewPage, $out ) ) ) { #FIXME: what do we pass here
+                       } elseif( !wfRunHooks( 'ArticleContentViewCustom', array( $this->mNewContent, $this->mNewPage, $out ) ) ) {
+                               // Handled by extension
+                       } elseif( Hooks::isRegistered( 'ArticleViewCustom' )
+                                       && !wfRunHooks( 'ArticleViewCustom', array( ContentHandler::getContentText( $this->mNewContent ), $this->mNewPage, $out ) ) ) { #NOTE: deperecated hook, B/C only
                                // Handled by extension
                        } else {
                                // Normal page
@@ -630,8 +645,6 @@ class DifferenceEngine extends ContextSource {
                        return false;
                }
 
-        #TODO: make sure both Content objects have the same content model. What do we do if they don't?
-
                $difftext = $this->generateContentDiffBody( $this->mOldContent, $this->mNewContent );
 
                // Save to cache for 7 days
@@ -669,45 +682,48 @@ class DifferenceEngine extends ContextSource {
                }
        }
 
-    /**
-     * Generate a diff, no caching.
-     *
-     * Subclasses may override this to provide a
-     *
-     * @param $old Content: old content
-     * @param $new Content: new content
-     */
-    function generateContentDiffBody( Content $old, Content $new ) {
-        #XXX: generate a warning if $old or $new are not instances of TextContent?
-        #XXX: fail if $old and $new don't have the same content model? or what?
-
-        $otext = $old->serialize();
-        $ntext = $new->serialize();
-
-        #XXX: text should be "already segmented". what does that mean?
-        return $this->generateTextDiffBody( $otext, $ntext );
-    }
-
-    /**
-     * Generate a diff, no caching
-     *
-     * @param $otext String: old text, must be already segmented
-     * @param $ntext String: new text, must be already segmented
-     * @deprecated since 1.20, use generateContentDiffBody() instead!
-     */
-    function generateDiffBody( $otext, $ntext ) {
-        wfDeprecated( __METHOD__, "1.20" );
-
-        return $this->generateTextDiffBody( $otext, $ntext );
-    }
+       /**
+        * Generate a diff, no caching.
+        *
+        * Subclasses may override this to provide a
+        *
+        * @param $old Content: old content
+        * @param $new Content: new content
+        *
+        * @since 1.WD
+        */
+       function generateContentDiffBody( Content $old, Content $new ) {
+               #XXX: generate a warning if $old or $new are not instances of TextContent?
+               #XXX: fail if $old and $new don't have the same content model? or what?
+
+               $otext = $old->serialize();
+               $ntext = $new->serialize();
+
+               #XXX: text should be "already segmented". what does that mean?
+               return $this->generateTextDiffBody( $otext, $ntext );
+       }
 
        /**
         * Generate a diff, no caching
         *
-     * @todo move this to TextDifferenceEngine, make DifferenceEngine abstract. At some point.
-     *
         * @param $otext String: old text, must be already segmented
         * @param $ntext String: new text, must be already segmented
+        * @deprecated since 1.WD, use generateContentDiffBody() instead!
+        */
+       function generateDiffBody( $otext, $ntext ) {
+               wfDeprecated( __METHOD__, "1.WD" );
+
+               return $this->generateTextDiffBody( $otext, $ntext );
+       }
+
+       /**
+        * Generate a diff, no caching
+        *
+        * @todo move this to TextDifferenceEngine, make DifferenceEngine abstract. At some point.
+        *
+        * @param $otext String: old text, must be already segmented
+        * @param $ntext String: new text, must be already segmented
+        * @return bool|string
         */
        function generateTextDiffBody( $otext, $ntext ) {
                global $wgExternalDiffEngine, $wgContLang;
@@ -741,9 +757,9 @@ class DifferenceEngine extends ContextSource {
                }
                if ( $wgExternalDiffEngine != 'wikidiff3' && $wgExternalDiffEngine !== false ) {
                        # Diff via the shell
-                       global $wgTmpDirectory;
-                       $tempName1 = tempnam( $wgTmpDirectory, 'diff_' );
-                       $tempName2 = tempnam( $wgTmpDirectory, 'diff_' );
+                       $tmpDir = wfTempDir();
+                       $tempName1 = tempnam( $tmpDir, 'diff_' );
+                       $tempName2 = tempnam( $tmpDir, 'diff_' );
 
                        $tempFile1 = fopen( $tempName1, "w" );
                        if ( !$tempFile1 ) {
@@ -783,6 +799,7 @@ class DifferenceEngine extends ContextSource {
        /**
         * Generate a debug comment indicating diff generating time,
         * server node, and generator backend.
+        * @return string
         */
        protected function debug( $generator = "internal" ) {
                global $wgShowHostnames;
@@ -804,6 +821,7 @@ class DifferenceEngine extends ContextSource {
 
        /**
         * Replace line numbers with the text in the user's language
+        * @return mixed
         */
        function localiseLineNumbers( $text ) {
                return preg_replace_callback( '/<!--LINE (\d+)-->/',
@@ -870,7 +888,7 @@ class DifferenceEngine extends ContextSource {
         *        the visibility of the revision and a link to edit the page.
         * @return String HTML fragment
         */
-       private function getRevisionHeader( Revision $rev, $complete = '' ) {
+       protected function getRevisionHeader( Revision $rev, $complete = '' ) {
                $lang = $this->getLanguage();
                $user = $this->getUser();
                $revtimestamp = $rev->getTimestamp();
@@ -900,7 +918,7 @@ class DifferenceEngine extends ContextSource {
                                $editQuery['oldid'] = $rev->getID();
                        }
 
-                       $msg = $this->msg( $title->userCan( 'edit', $user ) ? 'editold' : 'viewsourceold' )->escaped();
+                       $msg = $this->msg( $title->quickUserCan( 'edit', $user ) ? 'editold' : 'viewsourceold' )->escaped();
                        $header .= ' (' . Linker::linkKnown( $title, $msg, array(), $editQuery ) . ')';
                        if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
                                $header = Html::rawElement( 'span', array( 'class' => 'history-deleted' ), $header );
@@ -961,28 +979,28 @@ class DifferenceEngine extends ContextSource {
 
        /**
         * Use specified text instead of loading from the database
-     * @deprecated since 1.20
+        * @deprecated since 1.WD
         */
        function setText( $oldText, $newText ) { #FIXME: no longer use this, use setContent()!
-        wfDeprecated( __METHOD__, "1.20" );
+               wfDeprecated( __METHOD__, "1.WD" );
 
-        $oldContent = ContentHandler::makeContent( $oldText, $this->getTitle() );
-        $newContent = ContentHandler::makeContent( $newText, $this->getTitle() );
+               $oldContent = ContentHandler::makeContent( $oldText, $this->getTitle() );
+               $newContent = ContentHandler::makeContent( $newText, $this->getTitle() );
 
-        $this->setContent( $oldContent, $newContent );
-    }
+               $this->setContent( $oldContent, $newContent );
+       }
 
-    /**
-     * Use specified text instead of loading from the database
-     * @since 1.20
-     */
-    function setContent( Content $oldContent, Content $newContent ) {
-        $this->mOldContent = $oldContent;
-        $this->mNewContent = $newContent;
+       /**
+        * Use specified text instead of loading from the database
+        * @since 1.WD
+        */
+       function setContent( Content $oldContent, Content $newContent ) {
+               $this->mOldContent = $oldContent;
+               $this->mNewContent = $newContent;
 
-        $this->mTextLoaded = 2;
-        $this->mRevisionsLoaded = true;
-    }
+               $this->mTextLoaded = 2;
+               $this->mRevisionsLoaded = true;
+       }
 
        /**
         * Set the language in which the diff text is written