diff options
author | Luke Shumaker <LukeShu@sbcglobal.net> | 2014-01-28 09:50:25 -0500 |
---|---|---|
committer | Luke Shumaker <LukeShu@sbcglobal.net> | 2014-01-28 09:50:25 -0500 |
commit | 5744df39e15f85c6cc8a9faf8924d77e76d2b216 (patch) | |
tree | a8c8dd40a94d1fa0d5377566aa5548ae55a163da /includes/diff | |
parent | 4bb2aeca1d198391ca856aa16c40b8559c68daec (diff) | |
parent | 224b22a051051f6c2e494c3a2fb4adb42898e2d1 (diff) |
Merge branch 'archwiki'
Conflicts:
extensions/FluxBBAuthPlugin.php
extensions/SyntaxHighlight_GeSHi/README
extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.class.php
extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.i18n.php
extensions/SyntaxHighlight_GeSHi/SyntaxHighlight_GeSHi.php
extensions/SyntaxHighlight_GeSHi/geshi/docs/CHANGES
extensions/SyntaxHighlight_GeSHi/geshi/docs/THANKS
extensions/SyntaxHighlight_GeSHi/geshi/docs/TODO
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractClass.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractClass_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractMethod.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractPrivateClass.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractPrivateClass_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/AbstractPrivateMethod.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Class.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Class_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Constant.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Constructor.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Destructor.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Function.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Global.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/I.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Index.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Interface.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Interface_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/L.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Lminus.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Lplus.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Method.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Page.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Page_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateClass.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateClass_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateMethod.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/PrivateVariable.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/StaticMethod.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/StaticVariable.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/T.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Tminus.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Tplus.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/Variable.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/blank.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/class_folder.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/file.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/folder.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/function_folder.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/next_button.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/next_button_disabled.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/package.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/package_folder.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/previous_button.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/previous_button_disabled.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/private_class_logo.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/tutorial.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/tutorial_folder.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/api/media/images/up_button.png
extensions/SyntaxHighlight_GeSHi/geshi/docs/geshi-doc.html
extensions/SyntaxHighlight_GeSHi/geshi/docs/geshi-doc.txt
extensions/SyntaxHighlight_GeSHi/geshi/geshi.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/4cs.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/6502acme.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/6502kickass.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/6502tasm.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/68000devpac.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/abap.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/actionscript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/actionscript3.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/ada.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/algol68.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/apache.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/applescript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/apt_sources.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/asm.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/asp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/autoconf.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/autohotkey.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/autoit.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/avisynth.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/awk.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/bascomavr.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/bash.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/basic4gl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/bf.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/bibtex.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/blitzbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/bnf.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/boo.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/c.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/c_loadrunner.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/c_mac.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/caddcl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cadlisp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cfdg.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cfm.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/chaiscript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cil.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/clojure.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cmake.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cobol.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/coffeescript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cpp-qt.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cpp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/csharp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/css.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/cuesheet.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/d.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/dcs.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/delphi.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/diff.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/div.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/dos.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/dot.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/e.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/ecmascript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/eiffel.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/email.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/epc.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/erlang.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/euphoria.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/f1.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/falcon.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/fo.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/fortran.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/freebasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/fsharp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/gambas.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/gdb.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/genero.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/genie.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/gettext.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/glsl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/gml.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/gnuplot.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/go.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/groovy.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/gwbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/haskell.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/hicest.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/hq9plus.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/html4strict.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/html5.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/icon.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/idl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/ini.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/inno.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/intercal.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/io.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/j.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/java.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/java5.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/javascript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/jquery.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/kixtart.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/klonec.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/klonecpp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/latex.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lb.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lisp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/llvm.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/locobasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/logtalk.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lolcode.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lotusformulas.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lotusscript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lscript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lsl2.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/lua.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/m68k.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/magiksf.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/make.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/mapbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/matlab.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/mirc.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/mmix.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/modula2.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/modula3.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/mpasm.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/mxml.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/mysql.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/newlisp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/nsis.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/oberon2.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/objc.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/objeck.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/ocaml-brief.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/ocaml.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/oobas.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/oracle11.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/oracle8.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/oxygene.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/oz.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pascal.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pcre.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/per.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/perl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/perl6.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pf.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/php-brief.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/php.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pic16.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pike.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pixelbender.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pli.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/plsql.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/postgresql.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/povray.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/powerbuilder.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/powershell.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/proftpd.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/progress.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/prolog.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/properties.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/providex.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/purebasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/pycon.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/python.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/q.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/qbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/rails.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/rebol.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/reg.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/robots.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/rpmspec.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/rsplus.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/ruby.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/sas.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/scala.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/scheme.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/scilab.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/sdlbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/smalltalk.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/smarty.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/sql.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/systemverilog.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/tcl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/teraterm.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/text.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/thinbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/tsql.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/typoscript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/unicon.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/uscript.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/vala.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/vb.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/vbnet.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/verilog.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/vhdl.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/vim.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/visualfoxpro.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/visualprolog.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/whitespace.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/whois.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/winbatch.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/xbasic.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/xml.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/xorg_conf.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/xpp.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/yaml.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/z80.php
extensions/SyntaxHighlight_GeSHi/geshi/geshi/zxbasic.php
Diffstat (limited to 'includes/diff')
-rw-r--r-- | includes/diff/DairikiDiff.php | 117 | ||||
-rw-r--r-- | includes/diff/DifferenceEngine.php | 364 | ||||
-rw-r--r-- | includes/diff/WikiDiff3.php | 5 |
3 files changed, 301 insertions, 185 deletions
diff --git a/includes/diff/DairikiDiff.php b/includes/diff/DairikiDiff.php index 72eb5d3c..298d7240 100644 --- a/includes/diff/DairikiDiff.php +++ b/includes/diff/DairikiDiff.php @@ -5,6 +5,21 @@ * Copyright © 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org> * You may copy this code freely under the conditions of the GPL. * + * 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 * @defgroup DifferenceEngine DifferenceEngine @@ -28,14 +43,14 @@ class _DiffOp { * @return int */ function norig() { - return $this->orig ? sizeof( $this->orig ) : 0; + return $this->orig ? count( $this->orig ) : 0; } /** * @return int */ function nclosing() { - return $this->closing ? sizeof( $this->closing ) : 0; + return $this->closing ? count( $this->closing ) : 0; } } @@ -152,7 +167,7 @@ class _DiffOp_Change extends _DiffOp { */ class _DiffEngine { - const MAX_XREF_LENGTH = 10000; + const MAX_XREF_LENGTH = 10000; protected $xchanged, $ychanged; @@ -168,7 +183,7 @@ class _DiffEngine { * @param $to_lines * @return array */ - function diff ( $from_lines, $to_lines ) { + function diff( $from_lines, $to_lines ) { wfProfileIn( __METHOD__ ); // Diff and store locally @@ -179,8 +194,8 @@ class _DiffEngine { $this->_shift_boundaries( $to_lines, $this->ychanged, $this->xchanged ); // Compute the edit operations. - $n_from = sizeof( $from_lines ); - $n_to = sizeof( $to_lines ); + $n_from = count( $from_lines ); + $n_to = count( $to_lines ); $edits = array(); $xi = $yi = 0; @@ -206,7 +221,7 @@ class _DiffEngine { } $add = array(); - while ( $yi < $n_to && $this->ychanged[$yi] ) { + while ( $yi < $n_to && $this->ychanged[$yi] ) { $add[] = $to_lines[$yi++]; } @@ -226,7 +241,7 @@ class _DiffEngine { * @param $from_lines * @param $to_lines */ - function diff_local ( $from_lines, $to_lines ) { + function diff_local( $from_lines, $to_lines ) { global $wgExternalDiffEngine; wfProfileIn( __METHOD__ ); @@ -239,8 +254,8 @@ class _DiffEngine { unset( $wikidiff3 ); } else { // old diff - $n_from = sizeof( $from_lines ); - $n_to = sizeof( $to_lines ); + $n_from = count( $from_lines ); + $n_to = count( $to_lines ); $this->xchanged = $this->ychanged = array(); $this->xv = $this->yv = array(); $this->xind = $this->yind = array(); @@ -256,7 +271,8 @@ class _DiffEngine { $this->xchanged[$skip] = $this->ychanged[$skip] = false; } // Skip trailing common lines. - $xi = $n_from; $yi = $n_to; + $xi = $n_from; + $yi = $n_to; for ( $endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++ ) { if ( $from_lines[$xi] !== $to_lines[$yi] ) { break; @@ -288,7 +304,7 @@ class _DiffEngine { } // Find the LCS. - $this->_compareseq( 0, sizeof( $this->xv ), 0, sizeof( $this->yv ) ); + $this->_compareseq( 0, count( $this->xv ), 0, count( $this->yv ) ); } wfProfileOut( __METHOD__ ); } @@ -311,7 +327,7 @@ class _DiffEngine { * [XOFF, XLIM) and [YOFF, YLIM) into NCHUNKS approximately equally * sized segments. * - * Returns (LCS, PTS). LCS is the length of the LCS. PTS is an + * Returns (LCS, PTS). LCS is the length of the LCS. PTS is an * array of NCHUNKS+1 (X, Y) indexes giving the diving points between * sub sequences. The first sub-sequence is contained in [X0, X1), * [Y0, Y1), the second in [X1, X2), [Y1, Y2) and so on. Note @@ -379,7 +395,7 @@ class _DiffEngine { break; } } - while ( list ( , $y ) = each( $matches ) ) { + while ( list( , $y ) = each( $matches ) ) { if ( $y > $this->seq[$k -1] ) { assert( '$y < $this->seq[$k]' ); // Optimization: this is a common case: @@ -454,10 +470,9 @@ class _DiffEngine { * @param $yoff * @param $ylim */ - function _compareseq ( $xoff, $xlim, $yoff, $ylim ) { + function _compareseq( $xoff, $xlim, $yoff, $ylim ) { // Slide down the bottom initial diagonal. - while ( $xoff < $xlim && $yoff < $ylim - && $this->xv[$xoff] == $this->yv[$yoff] ) { + while ( $xoff < $xlim && $yoff < $ylim && $this->xv[$xoff] == $this->yv[$yoff] ) { ++$xoff; ++$yoff; } @@ -476,8 +491,7 @@ class _DiffEngine { // $nchunks = sqrt(min($xlim - $xoff, $ylim - $yoff) / 2.5); // $nchunks = max(2,min(8,(int)$nchunks)); $nchunks = min( 7, $xlim - $xoff, $ylim - $yoff ) + 1; - list ( $lcs, $seps ) - = $this->_diag( $xoff, $xlim, $yoff, $ylim, $nchunks ); + list( $lcs, $seps ) = $this->_diag( $xoff, $xlim, $yoff, $ylim, $nchunks ); } if ( $lcs == 0 ) { @@ -494,7 +508,7 @@ class _DiffEngine { reset( $seps ); $pt1 = $seps[0]; while ( $pt2 = next( $seps ) ) { - $this->_compareseq ( $pt1[0], $pt2[0], $pt1[1], $pt2[1] ); + $this->_compareseq( $pt1[0], $pt2[0], $pt1[1], $pt2[1] ); $pt1 = $pt2; } } @@ -518,9 +532,9 @@ class _DiffEngine { $i = 0; $j = 0; - assert( 'sizeof($lines) == sizeof($changed)' ); - $len = sizeof( $lines ); - $other_len = sizeof( $other_changed ); + assert( 'count($lines) == count($changed)' ); + $len = count( $lines ); + $other_len = count( $other_changed ); while ( 1 ) { /* @@ -540,9 +554,11 @@ class _DiffEngine { while ( $i < $len && ! $changed[$i] ) { assert( '$j < $other_len && ! $other_changed[$j]' ); - $i++; $j++; - while ( $j < $other_len && $other_changed[$j] ) + $i++; $j++; + while ( $j < $other_len && $other_changed[$j] ) { + $j++; + } } if ( $i == $len ) { @@ -676,7 +692,7 @@ class Diff { /** * Check for empty diff. * - * @return bool True iff two sequences were identical. + * @return bool True if two sequences were identical. */ function isEmpty() { foreach ( $this->edits as $edit ) { @@ -698,7 +714,7 @@ class Diff { $lcs = 0; foreach ( $this->edits as $edit ) { if ( $edit->type == 'copy' ) { - $lcs += sizeof( $edit->orig ); + $lcs += count( $edit->orig ); } } return $lcs; @@ -717,7 +733,7 @@ class Diff { foreach ( $this->edits as $edit ) { if ( $edit->orig ) { - array_splice( $lines, sizeof( $lines ), 0, $edit->orig ); + array_splice( $lines, count( $lines ), 0, $edit->orig ); } } return $lines; @@ -736,7 +752,7 @@ class Diff { foreach ( $this->edits as $edit ) { if ( $edit->closing ) { - array_splice( $lines, sizeof( $lines ), 0, $edit->closing ); + array_splice( $lines, count( $lines ), 0, $edit->closing ); } } return $lines; @@ -766,7 +782,6 @@ class Diff { trigger_error( "Reversed closing doesn't match", E_USER_ERROR ); } - $prevtype = 'none'; foreach ( $this->edits as $edit ) { if ( $prevtype == $edit->type ) { @@ -814,23 +829,23 @@ class MappedDiff extends Diff { $mapped_from_lines, $mapped_to_lines ) { wfProfileIn( __METHOD__ ); - assert( 'sizeof( $from_lines ) == sizeof( $mapped_from_lines )' ); - assert( 'sizeof( $to_lines ) == sizeof( $mapped_to_lines )' ); + assert( 'count( $from_lines ) == count( $mapped_from_lines )' ); + assert( 'count( $to_lines ) == count( $mapped_to_lines )' ); parent::__construct( $mapped_from_lines, $mapped_to_lines ); $xi = $yi = 0; - for ( $i = 0; $i < sizeof( $this->edits ); $i++ ) { + for ( $i = 0; $i < count( $this->edits ); $i++ ) { $orig = &$this->edits[$i]->orig; if ( is_array( $orig ) ) { - $orig = array_slice( $from_lines, $xi, sizeof( $orig ) ); - $xi += sizeof( $orig ); + $orig = array_slice( $from_lines, $xi, count( $orig ) ); + $xi += count( $orig ); } $closing = &$this->edits[$i]->closing; if ( is_array( $closing ) ) { - $closing = array_slice( $to_lines, $yi, sizeof( $closing ) ); - $yi += sizeof( $closing ); + $closing = array_slice( $to_lines, $yi, count( $closing ) ); + $yi += count( $closing ); } } wfProfileOut( __METHOD__ ); @@ -885,7 +900,7 @@ class DiffFormatter { foreach ( $diff->edits as $edit ) { if ( $edit->type == 'copy' ) { if ( is_array( $block ) ) { - if ( sizeof( $edit->orig ) <= $nlead + $ntrail ) { + if ( count( $edit->orig ) <= $nlead + $ntrail ) { $block[] = $edit; } else { if ( $ntrail ) { @@ -901,9 +916,9 @@ class DiffFormatter { $context = $edit->orig; } else { if ( !is_array( $block ) ) { - $context = array_slice( $context, sizeof( $context ) - $nlead ); - $x0 = $xi - sizeof( $context ); - $y0 = $yi - sizeof( $context ); + $context = array_slice( $context, count( $context ) - $nlead ); + $x0 = $xi - count( $context ); + $y0 = $yi - count( $context ); $block = array(); if ( $context ) { $block[] = new _DiffOp_Copy( $context ); @@ -913,10 +928,10 @@ class DiffFormatter { } if ( $edit->orig ) { - $xi += sizeof( $edit->orig ); + $xi += count( $edit->orig ); } if ( $edit->closing ) { - $yi += sizeof( $edit->closing ); + $yi += count( $edit->closing ); } } @@ -1096,7 +1111,7 @@ class ArrayDiffFormatter extends DiffFormatter { $newline = 1; $retval = array(); foreach ( $diff->edits as $edit ) { - switch( $edit->type ) { + switch ( $edit->type ) { case 'add': foreach ( $edit->closing as $l ) { $retval[] = array( @@ -1191,7 +1206,7 @@ class _HWLDF_WordAccumulator { * @param $words * @param $tag string */ - function addWords ( $words, $tag = '' ) { + function addWords( $words, $tag = '' ) { if ( $tag != $this->_tag ) { $this->_flushGroup( $tag ); } @@ -1231,7 +1246,7 @@ class WordLevelDiff extends MappedDiff { * @param $orig_lines * @param $closing_lines */ - function __construct ( $orig_lines, $closing_lines ) { + function __construct( $orig_lines, $closing_lines ) { wfProfileIn( __METHOD__ ); list( $orig_words, $orig_stripped ) = $this->_split( $orig_lines ); @@ -1269,8 +1284,12 @@ class WordLevelDiff extends MappedDiff { if ( preg_match_all( '/ ( [^\S\n]+ | [0-9_A-Za-z\x80-\xff]+ | . ) (?: (?!< \n) [^\S\n])? /xs', $line, $m ) ) { - $words = array_merge( $words, $m[0] ); - $stripped = array_merge( $stripped, $m[1] ); + foreach ( $m[0] as $word ) { + $words[] = $word; + } + foreach ( $m[1] as $stripped_word ) { + $stripped[] = $stripped_word; + } } } } @@ -1350,7 +1369,7 @@ class TableDiffFormatter extends DiffFormatter { */ function _block_header( $xbeg, $xlen, $ybeg, $ylen ) { $r = '<tr><td colspan="2" class="diff-lineno"><!--LINE ' . $xbeg . "--></td>\n" . - '<td colspan="2" class="diff-lineno"><!--LINE ' . $ybeg . "--></td></tr>\n"; + '<td colspan="2" class="diff-lineno"><!--LINE ' . $ybeg . "--></td></tr>\n"; return $r; } diff --git a/includes/diff/DifferenceEngine.php b/includes/diff/DifferenceEngine.php index c7156fb2..e436f58d 100644 --- a/includes/diff/DifferenceEngine.php +++ b/includes/diff/DifferenceEngine.php @@ -38,14 +38,17 @@ class DifferenceEngine extends ContextSource { * @private */ var $mOldid, $mNewid; - var $mOldtext, $mNewtext; + var $mOldTags, $mNewTags; + /** + * @var Content + */ + var $mOldContent, $mNewContent; protected $mDiffLang; /** * @var Title */ var $mOldPage, $mNewPage; - var $mRcidMarkPatrolled; /** * @var Revision @@ -78,7 +81,7 @@ class DifferenceEngine extends ContextSource { * @param $context IContextSource context to use, anything else will be ignored * @param $old Integer old ID we want to show and diff with. * @param $new String either 'prev' or 'next'. - * @param $rcid Integer ??? FIXME (default 0) + * @param $rcid Integer Deprecated, no longer used! * @param $refreshCache boolean If set, refreshes the diff cache * @param $unhide boolean If set, allow viewing deleted revs */ @@ -93,7 +96,6 @@ class DifferenceEngine extends ContextSource { $this->mOldid = $old; $this->mNewid = $new; - $this->mRcidMarkPatrolled = intval( $rcid ); # force it to be an integer $this->mRefreshCache = $refreshCache; $this->unhide = $unhide; } @@ -149,7 +151,7 @@ class DifferenceEngine extends ContextSource { function deletedLink( $id ) { if ( $this->getUser()->isAllowed( 'deletedhistory' ) ) { $dbr = wfGetDB( DB_SLAVE ); - $row = $dbr->selectRow('archive', '*', + $row = $dbr->selectRow( 'archive', '*', array( 'ar_rev_id' => $id ), __METHOD__ ); if ( $row ) { @@ -183,10 +185,14 @@ class DifferenceEngine extends ContextSource { $out = $this->getOutput(); $missing = array(); - if ( $this->mOldRev === null ) { + if ( $this->mOldRev === null || + ( $this->mOldRev && $this->mOldContent === null ) + ) { $missing[] = $this->deletedIdMarker( $this->mOldid ); } - if ( $this->mNewRev === null ) { + if ( $this->mNewRev === null || + ( $this->mNewRev && $this->mNewContent === null ) + ) { $missing[] = $this->deletedIdMarker( $this->mNewid ); } @@ -220,29 +226,6 @@ class DifferenceEngine extends ContextSource { throw new PermissionsError( 'read', $permErrors ); } - # 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' ) ) { - $urls = array( - 'File' => array( 'Extension' => 'wiki', 'URL' => - # This should be mOldPage, but it may not be set, see below. - $this->mNewPage->getCanonicalURL( array( - 'action' => 'raw', 'oldid' => $this->mOldid ) ) - ), - 'File2' => array( 'Extension' => 'wiki', 'URL' => - $this->mNewPage->getCanonicalURL( array( - 'action' => 'raw', 'oldid' => $this->mNewid ) ) - ), - ); - - $externalEditor = new ExternalEdit( $this->getContext(), $urls ); - $externalEditor->execute(); - - wfProfileOut( __METHOD__ ); - return; - } - $rollback = ''; $undoLink = ''; @@ -260,6 +243,8 @@ class DifferenceEngine extends ContextSource { $deleted = $suppressed = false; $allowed = $this->mNewRev->userCan( Revision::DELETED_TEXT, $user ); + $revisionTools = array(); + # mOldRev is false if the difference engine is called with a "vague" query for # 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. @@ -270,11 +255,6 @@ class DifferenceEngine extends ContextSource { } else { wfRunHooks( 'DiffViewHeader', array( $this, $this->mOldRev, $this->mNewRev ) ); - $sk = $this->getSkin(); - if ( method_exists( $sk, 'suppressQuickbar' ) ) { - $sk->suppressQuickbar(); - } - if ( $this->mNewPage->equals( $this->mOldPage ) ) { $out->setPageTitle( $this->msg( 'difference-title', $this->mNewPage->getPrefixedText() ) ); $samePage = true; @@ -287,20 +267,23 @@ class DifferenceEngine extends ContextSource { if ( $samePage && $this->mNewPage->quickUserCan( 'edit', $user ) ) { if ( $this->mNewRev->isCurrent() && $this->mNewPage->userCan( 'rollback', $user ) ) { - $out->preventClickjacking(); - $rollback = '   ' . Linker::generateRollback( $this->mNewRev, $this->getContext() ); + $rollbackLink = Linker::generateRollback( $this->mNewRev, $this->getContext() ); + if ( $rollbackLink ) { + $out->preventClickjacking(); + $rollback = '   ' . $rollbackLink; + } } if ( !$this->mOldRev->isDeleted( Revision::DELETED_TEXT ) && !$this->mNewRev->isDeleted( Revision::DELETED_TEXT ) ) { - $undoLink = ' ' . $this->msg( 'parentheses' )->rawParams( - Html::element( 'a', array( - 'href' => $this->mNewPage->getLocalUrl( array( + $undoLink = Html::element( 'a', array( + 'href' => $this->mNewPage->getLocalURL( array( 'action' => 'edit', 'undoafter' => $this->mOldid, 'undo' => $this->mNewid ) ), 'title' => Linker::titleAttrib( 'undo' ) ), $this->msg( 'editundo' )->text() - ) )->escaped(); + ); + $revisionTools[] = $undoLink; } } @@ -324,12 +307,14 @@ class DifferenceEngine extends ContextSource { $ldel = $this->revisionDeleteLink( $this->mOldRev ); $oldRevisionHeader = $this->getRevisionHeader( $this->mOldRev, 'complete' ); + $oldChangeTags = ChangeTags::formatSummaryRow( $this->mOldTags, 'diff' ); $oldHeader = '<div id="mw-diff-otitle1"><strong>' . $oldRevisionHeader . '</strong></div>' . '<div id="mw-diff-otitle2">' . Linker::revUserTools( $this->mOldRev, !$this->unhide ) . '</div>' . '<div id="mw-diff-otitle3">' . $oldminor . Linker::revComment( $this->mOldRev, !$diffOnly, !$this->unhide ) . $ldel . '</div>' . + '<div id="mw-diff-otitle5">' . $oldChangeTags[0] . '</div>' . '<div id="mw-diff-otitle4">' . $prevlink . '</div>'; if ( $this->mOldRev->isDeleted( Revision::DELETED_TEXT ) ) { @@ -366,19 +351,30 @@ class DifferenceEngine extends ContextSource { # Handle RevisionDelete links... $rdel = $this->revisionDeleteLink( $this->mNewRev ); - $newRevisionHeader = $this->getRevisionHeader( $this->mNewRev, 'complete' ) . $undoLink; + + # Allow extensions to define their own revision tools + wfRunHooks( 'DiffRevisionTools', array( $this->mNewRev, &$revisionTools ) ); + $formattedRevisionTools = array(); + // Put each one in parentheses (poor man's button) + foreach ( $revisionTools as $tool ) { + $formattedRevisionTools[] = $this->msg( 'parentheses' )->rawParams( $tool )->escaped(); + } + $newRevisionHeader = $this->getRevisionHeader( $this->mNewRev, 'complete' ) . ' ' . implode( ' ', $formattedRevisionTools ); + $newChangeTags = ChangeTags::formatSummaryRow( $this->mNewTags, 'diff' ); $newHeader = '<div id="mw-diff-ntitle1"><strong>' . $newRevisionHeader . '</strong></div>' . '<div id="mw-diff-ntitle2">' . Linker::revUserTools( $this->mNewRev, !$this->unhide ) . " $rollback</div>" . '<div id="mw-diff-ntitle3">' . $newminor . Linker::revComment( $this->mNewRev, !$diffOnly, !$this->unhide ) . $rdel . '</div>' . + '<div id="mw-diff-ntitle5">' . $newChangeTags[0] . '</div>' . '<div id="mw-diff-ntitle4">' . $nextlink . $this->markPatrolledLink() . '</div>'; if ( $this->mNewRev->isDeleted( Revision::DELETED_TEXT ) ) { $deleted = true; // new revisions text is hidden - if ( $this->mNewRev->isDeleted( Revision::DELETED_RESTRICTED ) ) + if ( $this->mNewRev->isDeleted( Revision::DELETED_RESTRICTED ) ) { $suppressed = true; // also suppressed + } } # If the diff cannot be shown due to a deleted revision, then output @@ -394,7 +390,7 @@ class DifferenceEngine extends ContextSource { array( $msg ) ); } else { # Give explanation and add a link to view the diff... - $link = $this->getTitle()->getFullUrl( $this->getRequest()->appendQueryValue( 'unhide', '1', true ) ); + $link = $this->getTitle()->getFullURL( $this->getRequest()->appendQueryValue( 'unhide', '1', true ) ); $msg = $suppressed ? 'rev-suppressed-unhide-diff' : 'rev-deleted-unhide-diff'; $out->wrapWikiMsg( "<div id='mw-$msg' class='mw-warning plainlinks'>\n$1\n</div>\n", array( $msg, $link ) ); } @@ -417,49 +413,54 @@ class DifferenceEngine extends ContextSource { /** * Get a link to mark the change as patrolled, or '' if there's either no * revision to patrol or the user is not allowed to to it. - * Side effect: this method will call OutputPage::preventClickjacking() - * when a link is builded. + * Side effect: When the patrol link is build, this method will call + * OutputPage::preventClickjacking() and load mediawiki.page.patrol.ajax. * * @return String */ protected function markPatrolledLink() { - global $wgUseRCPatrol; + global $wgUseRCPatrol, $wgEnableAPI, $wgEnableWriteAPI; + $user = $this->getUser(); if ( $this->mMarkPatrolledLink === null ) { // Prepare a change patrol link, if applicable - 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; - $rc = RecentChange::newFromId( $rcid ); - // Already patrolled? - $rcid = is_object( $rc ) && !$rc->getAttribute( 'rc_patrolled' ) ? $rcid : 0; + if ( + // Is patrolling enabled and the user allowed to? + $wgUseRCPatrol && $this->mNewPage->quickUserCan( 'patrol', $user ) && + // Only do this if the revision isn't more than 6 hours older + // than the Max RC age (6h because the RC might not be cleaned out regularly) + RecentChange::isInRCLifespan( $this->mNewRev->getTimestamp(), 21600 ) + ) { + // Look for an unpatrolled change corresponding to this diff + + $db = wfGetDB( DB_SLAVE ); + $change = RecentChange::newFromConds( + array( + 'rc_timestamp' => $db->timestamp( $this->mNewRev->getTimestamp() ), + 'rc_this_oldid' => $this->mNewid, + 'rc_patrolled' => 0 + ), + __METHOD__, + array( 'USE INDEX' => 'rc_timestamp' ) + ); + + if ( $change && $change->getPerformer()->getName() !== $user->getName() ) { + $rcid = $change->getAttribute( 'rc_id' ); } else { - // Look for an unpatrolled change corresponding to this diff - $db = wfGetDB( DB_SLAVE ); - $change = RecentChange::newFromConds( - array( - // Redundant user,timestamp condition so we can use the existing index - 'rc_user_text' => $this->mNewRev->getRawUserText(), - 'rc_timestamp' => $db->timestamp( $this->mNewRev->getTimestamp() ), - 'rc_this_oldid' => $this->mNewid, - 'rc_last_oldid' => $this->mOldid, - 'rc_patrolled' => 0 - ), - __METHOD__ - ); - if ( $change instanceof RecentChange ) { - $rcid = $change->mAttribs['rc_id']; - $this->mRcidMarkPatrolled = $rcid; - } else { - // None found - $rcid = 0; - } + // None found or the page has been created by the current user. + // If the user could patrol this it already would be patrolled + $rcid = 0; } // Build the link if ( $rcid ) { $this->getOutput()->preventClickjacking(); - $token = $this->getUser()->getEditToken( $rcid ); + if ( $wgEnableAPI && $wgEnableWriteAPI + && $user->isAllowed( 'writeapi' ) + ) { + $this->getOutput()->addModules( 'mediawiki.page.patrol.ajax' ); + } + + $token = $user->getEditToken( $rcid ); $this->mMarkPatrolledLink = ' <span class="patrollink">[' . Linker::linkKnown( $this->mNewPage, $this->msg( 'markaspatrolleddiff' )->escaped(), @@ -510,19 +511,23 @@ class DifferenceEngine extends ContextSource { $out->setRevisionTimestamp( $this->mNewRev->getTimestamp() ); $out->setArticleFlag( true ); + // NOTE: only needed for B/C: custom rendering of JS/CSS via hook if ( $this->mNewPage->isCssJsSubpage() || $this->mNewPage->isCssOrJsPage() ) { // 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 ) ) ) { - // 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" ); + // @todo standardize this crap into one function + if ( ContentHandler::runLegacyHooks( 'ShowRawCssJs', array( $this->mNewContent, $this->mNewPage, $out ) ) ) { + // NOTE: deprecated hook, B/C only + // use the content object's own rendering + $cnt = $this->mNewRev->getContent(); + $po = $cnt ? $cnt->getParserOutput( $this->mNewRev->getTitle(), $this->mNewRev->getId() ) : null; + $txt = $po ? $po->getText() : ''; + $out->addHTML( $txt ); } - } elseif ( !wfRunHooks( 'ArticleViewCustom', array( $this->mNewtext, $this->mNewPage, $out ) ) ) { + } elseif ( !wfRunHooks( 'ArticleContentViewCustom', array( $this->mNewContent, $this->mNewPage, $out ) ) ) { + // Handled by extension + } elseif ( !ContentHandler::runLegacyHooks( 'ArticleViewCustom', array( $this->mNewContent, $this->mNewPage, $out ) ) ) { + // NOTE: deprecated hook, B/C only // Handled by extension } else { // Normal page @@ -536,16 +541,21 @@ class DifferenceEngine extends ContextSource { $wikiPage = WikiPage::factory( $this->mNewPage ); } - $parserOptions = $wikiPage->makeParserOptions( $this->getContext() ); + $parserOutput = $this->getParserOutput( $wikiPage, $this->mNewRev ); - if ( !$this->mNewRev->isCurrent() ) { - $parserOptions->setEditSection( false ); - } + # Also try to load it as a redirect + $rt = $this->mNewContent ? $this->mNewContent->getRedirectTarget() : null; - $parserOutput = $wikiPage->getParserOutput( $parserOptions, $this->mNewid ); + if ( $rt ) { + $article = Article::newFromTitle( $this->mNewPage, $this->getContext() ); + $out->addHTML( $article->viewRedirect( $rt ) ); - # WikiPage::getParserOutput() should not return false, but just in case - if( $parserOutput ) { + # WikiPage::getParserOutput() should not return false, but just in case + if ( $parserOutput ) { + # Show categories etc. + $out->addParserOutputNoText( $parserOutput ); + } + } elseif ( $parserOutput ) { $out->addParserOutput( $parserOutput ); } } @@ -556,6 +566,17 @@ class DifferenceEngine extends ContextSource { wfProfileOut( __METHOD__ ); } + protected function getParserOutput( WikiPage $page, Revision $rev ) { + $parserOptions = $page->makeParserOptions( $this->getContext() ); + + if ( !$rev->isCurrent() || !$rev->getTitle()->quickUserCan( "edit" ) ) { + $parserOptions->setEditSection( false ); + } + + $parserOutput = $page->getParserOutput( $parserOptions, $rev->getId() ); + return $parserOutput; + } + /** * Get the diff text, send it to the OutputPage object * Returns false if the diff could not be generated, otherwise returns true @@ -584,9 +605,9 @@ class DifferenceEngine extends ContextSource { /** * Get complete diff table, including header * - * @param $otitle Title: old title - * @param $ntitle Title: new title - * @param $notice String: HTML between diff header and body + * @param string|bool $otitle Header for old text or false + * @param string|bool $ntitle Header for new text or false + * @param string $notice HTML between diff header and body * @return mixed */ function getDiff( $otitle, $ntitle, $notice = '' ) { @@ -595,6 +616,10 @@ class DifferenceEngine extends ContextSource { return false; } else { $multi = $this->getMultiNotice(); + // Display a message when the diff is empty + if ( $body === '' ) { + $notice .= '<div class="mw-diff-empty">' . $this->msg( 'diff-empty' )->parse() . "</div>\n"; + } return $this->addHeader( $body, $otitle, $ntitle, $multi, $notice ); } } @@ -620,7 +645,6 @@ class DifferenceEngine extends ContextSource { return false; } // Short-circuit - // If mOldRev is false, it means that the if ( $this->mOldRev === false || ( $this->mOldRev && $this->mNewRev && $this->mOldRev->getID() == $this->mNewRev->getID() ) ) { @@ -652,7 +676,7 @@ class DifferenceEngine extends ContextSource { return false; } - $difftext = $this->generateDiffBody( $this->mOldtext, $this->mNewtext ); + $difftext = $this->generateContentDiffBody( $this->mOldContent, $this->mNewContent ); // Save to cache for 7 days if ( !wfRunHooks( 'AbortDiffCache', array( &$this ) ) ) { @@ -672,31 +696,64 @@ class DifferenceEngine extends ContextSource { } /** - * Make sure the proper modules are loaded before we try to - * make the diff + * Generate a diff, no caching. + * + * This implementation uses generateTextDiffBody() to generate a diff based on the default + * serialization of the given Content objects. This will fail if $old or $new are not + * instances of TextContent. + * + * Subclasses may override this to provide a different rendering for the diff, + * perhaps taking advantage of the content's native form. This is required for all content + * models that are not text based. + * + * @param $old Content: old content + * @param $new Content: new content + * + * @return bool|string + * @since 1.21 + * @throws MWException if $old or $new are not instances of TextContent. */ - private function initDiffEngines() { - global $wgExternalDiffEngine; - if ( $wgExternalDiffEngine == 'wikidiff' && !function_exists( 'wikidiff_do_diff' ) ) { - wfProfileIn( __METHOD__ . '-php_wikidiff.so' ); - wfDl( 'php_wikidiff' ); - wfProfileOut( __METHOD__ . '-php_wikidiff.so' ); + function generateContentDiffBody( Content $old, Content $new ) { + if ( !( $old instanceof TextContent ) ) { + throw new MWException( "Diff not implemented for " . get_class( $old ) . "; " + . "override generateContentDiffBody to fix this." ); } - elseif ( $wgExternalDiffEngine == 'wikidiff2' && !function_exists( 'wikidiff2_do_diff' ) ) { - wfProfileIn( __METHOD__ . '-php_wikidiff2.so' ); - wfDl( 'wikidiff2' ); - wfProfileOut( __METHOD__ . '-php_wikidiff2.so' ); + + if ( !( $new instanceof TextContent ) ) { + throw new MWException( "Diff not implemented for " . get_class( $new ) . "; " + . "override generateContentDiffBody to fix this." ); } + + $otext = $old->serialize(); + $ntext = $new->serialize(); + + 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 + * @param string $otext old text, must be already segmented + * @param string $ntext new text, must be already segmented * @return bool|string + * @deprecated since 1.21, use generateContentDiffBody() instead! */ function generateDiffBody( $otext, $ntext ) { + ContentHandler::deprecated( __METHOD__, "1.21" ); + + return $this->generateTextDiffBody( $otext, $ntext ); + } + + /** + * Generate a diff, no caching + * + * @todo move this to TextDifferenceEngine, make DifferenceEngine abstract. At some point. + * + * @param string $otext old text, must be already segmented + * @param string $ntext new text, must be already segmented + * @return bool|string + */ + function generateTextDiffBody( $otext, $ntext ) { global $wgExternalDiffEngine, $wgContLang; wfProfileIn( __METHOD__ ); @@ -704,8 +761,6 @@ class DifferenceEngine extends ContextSource { $otext = str_replace( "\r\n", "\n", $otext ); $ntext = str_replace( "\r\n", "\n", $ntext ); - $this->initDiffEngines(); - if ( $wgExternalDiffEngine == 'wikidiff' && function_exists( 'wikidiff_do_diff' ) ) { # For historical reasons, external diff engine expects # input text to be HTML-escaped already @@ -800,11 +855,12 @@ class DifferenceEngine extends ContextSource { } function localiseLineNumbersCb( $matches ) { - if ( $matches[1] === '1' && $this->mReducedLineNumbers ) return ''; + if ( $matches[1] === '1' && $this->mReducedLineNumbers ) { + return ''; + } return $this->msg( 'lineno' )->numParams( $matches[1] )->escaped(); } - /** * If there are revisions between the ones being compared, return a note saying so. * @return string @@ -855,11 +911,11 @@ class DifferenceEngine extends ContextSource { * Get a header for a specified revision. * * @param $rev Revision - * @param $complete String: 'complete' to get the header wrapped depending + * @param string $complete 'complete' to get the header wrapped depending * 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(); @@ -932,11 +988,13 @@ class DifferenceEngine extends ContextSource { $colspan = 1; $multiColspan = 2; } - $header .= " - <tr style='vertical-align: top;'> - <td colspan='$colspan' class='diff-otitle'>{$otitle}</td> - <td colspan='$colspan' class='diff-ntitle'>{$ntitle}</td> - </tr>"; + if ( $otitle || $ntitle ) { + $header .= " + <tr style='vertical-align: top;'> + <td colspan='$colspan' class='diff-otitle'>{$otitle}</td> + <td colspan='$colspan' class='diff-ntitle'>{$ntitle}</td> + </tr>"; + } } if ( $multi != '' ) { @@ -951,10 +1009,25 @@ class DifferenceEngine extends ContextSource { /** * Use specified text instead of loading from the database + * @deprecated since 1.21, use setContent() instead. */ function setText( $oldText, $newText ) { - $this->mOldtext = $oldText; - $this->mNewtext = $newText; + ContentHandler::deprecated( __METHOD__, "1.21" ); + + $oldContent = ContentHandler::makeContent( $oldText, $this->getTitle() ); + $newContent = ContentHandler::makeContent( $newText, $this->getTitle() ); + + $this->setContent( $oldContent, $newContent ); + } + + /** + * Use specified text instead of loading from the database + * @since 1.21 + */ + function setContent( Content $oldContent, Content $newContent ) { + $this->mOldContent = $oldContent; + $this->mNewContent = $newContent; + $this->mTextLoaded = 2; $this->mRevisionsLoaded = true; } @@ -1062,6 +1135,25 @@ class DifferenceEngine extends ContextSource { $this->mOldPage = $this->mOldRev->getTitle(); } + // Load tags information for both revisions + $dbr = wfGetDB( DB_SLAVE ); + if ( $this->mOldid !== false ) { + $this->mOldTags = $dbr->selectField( + 'tag_summary', + 'ts_tags', + array( 'ts_rev_id' => $this->mOldid ), + __METHOD__ + ); + } else { + $this->mOldTags = false; + } + $this->mNewTags = $dbr->selectField( + 'tag_summary', + 'ts_tags', + array( 'ts_rev_id' => $this->mNewid ), + __METHOD__ + ); + return true; } @@ -1073,26 +1165,29 @@ class DifferenceEngine extends ContextSource { function loadText() { if ( $this->mTextLoaded == 2 ) { return true; - } else { - // Whether it succeeds or fails, we don't want to try again - $this->mTextLoaded = 2; } + // Whether it succeeds or fails, we don't want to try again + $this->mTextLoaded = 2; + if ( !$this->loadRevisionData() ) { return false; } + if ( $this->mOldRev ) { - $this->mOldtext = $this->mOldRev->getText( Revision::FOR_THIS_USER ); - if ( $this->mOldtext === false ) { + $this->mOldContent = $this->mOldRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ); + if ( $this->mOldContent === null ) { return false; } } + if ( $this->mNewRev ) { - $this->mNewtext = $this->mNewRev->getText( Revision::FOR_THIS_USER ); - if ( $this->mNewtext === false ) { + $this->mNewContent = $this->mNewRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ); + if ( $this->mNewContent === null ) { return false; } } + return true; } @@ -1104,13 +1199,16 @@ class DifferenceEngine extends ContextSource { function loadNewText() { if ( $this->mTextLoaded >= 1 ) { return true; - } else { - $this->mTextLoaded = 1; } + + $this->mTextLoaded = 1; + if ( !$this->loadRevisionData() ) { return false; } - $this->mNewtext = $this->mNewRev->getText( Revision::FOR_THIS_USER ); + + $this->mNewContent = $this->mNewRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ); + return true; } } diff --git a/includes/diff/WikiDiff3.php b/includes/diff/WikiDiff3.php index 66727445..ea6f6e5d 100644 --- a/includes/diff/WikiDiff3.php +++ b/includes/diff/WikiDiff3.php @@ -29,7 +29,7 @@ * (http://citeseer.ist.psu.edu/myers86ond.html) with range compression (see Wu et al.'s * "An O(NP) Sequence Comparison Algorithm"). * - * This implementation supports an upper bound on the excution time. + * This implementation supports an upper bound on the execution time. * * Complexity: O((M + N)D) worst case time, O(M + N + D^2) expected time, O(M + N) space * @@ -64,7 +64,7 @@ class WikiDiff3 { public function diff( /*array*/ $from, /*array*/ $to ) { // remember initial lengths - $m = sizeof( $from ); + $m = count( $from ); $n = count( $to ); $this->heuristicUsed = false; @@ -490,7 +490,6 @@ class WikiDiff3 { $temp = array( 0, 0, 0 ); - $max_progress = array_fill( 0, ceil( max( $forward_end_diag - $forward_start_diag, $backward_end_diag - $backward_start_diag ) / 2 ), $temp ); $num_progress = 0; // the 1st entry is current, it is initialized |