2005-12-21 01:08:25 +00:00
|
|
|
<?php
|
|
|
|
if ( ! defined( 'MEDIAWIKI' ) )
|
2006-01-27 10:14:45 +00:00
|
|
|
die();
|
2005-12-21 01:08:25 +00:00
|
|
|
/**#@+
|
2005-12-25 19:39:22 +00:00
|
|
|
* A parser extension that adds two tags, <ref> and <references> for adding
|
|
|
|
* citations to pages
|
|
|
|
*
|
2007-01-20 15:10:35 +00:00
|
|
|
* @addtogroup Extensions
|
2005-12-21 01:08:25 +00:00
|
|
|
*
|
2005-12-25 19:39:22 +00:00
|
|
|
* @link http://meta.wikimedia.org/wiki/Cite/Cite.php Documentation
|
2006-01-07 09:24:48 +00:00
|
|
|
* @link http://www.w3.org/TR/html4/struct/text.html#edef-CITE <cite> definition in HTML
|
|
|
|
* @link http://www.w3.org/TR/2005/WD-xhtml2-20050527/mod-text.html#edef_text_cite <cite> definition in XHTML 2.0
|
2005-12-25 19:39:22 +00:00
|
|
|
*
|
2006-01-12 15:14:46 +00:00
|
|
|
* @bug 4579
|
|
|
|
*
|
2005-12-21 01:08:25 +00:00
|
|
|
* @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
|
|
|
|
* @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason
|
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
|
|
|
|
*/
|
|
|
|
|
|
|
|
$wgExtensionFunctions[] = 'wfCite';
|
|
|
|
$wgExtensionCredits['parserhook'][] = array(
|
|
|
|
'name' => 'Cite',
|
|
|
|
'author' => 'Ævar Arnfjörð Bjarmason',
|
2007-01-13 14:32:58 +00:00
|
|
|
'description' => 'Adds <nowiki><ref[ name=id]></nowiki> and <nowiki><references/></nowiki> tags, for citations',
|
2007-07-04 17:53:24 +00:00
|
|
|
'url' => 'http://www.mediawiki.org/wiki/Extension:Cite/Cite.php'
|
2005-12-21 01:08:25 +00:00
|
|
|
);
|
2006-11-11 14:36:47 +00:00
|
|
|
$wgParserTestFiles[] = dirname( __FILE__ ) . "/citeParserTests.txt";
|
2005-12-21 01:08:25 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Error codes, first array = internal errors; second array = user errors
|
|
|
|
*/
|
2005-12-23 02:34:39 +00:00
|
|
|
$wgCiteErrors = array(
|
2005-12-21 01:08:25 +00:00
|
|
|
'system' => array(
|
|
|
|
'CITE_ERROR_STR_INVALID',
|
|
|
|
'CITE_ERROR_KEY_INVALID_1',
|
|
|
|
'CITE_ERROR_KEY_INVALID_2',
|
|
|
|
'CITE_ERROR_STACK_INVALID_INPUT'
|
|
|
|
),
|
|
|
|
'user' => array(
|
|
|
|
'CITE_ERROR_REF_NUMERIC_KEY',
|
|
|
|
'CITE_ERROR_REF_NO_KEY',
|
|
|
|
'CITE_ERROR_REF_TOO_MANY_KEYS',
|
|
|
|
'CITE_ERROR_REF_NO_INPUT',
|
|
|
|
'CITE_ERROR_REFERENCES_INVALID_INPUT',
|
2005-12-29 21:56:00 +00:00
|
|
|
'CITE_ERROR_REFERENCES_INVALID_PARAMETERS',
|
2007-09-23 23:38:12 +00:00
|
|
|
'CITE_ERROR_REFERENCES_NO_BACKLINK_LABEL',
|
|
|
|
'CITE_ERROR_REFERENCES_NO_TEXT'
|
2005-12-21 01:08:25 +00:00
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2005-12-23 02:34:39 +00:00
|
|
|
for ( $i = 0; $i < count( $wgCiteErrors['system'] ); ++$i )
|
2005-12-21 01:08:25 +00:00
|
|
|
// System errors are negative integers
|
2005-12-23 02:34:39 +00:00
|
|
|
define( $wgCiteErrors['system'][$i], -($i + 1) );
|
|
|
|
for ( $i = 0; $i < count( $wgCiteErrors['user'] ); ++$i )
|
2005-12-21 01:08:25 +00:00
|
|
|
// User errors are positive integers
|
2005-12-23 02:34:39 +00:00
|
|
|
define( $wgCiteErrors['user'][$i], $i + 1 );
|
2005-12-21 01:08:25 +00:00
|
|
|
|
2006-07-15 15:17:32 +00:00
|
|
|
# Internationalisation file
|
2007-02-09 05:55:23 +00:00
|
|
|
require_once( dirname(__FILE__) . '/Cite.i18n.php' );
|
2006-01-27 10:14:45 +00:00
|
|
|
|
2006-07-15 14:00:29 +00:00
|
|
|
function wfCite() {
|
|
|
|
# Add messages
|
2006-07-16 21:43:23 +00:00
|
|
|
global $wgMessageCache, $wgCiteMessages;
|
|
|
|
foreach( $wgCiteMessages as $key => $value ) {
|
|
|
|
$wgMessageCache->addMessages( $wgCiteMessages[$key], $key );
|
|
|
|
}
|
2006-01-27 10:14:45 +00:00
|
|
|
|
2005-12-21 01:08:25 +00:00
|
|
|
class Cite {
|
2005-12-23 02:34:39 +00:00
|
|
|
/**#@+
|
|
|
|
* @access private
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Datastructure representing <ref> input, in the format of:
|
|
|
|
* <code>
|
|
|
|
* array(
|
|
|
|
* 'user supplied' => array(
|
|
|
|
* 'text' => 'user supplied reference & key',
|
|
|
|
* 'count' => 1, // occurs twice
|
2005-12-29 21:56:00 +00:00
|
|
|
* 'number' => 1, // The first reference, we want
|
|
|
|
* // all occourances of it to
|
|
|
|
* // use the same number
|
2005-12-23 02:34:39 +00:00
|
|
|
* ),
|
|
|
|
* 0 => 'Anonymous reference',
|
|
|
|
* 1 => 'Another anonymous reference',
|
|
|
|
* 'some key' => array(
|
|
|
|
* 'text' => 'this one occurs once'
|
2005-12-29 21:56:00 +00:00
|
|
|
* 'count' => 0,
|
|
|
|
* 'number' => 4
|
2005-12-23 02:34:39 +00:00
|
|
|
* ),
|
|
|
|
* 3 => 'more stuff'
|
|
|
|
* );
|
|
|
|
* </code>
|
|
|
|
*
|
|
|
|
* This works because:
|
|
|
|
* * PHP's datastructures are guarenteed to be returned in the
|
|
|
|
* order that things are inserted into them (unless you mess
|
|
|
|
* with that)
|
|
|
|
* * User supplied keys can't be integers, therefore avoiding
|
|
|
|
* conflict with anonymous keys
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
**/
|
2005-12-21 01:08:25 +00:00
|
|
|
var $mRefs = array();
|
2005-12-23 02:34:39 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Count for user displayed output (ref[1], ref[2], ...)
|
|
|
|
*
|
|
|
|
* @var int
|
|
|
|
*/
|
|
|
|
var $mOutCnt = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal counter for anonymous references, seperate from
|
|
|
|
* $mOutCnt because anonymous references won't increment it,
|
|
|
|
* but will incremement $mOutCnt
|
|
|
|
*
|
|
|
|
* @var int
|
|
|
|
*/
|
|
|
|
var $mInCnt = 0;
|
2005-12-29 21:56:00 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The backlinks, in order, to pass as $3 to
|
|
|
|
* 'cite_references_link_many_format', defined in
|
|
|
|
* 'cite_references_link_many_format_backlink_labels
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
var $mBacklinkLabels;
|
2005-12-23 02:34:39 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var object
|
|
|
|
*/
|
2006-02-21 19:56:09 +00:00
|
|
|
var $mParser;
|
2006-01-27 10:14:45 +00:00
|
|
|
|
2006-04-16 06:22:42 +00:00
|
|
|
/**
|
|
|
|
* True when a <ref> or <references> tag is being processed.
|
|
|
|
* Used to avoid infinite recursion
|
|
|
|
*
|
|
|
|
* @var boolean
|
|
|
|
*/
|
|
|
|
var $mInCite = false;
|
|
|
|
|
2005-12-21 01:08:25 +00:00
|
|
|
/**#@-*/
|
|
|
|
|
2005-12-23 02:34:39 +00:00
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*/
|
2005-12-21 01:08:25 +00:00
|
|
|
function Cite() {
|
|
|
|
$this->setHooks();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**#@+ @access private */
|
|
|
|
|
2005-12-23 02:34:39 +00:00
|
|
|
/**
|
|
|
|
* Callback function for <ref>
|
|
|
|
*
|
|
|
|
* @param string $str Input
|
|
|
|
* @param array $argv Arguments
|
|
|
|
* @return string
|
|
|
|
*/
|
2006-02-21 19:56:09 +00:00
|
|
|
function ref( $str, $argv, $parser ) {
|
2006-04-16 06:22:42 +00:00
|
|
|
if ( $this->mInCite ) {
|
|
|
|
return htmlspecialchars( "<ref>$str</ref>" );
|
|
|
|
} else {
|
|
|
|
$this->mInCite = true;
|
|
|
|
$ret = $this->guardedRef( $str, $argv, $parser );
|
|
|
|
$this->mInCite = false;
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function guardedRef( $str, $argv, $parser ) {
|
2006-02-21 19:56:09 +00:00
|
|
|
$this->mParser = $parser;
|
2005-12-21 01:08:25 +00:00
|
|
|
$key = $this->refArg( $argv );
|
|
|
|
|
|
|
|
if ( $str !== null ) {
|
|
|
|
if ( $str === '' )
|
|
|
|
return $this->error( CITE_ERROR_REF_NO_INPUT );
|
|
|
|
if ( is_string( $key ) )
|
2005-12-23 02:34:39 +00:00
|
|
|
// I don't want keys in the form of /^[0-9]+$/ because they would
|
|
|
|
// conflict with the php datastructure I'm using, besides, why specify
|
|
|
|
// a manual key if it's just going to be any old integer?
|
2006-01-27 10:14:45 +00:00
|
|
|
if ( sprintf( '%d', $key ) === (string)$key )
|
2005-12-21 01:08:25 +00:00
|
|
|
return $this->error( CITE_ERROR_REF_NUMERIC_KEY );
|
|
|
|
else
|
|
|
|
return $this->stack( $str, $key );
|
|
|
|
else if ( $key === null )
|
|
|
|
return $this->stack( $str );
|
|
|
|
else if ( $key === false )
|
|
|
|
return $this->error( CITE_ERROR_REF_TOO_MANY_KEYS );
|
|
|
|
else
|
|
|
|
$this->croak( CITE_ERROR_KEY_INVALID_1, serialize( $key ) );
|
|
|
|
} else if ( $str === null ) {
|
|
|
|
if ( is_string( $key ) )
|
2006-01-27 10:14:45 +00:00
|
|
|
if ( sprintf( '%d', $key ) === (string)$key )
|
2005-12-21 01:08:25 +00:00
|
|
|
return $this->error( CITE_ERROR_REF_NUMERIC_KEY );
|
|
|
|
else
|
|
|
|
return $this->stack( $str, $key );
|
|
|
|
else if ( $key === false )
|
|
|
|
return $this->error( CITE_ERROR_REF_TOO_MANY_KEYS );
|
|
|
|
else if ( $key === null )
|
|
|
|
return $this->error( CITE_ERROR_REF_NO_KEY );
|
|
|
|
else
|
|
|
|
$this->croak( CITE_ERROR_KEY_INVALID_2, serialize( $key ) );
|
|
|
|
|
|
|
|
} else
|
|
|
|
$this->croak( CITE_ERROR_STR_INVALID, serialize( $str ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse the arguments to the <ref> tag
|
|
|
|
*
|
2006-01-07 09:24:48 +00:00
|
|
|
* @static
|
2005-12-21 01:08:25 +00:00
|
|
|
*
|
2006-01-07 09:24:48 +00:00
|
|
|
* @param array $argv The argument vector
|
2005-12-21 01:08:25 +00:00
|
|
|
* @return mixed false on invalid input, a string on valid
|
|
|
|
* input and null on no input
|
|
|
|
*/
|
|
|
|
function refArg( $argv ) {
|
2005-12-24 18:03:21 +00:00
|
|
|
|
|
|
|
$cnt = count( $argv );
|
|
|
|
|
|
|
|
if ( $cnt > 1 )
|
2005-12-21 01:08:25 +00:00
|
|
|
// There should only be one key
|
|
|
|
return false;
|
2005-12-24 18:03:21 +00:00
|
|
|
else if ( $cnt == 1 )
|
|
|
|
if ( isset( $argv['name'] ) )
|
|
|
|
// Key given.
|
2006-05-26 11:54:38 +00:00
|
|
|
return $this->validateName( array_shift( $argv ) );
|
2005-12-24 18:03:21 +00:00
|
|
|
else
|
|
|
|
// Invalid key
|
|
|
|
return false;
|
2005-12-21 01:08:25 +00:00
|
|
|
else
|
|
|
|
// No key
|
|
|
|
return null;
|
|
|
|
}
|
2006-05-26 11:54:38 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Since the key name is used in an XHTML id attribute, it must
|
|
|
|
* conform to the validity rules. The restriction to begin with
|
|
|
|
* a letter is lifted since references have their own prefix.
|
|
|
|
*
|
|
|
|
* @fixme merge this code with the various section name transformations
|
|
|
|
* @fixme double-check for complete validity
|
|
|
|
* @return string if valid, false if invalid
|
|
|
|
*/
|
|
|
|
function validateName( $name ) {
|
|
|
|
if( preg_match( '/^[A-Za-z0-9:_.-]*$/i', $name ) ) {
|
|
|
|
return $name;
|
|
|
|
} else {
|
|
|
|
// WARNING: CRAPPY CUT AND PASTE MAKES BABY JESUS CRY
|
|
|
|
$text = urlencode( str_replace( ' ', '_', $name ) );
|
|
|
|
$replacearray = array(
|
|
|
|
'%3A' => ':',
|
|
|
|
'%' => '.'
|
|
|
|
);
|
|
|
|
return str_replace(
|
|
|
|
array_keys( $replacearray ),
|
|
|
|
array_values( $replacearray ),
|
|
|
|
$text );
|
|
|
|
}
|
|
|
|
}
|
2005-12-21 01:08:25 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Populate $this->mRefs based on input and arguments to <ref>
|
|
|
|
*
|
|
|
|
* @param string $str Input from the <ref> tag
|
|
|
|
* @param mixed $key Argument to the <ref> tag as returned by $this->refArg()
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function stack( $str, $key = null ) {
|
|
|
|
if ( $key === null ) {
|
|
|
|
// No key
|
|
|
|
$this->mRefs[] = $str;
|
2005-12-23 02:34:39 +00:00
|
|
|
return $this->linkRef( $this->mInCnt++ );
|
2005-12-21 01:08:25 +00:00
|
|
|
} else if ( is_string( $key ) )
|
|
|
|
// Valid key
|
2006-11-29 13:06:21 +00:00
|
|
|
if ( ! isset( $this->mRefs[$key] ) || ! is_array( $this->mRefs[$key] ) ) {
|
2005-12-21 01:08:25 +00:00
|
|
|
// First occourance
|
|
|
|
$this->mRefs[$key] = array(
|
|
|
|
'text' => $str,
|
2005-12-29 21:56:00 +00:00
|
|
|
'count' => 0,
|
|
|
|
'number' => ++$this->mOutCnt
|
2005-12-21 01:08:25 +00:00
|
|
|
);
|
2005-12-29 21:56:00 +00:00
|
|
|
return
|
|
|
|
$this->linkRef(
|
|
|
|
$key,
|
|
|
|
$this->mRefs[$key]['count'],
|
|
|
|
$this->mRefs[$key]['number']
|
|
|
|
);
|
2006-11-03 14:08:35 +00:00
|
|
|
} else {
|
2005-12-21 01:08:25 +00:00
|
|
|
// We've been here before
|
2006-11-03 15:34:46 +00:00
|
|
|
if ( $this->mRefs[$key]['text'] === null && $str !== '' ) {
|
2006-11-03 14:08:35 +00:00
|
|
|
// If no text found before, use this text
|
|
|
|
$this->mRefs[$key]['text'] = $str;
|
|
|
|
};
|
2005-12-29 21:56:00 +00:00
|
|
|
return
|
|
|
|
$this->linkRef(
|
|
|
|
$key,
|
|
|
|
++$this->mRefs[$key]['count'],
|
|
|
|
$this->mRefs[$key]['number']
|
2006-11-03 14:08:35 +00:00
|
|
|
); }
|
2005-12-21 01:08:25 +00:00
|
|
|
else
|
|
|
|
$this->croak( CITE_ERROR_STACK_INVALID_INPUT, serialize( array( $key, $str ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-12-23 02:34:39 +00:00
|
|
|
* Callback function for <references>
|
|
|
|
*
|
|
|
|
* @param string $str Input
|
|
|
|
* @param array $argv Arguments
|
2005-12-21 01:08:25 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
2006-02-21 19:56:09 +00:00
|
|
|
function references( $str, $argv, $parser ) {
|
2006-04-16 06:22:42 +00:00
|
|
|
if ( $this->mInCite ) {
|
|
|
|
if ( is_null( $str ) ) {
|
|
|
|
return htmlspecialchars( "<references/>" );
|
|
|
|
} else {
|
|
|
|
return htmlspecialchars( "<references>$str</references>" );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$this->mInCite = true;
|
|
|
|
$ret = $this->guardedReferences( $str, $argv, $parser );
|
|
|
|
$this->mInCite = false;
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function guardedReferences( $str, $argv, $parser ) {
|
2006-02-21 19:56:09 +00:00
|
|
|
$this->mParser = $parser;
|
2005-12-21 01:08:25 +00:00
|
|
|
if ( $str !== null )
|
|
|
|
return $this->error( CITE_ERROR_REFERENCES_INVALID_INPUT );
|
|
|
|
else if ( count( $argv ) )
|
|
|
|
return $this->error( CITE_ERROR_REFERENCES_INVALID_PARAMETERS );
|
|
|
|
else
|
|
|
|
return $this->referencesFormat();
|
|
|
|
}
|
|
|
|
|
2005-12-23 02:34:39 +00:00
|
|
|
/**
|
|
|
|
* Make output to be returned from the references() function
|
|
|
|
*
|
|
|
|
* @return string XHTML ready for output
|
|
|
|
*/
|
2005-12-21 01:08:25 +00:00
|
|
|
function referencesFormat() {
|
2007-05-08 21:20:48 +00:00
|
|
|
if ( count( $this->mRefs ) == 0 )
|
|
|
|
return '';
|
2007-01-13 22:04:57 +00:00
|
|
|
|
2007-05-08 21:20:48 +00:00
|
|
|
$ent = array();
|
2007-01-13 22:04:57 +00:00
|
|
|
foreach ( $this->mRefs as $k => $v )
|
2005-12-21 01:08:25 +00:00
|
|
|
$ent[] = $this->referencesFormatEntry( $k, $v );
|
|
|
|
|
|
|
|
$prefix = wfMsgForContentNoTrans( 'cite_references_prefix' );
|
|
|
|
$suffix = wfMsgForContentNoTrans( 'cite_references_suffix' );
|
|
|
|
$content = implode( "\n", $ent );
|
|
|
|
|
2006-04-02 03:43:47 +00:00
|
|
|
// Live hack: parse() adds two newlines on WM, can't reproduce it locally -ævar
|
2007-01-13 22:04:57 +00:00
|
|
|
return rtrim( $this->parse( $prefix . $content . $suffix ), "\n" );
|
2005-12-21 01:08:25 +00:00
|
|
|
}
|
|
|
|
|
2005-12-23 02:34:39 +00:00
|
|
|
/**
|
|
|
|
* Format a single entry for the referencesFormat() function
|
|
|
|
*
|
|
|
|
* @param string $key The key of the reference
|
|
|
|
* @param mixed $val The value of the reference, string for anonymous
|
2007-01-13 22:04:57 +00:00
|
|
|
* references, array for user-suppplied
|
2005-12-23 02:34:39 +00:00
|
|
|
* @return string Wikitext
|
|
|
|
*/
|
2005-12-21 01:08:25 +00:00
|
|
|
function referencesFormatEntry( $key, $val ) {
|
2006-02-23 21:24:57 +00:00
|
|
|
// Anonymous reference
|
2005-12-21 01:08:25 +00:00
|
|
|
if ( ! is_array( $val ) )
|
|
|
|
return
|
|
|
|
wfMsgForContentNoTrans(
|
|
|
|
'cite_references_link_one',
|
2005-12-23 02:34:39 +00:00
|
|
|
$this->referencesKey( $key ),
|
|
|
|
$this->refKey( $key ),
|
2005-12-21 01:08:25 +00:00
|
|
|
$val
|
|
|
|
);
|
2007-09-23 23:38:12 +00:00
|
|
|
else if ($val['text']=='') return
|
|
|
|
wfMsgForContentNoTrans(
|
|
|
|
'cite_references_link_one',
|
|
|
|
$this->referencesKey( $key ),
|
|
|
|
$this->refKey( $key, $val['count'] ),
|
|
|
|
$this->error(CITE_ERROR_REFERENCES_NO_TEXT)
|
|
|
|
);
|
2006-02-23 21:24:57 +00:00
|
|
|
// Standalone named reference, I want to format this like an
|
|
|
|
// anonymous reference because displaying "1. 1.1 Ref text" is
|
|
|
|
// overkill and users frequently use named references when they
|
|
|
|
// don't need them for convenience
|
|
|
|
else if ( $val['count'] === 0 )
|
|
|
|
return
|
|
|
|
wfMsgForContentNoTrans(
|
|
|
|
'cite_references_link_one',
|
|
|
|
$this->referencesKey( $key ),
|
|
|
|
$this->refKey( $key, $val['count'] ),
|
2007-10-02 21:54:43 +00:00
|
|
|
($val['text']!=''?$val['text']:$this->error(CITE_ERROR_REFERENCES_NO_TEXT))
|
2006-02-23 21:24:57 +00:00
|
|
|
);
|
|
|
|
// Named references with >1 occurrences
|
2005-12-21 01:08:25 +00:00
|
|
|
else {
|
|
|
|
$links = array();
|
|
|
|
|
|
|
|
for ( $i = 0; $i <= $val['count']; ++$i ) {
|
|
|
|
$links[] = wfMsgForContentNoTrans(
|
|
|
|
'cite_references_link_many_format',
|
2005-12-23 02:34:39 +00:00
|
|
|
$this->refKey( $key, $i ),
|
2006-05-02 17:02:23 +00:00
|
|
|
$this->referencesFormatEntryNumericBacklinkLabel( $val['number'], $i, $val['count'] ),
|
2005-12-29 21:56:00 +00:00
|
|
|
$this->referencesFormatEntryAlternateBacklinkLabel( $i )
|
2005-12-21 01:08:25 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$list = $this->listToText( $links );
|
|
|
|
|
|
|
|
return
|
|
|
|
wfMsgForContentNoTrans( 'cite_references_link_many',
|
2005-12-23 02:34:39 +00:00
|
|
|
$this->referencesKey( $key ),
|
2005-12-21 01:08:25 +00:00
|
|
|
$list,
|
2007-10-02 21:54:43 +00:00
|
|
|
($val['text']!=''?$val['text']:$this->error(CITE_ERROR_REFERENCES_NO_TEXT))
|
2005-12-21 01:08:25 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-29 21:56:00 +00:00
|
|
|
/**
|
|
|
|
* Generate a numeric backlink given a base number and an
|
|
|
|
* offset, e.g. $base = 1, $offset = 2; = 1.2
|
2006-05-02 17:02:23 +00:00
|
|
|
* Since bug #5525, it correctly does 1.9 -> 1.10 as well as 1.099 -> 1.100
|
2005-12-29 21:56:00 +00:00
|
|
|
*
|
2006-01-07 09:24:48 +00:00
|
|
|
* @static
|
|
|
|
*
|
2005-12-29 21:56:00 +00:00
|
|
|
* @param int $base The base
|
|
|
|
* @param int $offset The offset
|
2006-05-02 17:02:23 +00:00
|
|
|
* @param int $max Maximum value expected.
|
2005-12-29 21:56:00 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
2006-05-02 17:02:23 +00:00
|
|
|
function referencesFormatEntryNumericBacklinkLabel( $base, $offset, $max ) {
|
2005-12-29 21:56:00 +00:00
|
|
|
global $wgContLang;
|
2006-05-02 17:02:23 +00:00
|
|
|
$scope = strlen( $max );
|
|
|
|
$ret = $wgContLang->formatNum(
|
|
|
|
sprintf("%s.%0{$scope}s", $base, $offset)
|
|
|
|
);
|
|
|
|
return $ret;
|
2005-12-29 21:56:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate a custom format backlink given an offset, e.g.
|
|
|
|
* $offset = 2; = c if $this->mBacklinkLabels = array( 'a',
|
|
|
|
* 'b', 'c', ...). Return an error if the offset > the # of
|
|
|
|
* array items
|
|
|
|
*
|
|
|
|
* @param int $offset The offset
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function referencesFormatEntryAlternateBacklinkLabel( $offset ) {
|
2006-07-02 14:19:45 +00:00
|
|
|
if ( !isset( $this->mBacklinkLabels ) ) {
|
|
|
|
$this->genBacklinkLabels();
|
|
|
|
}
|
|
|
|
if ( isset( $this->mBacklinkLabels[$offset] ) ) {
|
2005-12-29 21:56:00 +00:00
|
|
|
return $this->mBacklinkLabels[$offset];
|
2006-07-02 14:19:45 +00:00
|
|
|
} else {
|
2005-12-29 21:56:00 +00:00
|
|
|
// Feed me!
|
|
|
|
return $this->error( CITE_ERROR_REFERENCES_NO_BACKLINK_LABEL );
|
2006-07-02 14:19:45 +00:00
|
|
|
}
|
2005-12-29 21:56:00 +00:00
|
|
|
}
|
|
|
|
|
2005-12-23 02:34:39 +00:00
|
|
|
/**
|
|
|
|
* Return an id for use in wikitext output based on a key and
|
|
|
|
* optionally the # of it, used in <references>, not <ref>
|
|
|
|
* (since otherwise it would link to itself)
|
|
|
|
*
|
2006-01-07 09:24:48 +00:00
|
|
|
* @static
|
|
|
|
*
|
2005-12-23 02:34:39 +00:00
|
|
|
* @param string $key The key
|
|
|
|
* @param int $num The number of the key
|
|
|
|
* @return string A key for use in wikitext
|
|
|
|
*/
|
|
|
|
function refKey( $key, $num = null ) {
|
|
|
|
$prefix = wfMsgForContent( 'cite_reference_link_prefix' );
|
|
|
|
$suffix = wfMsgForContent( 'cite_reference_link_suffix' );
|
|
|
|
if ( isset( $num ) )
|
|
|
|
$key = wfMsgForContentNoTrans( 'cite_reference_link_key_with_num', $key, $num );
|
|
|
|
|
|
|
|
return $prefix . $key . $suffix;
|
|
|
|
}
|
2005-12-21 01:08:25 +00:00
|
|
|
|
2005-12-23 02:34:39 +00:00
|
|
|
/**
|
|
|
|
* Return an id for use in wikitext output based on a key and
|
2005-12-23 05:28:39 +00:00
|
|
|
* optionally the # of it, used in <ref>, not <references>
|
2005-12-23 02:34:39 +00:00
|
|
|
* (since otherwise it would link to itself)
|
|
|
|
*
|
2006-01-07 09:24:48 +00:00
|
|
|
* @static
|
|
|
|
*
|
2005-12-23 02:34:39 +00:00
|
|
|
* @param string $key The key
|
|
|
|
* @param int $num The number of the key
|
|
|
|
* @return string A key for use in wikitext
|
|
|
|
*/
|
|
|
|
function referencesKey( $key, $num = null ) {
|
|
|
|
$prefix = wfMsgForContent( 'cite_references_link_prefix' );
|
|
|
|
$suffix = wfMsgForContent( 'cite_references_link_suffix' );
|
|
|
|
if ( isset( $num ) )
|
|
|
|
$key = wfMsgForContentNoTrans( 'cite_reference_link_key_with_num', $key, $num );
|
|
|
|
|
2005-12-21 01:08:25 +00:00
|
|
|
return $prefix . $key . $suffix;
|
|
|
|
}
|
|
|
|
|
2005-12-23 02:34:39 +00:00
|
|
|
/**
|
|
|
|
* Generate a link (<sup ...) for the <ref> element from a key
|
|
|
|
* and return XHTML ready for output
|
|
|
|
*
|
|
|
|
* @param string $key The key for the link
|
2005-12-29 21:56:00 +00:00
|
|
|
* @param int $count The # of the key, used for distinguishing
|
|
|
|
* multiple occourances of the same key
|
|
|
|
* @param int $label The label to use for the link, I want to
|
|
|
|
* use the same label for all occourances of
|
|
|
|
* the same named reference.
|
2005-12-23 02:34:39 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
2005-12-29 21:56:00 +00:00
|
|
|
function linkRef( $key, $count = null, $label = null ) {
|
2005-12-21 01:08:25 +00:00
|
|
|
global $wgContLang;
|
2005-12-29 21:56:00 +00:00
|
|
|
|
2005-12-21 01:08:25 +00:00
|
|
|
return
|
|
|
|
$this->parse(
|
|
|
|
wfMsgForContentNoTrans(
|
|
|
|
'cite_reference_link',
|
2005-12-29 21:56:00 +00:00
|
|
|
$this->refKey( $key, $count ),
|
2005-12-23 02:34:39 +00:00
|
|
|
$this->referencesKey( $key ),
|
2005-12-29 21:56:00 +00:00
|
|
|
$wgContLang->formatNum( is_null( $label ) ? ++$this->mOutCnt : $label )
|
2005-12-21 01:08:25 +00:00
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This does approximately the same thing as
|
|
|
|
* Langauge::listToText() but due to this being used for a
|
|
|
|
* slightly different purpose (people might not want , as the
|
|
|
|
* first seperator and not 'and' as the second, and this has to
|
|
|
|
* use messages from the content language) I'm rolling my own.
|
|
|
|
*
|
2006-01-07 09:24:48 +00:00
|
|
|
* @static
|
|
|
|
*
|
2005-12-23 02:34:39 +00:00
|
|
|
* @param array $arr The array to format
|
2005-12-21 01:08:25 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function listToText( $arr ) {
|
|
|
|
$cnt = count( $arr );
|
|
|
|
|
|
|
|
$sep = wfMsgForContentNoTrans( 'cite_references_link_many_sep' );
|
|
|
|
$and = wfMsgForContentNoTrans( 'cite_references_link_many_and' );
|
|
|
|
|
|
|
|
if ( $cnt == 1 )
|
2005-12-23 02:34:39 +00:00
|
|
|
// Enforce always returning a string
|
2005-12-21 01:08:25 +00:00
|
|
|
return (string)$arr[0];
|
|
|
|
else {
|
|
|
|
$t = array_slice( $arr, 0, $cnt - 1 );
|
2005-12-23 00:43:23 +00:00
|
|
|
return implode( $sep, $t ) . $and . $arr[$cnt - 1];
|
2005-12-21 01:08:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-23 02:34:39 +00:00
|
|
|
/**
|
|
|
|
* Parse a given fragment and fix up Tidy's trail of blood on
|
|
|
|
* it...
|
|
|
|
*
|
|
|
|
* @param string $in The text to parse
|
|
|
|
* @return string The parsed text
|
|
|
|
*/
|
2005-12-21 01:08:25 +00:00
|
|
|
function parse( $in ) {
|
2006-08-06 15:46:00 +00:00
|
|
|
if ( method_exists( $this->mParser, 'recursiveTagParse' ) ) {
|
|
|
|
// New fast method
|
|
|
|
return $this->mParser->recursiveTagParse( $in );
|
|
|
|
} else {
|
|
|
|
// Old method
|
|
|
|
$ret = $this->mParser->parse(
|
|
|
|
$in,
|
|
|
|
$this->mParser->mTitle,
|
|
|
|
$this->mParser->mOptions,
|
|
|
|
// Avoid whitespace buildup
|
|
|
|
false,
|
|
|
|
// Important, otherwise $this->clearState()
|
|
|
|
// would get run every time <ref> or
|
|
|
|
// <references> is called, fucking the whole
|
|
|
|
// thing up.
|
|
|
|
false
|
|
|
|
);
|
|
|
|
$text = $ret->getText();
|
|
|
|
|
|
|
|
return $this->fixTidy( $text );
|
|
|
|
}
|
2005-12-23 00:43:23 +00:00
|
|
|
}
|
|
|
|
|
2005-12-23 02:34:39 +00:00
|
|
|
/**
|
|
|
|
* Tidy treats all input as a block, it will e.g. wrap most
|
|
|
|
* input in <p> if it isn't already, fix that and return the fixed text
|
|
|
|
*
|
2006-01-07 09:24:48 +00:00
|
|
|
* @static
|
|
|
|
*
|
2005-12-23 02:34:39 +00:00
|
|
|
* @param string $text The text to fix
|
|
|
|
* @return string The fixed text
|
|
|
|
*/
|
2005-12-23 00:43:23 +00:00
|
|
|
function fixTidy( $text ) {
|
|
|
|
global $wgUseTidy;
|
|
|
|
|
|
|
|
if ( ! $wgUseTidy )
|
|
|
|
return $text;
|
|
|
|
else {
|
2006-01-07 09:24:48 +00:00
|
|
|
$text = preg_replace( '~^<p>\s*~', '', $text );
|
|
|
|
$text = preg_replace( '~\s*</p>\s*~', '', $text );
|
|
|
|
$text = preg_replace( '~\n$~', '', $text );
|
2005-12-23 00:43:23 +00:00
|
|
|
|
|
|
|
return $text;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-29 21:56:00 +00:00
|
|
|
/**
|
|
|
|
* Generate the labels to pass to the
|
|
|
|
* 'cite_references_link_many_format' message, the format is an
|
|
|
|
* arbitary number of tokens seperated by [\t\n ]
|
|
|
|
*/
|
|
|
|
function genBacklinkLabels() {
|
2006-07-02 14:19:45 +00:00
|
|
|
wfProfileIn( __METHOD__ );
|
2005-12-29 21:56:00 +00:00
|
|
|
$text = wfMsgForContentNoTrans( 'cite_references_link_many_format_backlink_labels' );
|
|
|
|
$this->mBacklinkLabels = preg_split( '#[\n\t ]#', $text );
|
2006-07-02 14:19:45 +00:00
|
|
|
wfProfileOut( __METHOD__ );
|
2005-12-29 21:56:00 +00:00
|
|
|
}
|
|
|
|
|
2005-12-23 06:06:57 +00:00
|
|
|
/**
|
|
|
|
* Gets run when Parser::clearState() gets run, since we don't
|
|
|
|
* want the counts to transcend pages and other instances
|
|
|
|
*/
|
|
|
|
function clearState() {
|
|
|
|
$this->mOutCnt = $this->mInCnt = 0;
|
|
|
|
$this->mRefs = array();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-12-21 01:08:25 +00:00
|
|
|
/**
|
|
|
|
* Initialize the parser hooks
|
|
|
|
*/
|
|
|
|
function setHooks() {
|
2005-12-23 06:06:57 +00:00
|
|
|
global $wgParser, $wgHooks;
|
2005-12-21 01:08:25 +00:00
|
|
|
|
|
|
|
$wgParser->setHook( 'ref' , array( &$this, 'ref' ) );
|
|
|
|
$wgParser->setHook( 'references' , array( &$this, 'references' ) );
|
2005-12-23 06:06:57 +00:00
|
|
|
|
|
|
|
$wgHooks['ParserClearState'][] = array( &$this, 'clearState' );
|
2005-12-21 01:08:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-12-23 02:34:39 +00:00
|
|
|
* Return an error message based on an error ID
|
|
|
|
*
|
2005-12-21 01:08:25 +00:00
|
|
|
* @param int $id ID for the error
|
2005-12-23 02:34:39 +00:00
|
|
|
* @return string XHTML ready for output
|
2005-12-21 01:08:25 +00:00
|
|
|
*/
|
|
|
|
function error( $id ) {
|
|
|
|
if ( $id > 0 )
|
|
|
|
// User errors are positive
|
2005-12-23 05:06:17 +00:00
|
|
|
return
|
|
|
|
$this->parse(
|
|
|
|
'<strong class="error">' .
|
2007-08-07 06:32:20 +00:00
|
|
|
wfMsg( 'cite_error', $id, wfMsg( "cite_error_$id" ) ) .
|
2005-12-23 05:06:17 +00:00
|
|
|
'</strong>'
|
|
|
|
);
|
2005-12-21 01:08:25 +00:00
|
|
|
else if ( $id < 0 )
|
2007-08-07 06:32:20 +00:00
|
|
|
return wfMsg( 'cite_error', $id );
|
2005-12-21 01:08:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Die with a backtrace if something happens in the code which
|
|
|
|
* shouldn't have
|
|
|
|
*
|
|
|
|
* @param int $error ID for the error
|
|
|
|
* @param string $data Serialized error data
|
|
|
|
*/
|
|
|
|
function croak( $error, $data ) {
|
|
|
|
wfDebugDieBacktrace( wfMsgForContent( 'cite_croak', $this->error( $error ), $data ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**#@-*/
|
|
|
|
}
|
|
|
|
|
2006-01-07 09:24:48 +00:00
|
|
|
new Cite;
|
2005-12-21 01:08:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**#@-*/
|
2007-06-29 01:36:09 +00:00
|
|
|
|