2008-06-06 20:38:04 +00:00
|
|
|
<?php
|
|
|
|
|
2016-09-21 11:01:25 +00:00
|
|
|
/**
|
2008-06-06 20:38:04 +00:00
|
|
|
* A parser extension that adds two tags, <ref> and <references> for adding
|
|
|
|
* citations to pages
|
|
|
|
*
|
2010-06-06 15:12:22 +00:00
|
|
|
* @ingroup Extensions
|
2008-06-06 20:38:04 +00:00
|
|
|
*
|
2016-09-21 11:01:25 +00:00
|
|
|
* Documentation
|
2018-10-30 12:08:46 +00:00
|
|
|
* @link https://www.mediawiki.org/wiki/Extension:Cite/Cite.php
|
2016-09-21 11:01:25 +00:00
|
|
|
*
|
|
|
|
* <cite> definition in HTML
|
|
|
|
* @link http://www.w3.org/TR/html4/struct/text.html#edef-CITE
|
|
|
|
*
|
|
|
|
* <cite> definition in XHTML 2.0
|
|
|
|
* @link http://www.w3.org/TR/2005/WD-xhtml2-20050527/mod-text.html#edef_text_cite
|
2008-06-06 20:38:04 +00:00
|
|
|
*
|
2016-09-29 14:19:16 +00:00
|
|
|
* @bug https://phabricator.wikimedia.org/T6579
|
2008-06-06 20:38:04 +00:00
|
|
|
*
|
|
|
|
* @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
|
|
|
|
* @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason
|
2017-12-29 12:12:35 +00:00
|
|
|
* @license GPL-2.0-or-later
|
2008-06-06 20:38:04 +00:00
|
|
|
*/
|
|
|
|
|
2019-11-19 14:12:11 +00:00
|
|
|
namespace Cite;
|
|
|
|
|
|
|
|
use Exception;
|
|
|
|
use Html;
|
2017-12-25 13:17:20 +00:00
|
|
|
use MediaWiki\MediaWikiServices;
|
2019-11-19 14:12:11 +00:00
|
|
|
use Parser;
|
|
|
|
use ParserOptions;
|
|
|
|
use Sanitizer;
|
2019-11-22 21:45:11 +00:00
|
|
|
use StatusValue;
|
2017-12-22 20:28:29 +00:00
|
|
|
|
2008-08-08 19:11:31 +00:00
|
|
|
class Cite {
|
2015-04-30 18:34:47 +00:00
|
|
|
|
2019-11-28 14:39:11 +00:00
|
|
|
public const DEFAULT_GROUP = '';
|
2015-04-30 18:34:47 +00:00
|
|
|
|
2019-10-24 09:23:44 +00:00
|
|
|
/**
|
|
|
|
* Wikitext attribute name for Book Referencing.
|
|
|
|
*/
|
2019-11-12 10:03:44 +00:00
|
|
|
public const BOOK_REF_ATTRIBUTE = 'extends';
|
2019-10-24 09:23:44 +00:00
|
|
|
|
2019-11-08 11:59:09 +00:00
|
|
|
/**
|
|
|
|
* Page property key for the Book Referencing `extends` attribute.
|
|
|
|
*/
|
|
|
|
public const BOOK_REF_PROPERTY = 'ref-extends';
|
|
|
|
|
2008-06-06 20:38:04 +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
|
|
|
|
*
|
2016-09-21 11:01:25 +00:00
|
|
|
* @var string[]
|
2008-06-06 20:38:04 +00:00
|
|
|
*/
|
2016-09-21 11:01:25 +00:00
|
|
|
private $mBacklinkLabels;
|
2010-05-22 14:28:48 +00:00
|
|
|
|
2008-06-06 20:38:04 +00:00
|
|
|
/**
|
2011-05-28 20:44:24 +00:00
|
|
|
* @var Parser
|
2008-06-06 20:38:04 +00:00
|
|
|
*/
|
2016-09-21 11:01:25 +00:00
|
|
|
private $mParser;
|
2011-02-22 00:07:21 +00:00
|
|
|
|
2019-11-22 22:17:23 +00:00
|
|
|
/**
|
|
|
|
* @var bool
|
|
|
|
*/
|
|
|
|
private $isPagePreview;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var bool
|
|
|
|
*/
|
|
|
|
private $isSectionPreview;
|
|
|
|
|
2019-11-28 14:39:11 +00:00
|
|
|
/**
|
|
|
|
* @var FootnoteMarkFormatter
|
|
|
|
*/
|
|
|
|
private $footnoteMarkFormatter;
|
|
|
|
|
2019-11-19 10:29:33 +00:00
|
|
|
/**
|
|
|
|
* @var CiteErrorReporter
|
|
|
|
*/
|
|
|
|
private $errorReporter;
|
|
|
|
|
2015-06-08 14:05:06 +00:00
|
|
|
/**
|
|
|
|
* True when the ParserAfterParse hook has been called.
|
|
|
|
* Used to avoid doing anything in ParserBeforeTidy.
|
|
|
|
*
|
2019-10-25 08:34:35 +00:00
|
|
|
* @var bool
|
2015-06-08 14:05:06 +00:00
|
|
|
*/
|
2016-09-21 11:01:25 +00:00
|
|
|
private $mHaveAfterParse = false;
|
2015-06-08 14:05:06 +00:00
|
|
|
|
2008-06-06 20:38:04 +00:00
|
|
|
/**
|
2009-07-26 22:15:13 +00:00
|
|
|
* True when a <ref> tag is being processed.
|
2008-06-06 20:38:04 +00:00
|
|
|
* Used to avoid infinite recursion
|
2011-02-22 00:07:21 +00:00
|
|
|
*
|
2019-10-25 08:34:35 +00:00
|
|
|
* @var bool
|
2008-06-06 20:38:04 +00:00
|
|
|
*/
|
2019-11-19 11:01:10 +00:00
|
|
|
private $mInCite = false;
|
2009-07-26 22:15:13 +00:00
|
|
|
|
|
|
|
/**
|
2019-11-19 13:34:19 +00:00
|
|
|
* @var null|string The current group name while parsing nested <ref> in <references>. Null when
|
|
|
|
* parsing <ref> outside of <references>. Warning, an empty string is a valid group name!
|
2009-07-26 22:15:13 +00:00
|
|
|
*/
|
2019-11-19 13:34:19 +00:00
|
|
|
private $inReferencesGroup = null;
|
2009-07-26 22:15:13 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Error stack used when defining refs in <references>
|
2011-02-22 00:07:21 +00:00
|
|
|
*
|
2016-09-21 11:01:25 +00:00
|
|
|
* @var string[]
|
2009-07-26 22:15:13 +00:00
|
|
|
*/
|
2016-09-21 11:01:25 +00:00
|
|
|
private $mReferencesErrors = [];
|
2009-07-26 22:15:13 +00:00
|
|
|
|
2015-06-08 14:05:06 +00:00
|
|
|
/**
|
2019-11-29 13:37:31 +00:00
|
|
|
* @var ReferenceStack
|
2015-06-08 14:05:06 +00:00
|
|
|
*/
|
2019-11-22 17:28:51 +00:00
|
|
|
private $referenceStack;
|
2015-06-08 14:05:06 +00:00
|
|
|
|
2019-11-28 14:35:23 +00:00
|
|
|
/**
|
|
|
|
* @var CiteKeyFormatter
|
|
|
|
*/
|
|
|
|
private $citeKeyFormatter;
|
|
|
|
|
2019-11-19 10:29:33 +00:00
|
|
|
/**
|
|
|
|
* @param Parser $parser
|
|
|
|
*/
|
|
|
|
private function rememberParser( Parser $parser ) {
|
|
|
|
if ( $parser !== $this->mParser ) {
|
|
|
|
$this->mParser = $parser;
|
2019-11-22 22:17:23 +00:00
|
|
|
$this->isPagePreview = $parser->getOptions()->getIsPreview();
|
|
|
|
$this->isSectionPreview = $parser->getOptions()->getIsSectionPreview();
|
2019-11-19 10:29:33 +00:00
|
|
|
$this->errorReporter = new CiteErrorReporter(
|
|
|
|
$parser->getOptions()->getUserLangObj(),
|
|
|
|
$parser
|
|
|
|
);
|
2019-11-22 17:28:51 +00:00
|
|
|
$this->referenceStack = new ReferenceStack( $this->errorReporter );
|
2019-11-28 14:35:23 +00:00
|
|
|
$this->citeKeyFormatter = new CiteKeyFormatter();
|
2019-11-28 14:39:11 +00:00
|
|
|
$this->footnoteMarkFormatter = new FootnoteMarkFormatter(
|
|
|
|
$this->mParser, $this->errorReporter, $this->citeKeyFormatter );
|
2019-11-19 10:29:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-06 20:38:04 +00:00
|
|
|
/**
|
2015-06-08 14:05:06 +00:00
|
|
|
* Callback function for <ref>
|
2008-06-06 20:38:04 +00:00
|
|
|
*
|
2019-11-05 09:28:20 +00:00
|
|
|
* @param string|null $text Raw content of the <ref> tag.
|
2015-10-26 14:44:02 +00:00
|
|
|
* @param string[] $argv Arguments
|
|
|
|
* @param Parser $parser
|
2011-05-28 20:44:24 +00:00
|
|
|
*
|
2019-11-12 12:06:39 +00:00
|
|
|
* @return string|false False in case a <ref> tag is not allowed in the current context
|
2008-06-06 20:38:04 +00:00
|
|
|
*/
|
2019-11-12 12:06:39 +00:00
|
|
|
public function ref( $text, array $argv, Parser $parser ) {
|
2015-06-08 14:05:06 +00:00
|
|
|
if ( $this->mInCite ) {
|
2019-11-12 12:06:39 +00:00
|
|
|
return false;
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
2014-10-01 14:25:58 +00:00
|
|
|
|
2019-11-19 10:29:33 +00:00
|
|
|
$this->rememberParser( $parser );
|
2014-10-01 14:25:58 +00:00
|
|
|
|
2019-11-19 10:29:33 +00:00
|
|
|
$this->mInCite = true;
|
2019-11-05 09:28:20 +00:00
|
|
|
$ret = $this->guardedRef( $text, $argv, $parser );
|
2014-10-01 14:25:58 +00:00
|
|
|
$this->mInCite = false;
|
|
|
|
|
2015-06-08 14:05:06 +00:00
|
|
|
return $ret;
|
2014-12-19 18:38:37 +00:00
|
|
|
}
|
|
|
|
|
2019-11-22 21:45:11 +00:00
|
|
|
/**
|
2019-11-25 15:07:58 +00:00
|
|
|
* @param string|null $text
|
|
|
|
* @param string|null $name
|
|
|
|
* @param string|null $group
|
|
|
|
* @param string|null $follow
|
|
|
|
* @param string|null $extends
|
2019-11-22 21:45:11 +00:00
|
|
|
* @return StatusValue
|
|
|
|
*/
|
2019-11-25 15:07:23 +00:00
|
|
|
private function validateRef( $text, $name, $group, $follow, $extends ) : StatusValue {
|
2019-11-26 09:11:57 +00:00
|
|
|
if ( ctype_digit( $name ) || ctype_digit( $follow ) || ctype_digit( $extends ) ) {
|
2019-11-26 09:06:15 +00:00
|
|
|
// Numeric names mess up the resulting id's, potentially producing
|
|
|
|
// duplicate id's in the XHTML. The Right Thing To Do
|
|
|
|
// would be to mangle them, but it's not really high-priority
|
|
|
|
// (and would produce weird id's anyway).
|
|
|
|
return StatusValue::newFatal( 'cite_error_ref_numeric_key' );
|
|
|
|
}
|
|
|
|
|
2019-11-25 15:31:56 +00:00
|
|
|
global $wgCiteBookReferencing;
|
|
|
|
// Temporary feature flag until mainstreamed. See T236255
|
|
|
|
if ( !$wgCiteBookReferencing && $extends ) {
|
|
|
|
return StatusValue::newFatal( 'cite_error_ref_too_many_keys' );
|
|
|
|
}
|
|
|
|
|
2019-11-25 15:38:35 +00:00
|
|
|
if ( $follow && ( $name || $extends ) ) {
|
|
|
|
// TODO: Introduce a specific error for this case.
|
|
|
|
return StatusValue::newFatal( 'cite_error_ref_too_many_keys' );
|
|
|
|
}
|
|
|
|
|
2019-11-22 21:45:11 +00:00
|
|
|
if ( $this->inReferencesGroup !== null ) {
|
2019-11-25 15:10:05 +00:00
|
|
|
// Inside a references tag. Note that we could have be deceived by `{{#tag`, so don't
|
|
|
|
// take any actions that we can't reverse later.
|
|
|
|
// FIXME: Some assertions make assumptions that rely on earlier tests not failing.
|
|
|
|
// These dependencies need to be explicit so they aren't accidentally broken by
|
|
|
|
// reordering in the future.
|
|
|
|
|
2019-11-22 21:45:11 +00:00
|
|
|
if ( $group !== $this->inReferencesGroup ) {
|
|
|
|
// <ref> and <references> have conflicting group attributes.
|
|
|
|
return StatusValue::newFatal( 'cite_error_references_group_mismatch',
|
|
|
|
Sanitizer::safeEncodeAttribute( $group ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !$name ) {
|
|
|
|
// <ref> calls inside <references> must be named
|
|
|
|
return StatusValue::newFatal( 'cite_error_references_no_key' );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( $text === '' ) {
|
|
|
|
// <ref> called in <references> has no content.
|
|
|
|
return StatusValue::newFatal(
|
|
|
|
'cite_error_empty_references_define',
|
|
|
|
Sanitizer::safeEncodeAttribute( $name )
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-11-26 10:35:47 +00:00
|
|
|
// Section previews are exempt from some rules.
|
|
|
|
if ( !$this->isSectionPreview ) {
|
|
|
|
if ( !$this->referenceStack->hasGroup( $group ) ) {
|
|
|
|
// Called with group attribute not defined in text.
|
|
|
|
return StatusValue::newFatal( 'cite_error_references_missing_group',
|
|
|
|
Sanitizer::safeEncodeAttribute( $group ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
$groupRefs = $this->referenceStack->getGroupRefs( $group );
|
|
|
|
|
|
|
|
if ( !isset( $groupRefs[$name] ) ) {
|
|
|
|
// No such group exists.
|
|
|
|
return StatusValue::newFatal( 'cite_error_references_missing_key',
|
|
|
|
Sanitizer::safeEncodeAttribute( $name ) );
|
|
|
|
}
|
2019-11-22 21:45:11 +00:00
|
|
|
}
|
|
|
|
} else {
|
2019-11-25 15:10:05 +00:00
|
|
|
// Not in a references tag
|
|
|
|
|
2019-11-22 21:45:11 +00:00
|
|
|
if ( $text !== null && trim( $text ) === '' && !$name ) {
|
|
|
|
// Must have content or reuse another ref by name.
|
|
|
|
// TODO: Trim text before validation.
|
|
|
|
return StatusValue::newFatal( 'cite_error_ref_no_input' );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( $text === null && $name === null ) {
|
|
|
|
// Something like <ref />; this makes no sense.
|
|
|
|
// TODO: Is this redundant with no_input?
|
|
|
|
return StatusValue::newFatal( 'cite_error_ref_no_key' );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( preg_match( '/<ref\b[^<]*?>/',
|
|
|
|
preg_replace( '#<([^ ]+?).*?>.*?</\\1 *>|<!--.*?-->#', '', $text ) ) ) {
|
|
|
|
// (bug T8199) This most likely implies that someone left off the
|
|
|
|
// closing </ref> tag, which will cause the entire article to be
|
|
|
|
// eaten up until the next <ref>. So we bail out early instead.
|
|
|
|
// The fancy regex above first tries chopping out anything that
|
|
|
|
// looks like a comment or SGML tag, which is a crude way to avoid
|
|
|
|
// false alarms for <nowiki>, <pre>, etc.
|
|
|
|
//
|
|
|
|
// Possible improvement: print the warning, followed by the contents
|
|
|
|
// of the <ref> tag. This way no part of the article will be eaten
|
|
|
|
// even temporarily.
|
|
|
|
return StatusValue::newFatal( 'cite_error_included_ref' );
|
|
|
|
}
|
2019-11-26 14:08:18 +00:00
|
|
|
|
|
|
|
// TODO: Assert things such as $text is different than existing ref with $name,
|
|
|
|
// currently done in `pushRef`.
|
2019-11-22 21:45:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return StatusValue::newGood();
|
|
|
|
}
|
|
|
|
|
2011-05-28 20:44:24 +00:00
|
|
|
/**
|
2019-11-25 15:10:05 +00:00
|
|
|
* TODO: Looks like this should be split into a section insensitive to context, and the
|
|
|
|
* special handling for each context.
|
|
|
|
*
|
2019-11-05 09:28:20 +00:00
|
|
|
* @param string|null $text Raw content of the <ref> tag.
|
2015-10-26 14:44:02 +00:00
|
|
|
* @param string[] $argv Arguments
|
|
|
|
* @param Parser $parser
|
|
|
|
*
|
|
|
|
* @throws Exception
|
2011-05-28 20:44:24 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
2016-09-21 11:01:25 +00:00
|
|
|
private function guardedRef(
|
2019-11-05 09:28:20 +00:00
|
|
|
$text,
|
2016-09-20 13:59:58 +00:00
|
|
|
array $argv,
|
2018-11-19 15:24:21 +00:00
|
|
|
Parser $parser
|
2016-09-20 13:59:58 +00:00
|
|
|
) {
|
2019-11-26 10:46:05 +00:00
|
|
|
// Tag every page where Book Referencing has been used, whether or not the ref tag is valid.
|
|
|
|
// This code and the page property will be removed once the feature is stable. See T237531.
|
|
|
|
if ( array_key_exists( self::BOOK_REF_ATTRIBUTE, $argv ) ) {
|
|
|
|
$parser->getOutput()->setProperty( self::BOOK_REF_PROPERTY, true );
|
|
|
|
}
|
|
|
|
|
2019-11-26 11:05:51 +00:00
|
|
|
$status = $this->parseArguments(
|
2019-11-27 16:47:20 +00:00
|
|
|
$argv,
|
|
|
|
[ 'dir', self::BOOK_REF_ATTRIBUTE, 'follow', 'group', 'name' ]
|
|
|
|
);
|
2019-11-27 12:50:05 +00:00
|
|
|
[
|
|
|
|
'dir' => $dir,
|
|
|
|
self::BOOK_REF_ATTRIBUTE => $extends,
|
|
|
|
'follow' => $follow,
|
|
|
|
'group' => $group,
|
|
|
|
'name' => $name
|
2019-11-26 11:05:51 +00:00
|
|
|
] = $status->getValue();
|
2019-11-21 11:52:47 +00:00
|
|
|
|
2019-11-26 11:05:51 +00:00
|
|
|
// Use the default group, or the references group when inside one.
|
2010-04-17 21:07:37 +00:00
|
|
|
if ( $group === null ) {
|
2019-11-19 13:34:19 +00:00
|
|
|
$group = $this->inReferencesGroup ?? self::DEFAULT_GROUP;
|
2009-07-26 22:15:13 +00:00
|
|
|
}
|
2011-02-22 00:07:21 +00:00
|
|
|
|
2019-11-26 11:05:51 +00:00
|
|
|
$status->merge( $this->validateRef( $text, $name, $group, $follow, $extends ) );
|
2009-07-26 22:15:13 +00:00
|
|
|
|
2019-11-22 21:45:11 +00:00
|
|
|
if ( $this->inReferencesGroup !== null ) {
|
2019-11-27 16:47:20 +00:00
|
|
|
if ( !$status->isOK() ) {
|
|
|
|
foreach ( $status->getErrors() as $error ) {
|
2019-11-22 21:45:11 +00:00
|
|
|
$this->mReferencesErrors[] = $this->errorReporter->halfParsed(
|
|
|
|
$error['message'], ...$error['params'] );
|
|
|
|
}
|
2015-07-07 12:26:35 +00:00
|
|
|
} else {
|
2019-11-22 21:45:11 +00:00
|
|
|
$groupRefs = $this->referenceStack->getGroupRefs( $group );
|
|
|
|
if ( !isset( $groupRefs[$name]['text'] ) ) {
|
|
|
|
$this->referenceStack->setRefText( $group, $name, $text );
|
|
|
|
} else {
|
|
|
|
if ( $groupRefs[$name]['text'] !== $text ) {
|
|
|
|
// two refs with same key and different content
|
2019-11-26 09:13:18 +00:00
|
|
|
// adds error message to the original ref
|
|
|
|
// TODO: report these errors the same way as the others, rather than a
|
|
|
|
// special case to append to the second one's content.
|
2019-11-22 21:45:11 +00:00
|
|
|
$text =
|
|
|
|
$groupRefs[$name]['text'] . ' ' .
|
|
|
|
$this->errorReporter->plain( 'cite_error_references_duplicate_key',
|
|
|
|
$name );
|
|
|
|
$this->referenceStack->setRefText( $group, $name, $text );
|
|
|
|
}
|
|
|
|
}
|
2009-07-26 22:15:13 +00:00
|
|
|
}
|
2019-11-22 21:45:11 +00:00
|
|
|
return '';
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
2011-02-22 00:07:21 +00:00
|
|
|
|
2019-11-22 21:45:11 +00:00
|
|
|
if ( $text !== null && trim( $text ) === '' && $name ) {
|
|
|
|
$text = null;
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
|
|
|
|
2019-11-27 16:47:20 +00:00
|
|
|
if ( !$status->isOK() ) {
|
2019-11-22 17:28:51 +00:00
|
|
|
$this->referenceStack->pushInvalidRef();
|
2008-09-18 17:16:10 +00:00
|
|
|
|
2019-11-26 09:13:18 +00:00
|
|
|
// FIXME: If we ever have multiple errors, these must all be presented to the user,
|
|
|
|
// so they know what to correct.
|
2019-11-25 15:10:05 +00:00
|
|
|
// TODO: Make this nicer, see T238061
|
2019-11-27 16:47:20 +00:00
|
|
|
$error = $status->getErrors()[0];
|
2019-11-22 21:45:11 +00:00
|
|
|
return $this->errorReporter->halfParsed( $error['message'], ...$error['params'] );
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
|
|
|
|
2019-11-22 21:45:11 +00:00
|
|
|
# We don't care about the content: if the name exists, the ref
|
|
|
|
# is presumptively valid. Either it stores a new ref, or re-
|
|
|
|
# fers to an existing one. If it refers to a nonexistent ref,
|
|
|
|
# we'll figure that out later. Likewise it's definitely valid
|
|
|
|
# if there's any content, regardless of name.
|
2008-06-06 20:38:04 +00:00
|
|
|
|
2019-11-22 21:45:11 +00:00
|
|
|
$result = $this->referenceStack->pushRef(
|
2019-11-27 23:27:11 +00:00
|
|
|
$text, $name, $group, $extends, $follow, $argv, $dir, $parser->getStripState() );
|
2019-11-22 21:45:11 +00:00
|
|
|
if ( $result === null ) {
|
|
|
|
return '';
|
2019-11-19 13:46:29 +00:00
|
|
|
} else {
|
2019-11-22 21:45:11 +00:00
|
|
|
[ $key, $count, $label, $subkey ] = $result;
|
2019-11-28 14:39:11 +00:00
|
|
|
return $this->footnoteMarkFormatter->linkRef( $group, $key, $count, $label, $subkey );
|
2019-11-01 14:29:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-06 20:38:04 +00:00
|
|
|
/**
|
2015-10-26 14:44:02 +00:00
|
|
|
* @param string[] $argv The argument vector
|
2019-11-27 12:50:05 +00:00
|
|
|
* @param string[] $allowedAttributes Allowed attribute names
|
|
|
|
*
|
2019-11-26 11:05:51 +00:00
|
|
|
* @return StatusValue Either an error, or has a value with the dictionary of field names and
|
|
|
|
* parsed or default values. Missing attributes will be `null`.
|
2008-06-06 20:38:04 +00:00
|
|
|
*/
|
2019-11-27 12:50:05 +00:00
|
|
|
private function parseArguments( array $argv, array $allowedAttributes ) {
|
2019-11-26 11:05:51 +00:00
|
|
|
$maxCount = count( $allowedAttributes );
|
|
|
|
$allValues = array_merge( array_fill_keys( $allowedAttributes, null ), $argv );
|
|
|
|
$status = StatusValue::newGood( array_slice( $allValues, 0, $maxCount ) );
|
|
|
|
|
|
|
|
if ( count( $allValues ) > $maxCount ) {
|
|
|
|
// A <ref> must have a name (can be null), but <references> can't have one
|
|
|
|
$status->fatal( in_array( 'name', $allowedAttributes )
|
|
|
|
? 'cite_error_ref_too_many_keys'
|
|
|
|
: 'cite_error_references_invalid_parameters'
|
|
|
|
);
|
2018-11-19 15:29:16 +00:00
|
|
|
}
|
|
|
|
|
2019-11-26 11:05:51 +00:00
|
|
|
return $status;
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
|
|
|
|
2015-06-08 14:05:06 +00:00
|
|
|
/**
|
|
|
|
* Callback function for <references>
|
2008-06-06 20:38:04 +00:00
|
|
|
*
|
2019-11-05 09:28:20 +00:00
|
|
|
* @param string|null $text Raw content of the <references> tag.
|
2015-10-26 14:44:02 +00:00
|
|
|
* @param string[] $argv Arguments
|
|
|
|
* @param Parser $parser
|
2011-05-28 20:44:24 +00:00
|
|
|
*
|
2019-11-12 12:06:39 +00:00
|
|
|
* @return string|false False in case a <references> tag is not allowed in the current context
|
2008-06-06 20:38:04 +00:00
|
|
|
*/
|
2019-11-12 12:06:39 +00:00
|
|
|
public function references( $text, array $argv, Parser $parser ) {
|
2019-11-19 13:34:19 +00:00
|
|
|
if ( $this->mInCite || $this->inReferencesGroup !== null ) {
|
2019-11-12 12:06:39 +00:00
|
|
|
return false;
|
2015-07-18 20:55:32 +00:00
|
|
|
}
|
2019-11-11 19:16:05 +00:00
|
|
|
|
2019-11-19 10:29:33 +00:00
|
|
|
$this->rememberParser( $parser );
|
2019-11-05 09:28:20 +00:00
|
|
|
$ret = $this->guardedReferences( $text, $argv, $parser );
|
2019-11-19 13:34:19 +00:00
|
|
|
$this->inReferencesGroup = null;
|
2019-11-11 19:16:05 +00:00
|
|
|
|
2015-07-18 20:55:32 +00:00
|
|
|
return $ret;
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
|
|
|
|
2011-05-28 20:44:24 +00:00
|
|
|
/**
|
2018-07-24 23:08:25 +00:00
|
|
|
* Must only be called from references(). Use that to prevent recursion.
|
|
|
|
*
|
2019-11-05 09:28:20 +00:00
|
|
|
* @param string|null $text Raw content of the <references> tag.
|
2015-10-26 14:44:02 +00:00
|
|
|
* @param string[] $argv
|
|
|
|
* @param Parser $parser
|
2018-11-19 15:24:21 +00:00
|
|
|
*
|
2011-05-28 20:44:24 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
2016-09-21 11:01:25 +00:00
|
|
|
private function guardedReferences(
|
2019-11-05 09:28:20 +00:00
|
|
|
$text,
|
2016-09-20 13:59:58 +00:00
|
|
|
array $argv,
|
2018-11-19 15:24:21 +00:00
|
|
|
Parser $parser
|
2016-09-20 13:59:58 +00:00
|
|
|
) {
|
2017-03-22 19:13:22 +00:00
|
|
|
global $wgCiteResponsiveReferences;
|
2008-06-06 20:38:04 +00:00
|
|
|
|
2019-11-26 11:05:51 +00:00
|
|
|
$status = $this->parseArguments(
|
2019-11-27 12:50:05 +00:00
|
|
|
$argv,
|
|
|
|
[ 'group', 'responsive' ]
|
|
|
|
);
|
2019-11-26 11:05:51 +00:00
|
|
|
[ 'group' => $group, 'responsive' => $responsive ] = $status->getValue();
|
2019-11-27 12:50:05 +00:00
|
|
|
$this->inReferencesGroup = $group ?? self::DEFAULT_GROUP;
|
2011-02-22 00:07:21 +00:00
|
|
|
|
2019-11-05 09:28:20 +00:00
|
|
|
if ( strval( $text ) !== '' ) {
|
Rollback all, then redo all, when fixing out-of-order tags; not one-by-one
Imagine the following wikitext:
<ref name=r/>
<references>
<ref name=r>A</ref>
<ref name=r>B</ref>
</references>
This is simple. Cite would see these as the following operations, in
order:
1. Use only: <ref name=r/>
2. References block
3. Define only: <ref name=r>A</ref>
4. Define only: <ref name=r>B</ref>
<ref name=r> is defined twice with different content and we get an
error message.
Now, imagine the following wikitext:
<ref name=r/>
{{#tag:references|
<ref name=r>A</ref>
<ref name=r>B</ref>
}}
Cite would see these as the following operations, in order:
1. Use only: <ref name=r/>
2. Use and define: <ref name=r>A</ref>
3. Use and define: <ref name=r>B</ref>
4. References block
When the 'references' block appears, Cite notices that the tag has
parsed content, and deduces that it was called with #tag. We need to
undo the last operations to update internal bookkeeping, as the last
two 'ref' tags do not actually represent ref usages, as we assumed,
but only definitions.
5. Undo: <ref name=r> reused
6. Define only: <ref name=r>B</ref>
7. Undo: <ref name=r> defined
(Right now, it appears to Cite that <ref name=r> was never defined!)
8. Define only: <ref name=r>A</ref>
Thus we get no errors, although we should.
This patch changes the order of the rollback operations:
5. Undo: <ref name=r> reused
6. Undo: <ref name=r> defined
7. Define only: <ref name=r>A</ref>
8. Define only: <ref name=r>B</ref>
Aha! <ref name=r> is defined twice with different content! We get an
error correctly.
Bug: T124227
Change-Id: I61766c4104856323987cca9a5e4ff85a76b3618b
2016-01-20 20:38:59 +00:00
|
|
|
# Detect whether we were sent already rendered <ref>s.
|
|
|
|
# Mostly a side effect of using #tag to call references.
|
|
|
|
# The following assumes that the parsed <ref>s sent within
|
|
|
|
# the <references> block were the most recent calls to
|
|
|
|
# <ref>. This assumption is true for all known use cases,
|
|
|
|
# but not strictly enforced by the parser. It is possible
|
|
|
|
# that some unusual combination of #tag, <references> and
|
|
|
|
# conditional parser functions could be created that would
|
|
|
|
# lead to malformed references here.
|
2019-11-05 09:28:20 +00:00
|
|
|
$count = substr_count( $text, Parser::MARKER_PREFIX . "-ref-" );
|
Rollback all, then redo all, when fixing out-of-order tags; not one-by-one
Imagine the following wikitext:
<ref name=r/>
<references>
<ref name=r>A</ref>
<ref name=r>B</ref>
</references>
This is simple. Cite would see these as the following operations, in
order:
1. Use only: <ref name=r/>
2. References block
3. Define only: <ref name=r>A</ref>
4. Define only: <ref name=r>B</ref>
<ref name=r> is defined twice with different content and we get an
error message.
Now, imagine the following wikitext:
<ref name=r/>
{{#tag:references|
<ref name=r>A</ref>
<ref name=r>B</ref>
}}
Cite would see these as the following operations, in order:
1. Use only: <ref name=r/>
2. Use and define: <ref name=r>A</ref>
3. Use and define: <ref name=r>B</ref>
4. References block
When the 'references' block appears, Cite notices that the tag has
parsed content, and deduces that it was called with #tag. We need to
undo the last operations to update internal bookkeeping, as the last
two 'ref' tags do not actually represent ref usages, as we assumed,
but only definitions.
5. Undo: <ref name=r> reused
6. Define only: <ref name=r>B</ref>
7. Undo: <ref name=r> defined
(Right now, it appears to Cite that <ref name=r> was never defined!)
8. Define only: <ref name=r>A</ref>
Thus we get no errors, although we should.
This patch changes the order of the rollback operations:
5. Undo: <ref name=r> reused
6. Undo: <ref name=r> defined
7. Define only: <ref name=r>A</ref>
8. Define only: <ref name=r>B</ref>
Aha! <ref name=r> is defined twice with different content! We get an
error correctly.
Bug: T124227
Change-Id: I61766c4104856323987cca9a5e4ff85a76b3618b
2016-01-20 20:38:59 +00:00
|
|
|
|
|
|
|
# Undo effects of calling <ref> while unaware of containing <references>
|
2019-11-22 17:28:51 +00:00
|
|
|
$redoStack = $this->referenceStack->rollbackRefs( $count );
|
2015-06-08 14:05:06 +00:00
|
|
|
|
Rollback all, then redo all, when fixing out-of-order tags; not one-by-one
Imagine the following wikitext:
<ref name=r/>
<references>
<ref name=r>A</ref>
<ref name=r>B</ref>
</references>
This is simple. Cite would see these as the following operations, in
order:
1. Use only: <ref name=r/>
2. References block
3. Define only: <ref name=r>A</ref>
4. Define only: <ref name=r>B</ref>
<ref name=r> is defined twice with different content and we get an
error message.
Now, imagine the following wikitext:
<ref name=r/>
{{#tag:references|
<ref name=r>A</ref>
<ref name=r>B</ref>
}}
Cite would see these as the following operations, in order:
1. Use only: <ref name=r/>
2. Use and define: <ref name=r>A</ref>
3. Use and define: <ref name=r>B</ref>
4. References block
When the 'references' block appears, Cite notices that the tag has
parsed content, and deduces that it was called with #tag. We need to
undo the last operations to update internal bookkeeping, as the last
two 'ref' tags do not actually represent ref usages, as we assumed,
but only definitions.
5. Undo: <ref name=r> reused
6. Define only: <ref name=r>B</ref>
7. Undo: <ref name=r> defined
(Right now, it appears to Cite that <ref name=r> was never defined!)
8. Define only: <ref name=r>A</ref>
Thus we get no errors, although we should.
This patch changes the order of the rollback operations:
5. Undo: <ref name=r> reused
6. Undo: <ref name=r> defined
7. Define only: <ref name=r>A</ref>
8. Define only: <ref name=r>B</ref>
Aha! <ref name=r> is defined twice with different content! We get an
error correctly.
Bug: T124227
Change-Id: I61766c4104856323987cca9a5e4ff85a76b3618b
2016-01-20 20:38:59 +00:00
|
|
|
# Rerun <ref> call now that mInReferences is set.
|
2019-11-22 17:28:51 +00:00
|
|
|
foreach ( $redoStack as $call ) {
|
|
|
|
[ $ref_argv, $ref_text ] = $call;
|
|
|
|
$this->guardedRef( $ref_text, $ref_argv, $parser );
|
2015-06-08 14:05:06 +00:00
|
|
|
}
|
|
|
|
|
2019-11-05 09:28:20 +00:00
|
|
|
# Parse $text to process any unparsed <ref> tags.
|
|
|
|
$parser->recursiveTagParse( $text );
|
2009-07-26 22:15:13 +00:00
|
|
|
}
|
|
|
|
|
2019-11-27 12:50:05 +00:00
|
|
|
// FIXME: This feature is not covered by parser tests!
|
Implement responsive columns for reference lists
This is based on the popular 'count' parameter from Template:Reflist on
English Wikipedia, which has also been adopted by many other wikis.
That template's 'count' parameter allows maximum flexibility on a per-
page basis. This was important because the template can't know how many
references the list will contain. Users typically manually add (and
later, increment) the 'count' parameter when the list exceeds a certain
threshold.
The template currently sets an exact column count (via the CSS3
property `column-count`).
This patch improves on that by instead using the closely related CSS3
`column-width` property. This automatically derives the column count
based on the available space in the browser window. It will thus create
two or three columns on a typical desktop screen, and two or no columns
on a mobile device.
The specified width is the minimum width of a column. This ensures that
the list is not split when rendered on a narrow screen or mobile device.
It also hooks into the raw list before parsing and adds the class only
when the list will contain more than a certain number of items. This
prevents very short lists from being split into multiple columns.
Templates like Template:Reflist on English Wikipedia currently are not
able to set inline styles on the list element directly, which is why
they set it on a `<div>` wrapping the `<references />` output. Because
of this, the feature of the Cite extension must not be enabled at the
same time, as that would result in both the template's wrapper and the
references list being split. The end result would involve sitations with
three columns split in four sub-columns, creating a complicated mess of
nine intermixed columns.
To provide a smooth migration for wikis, this feature can be disabled by
default using `$wgCiteResponsiveReferences = false`. Each individual
template createing reference list can then be migrated, by removing the
wrapper column styles and instead settting the new "responsive"
attribute, like so: `<references responsive />`.
Once any conflicting templates have been migrated, the default for the
wiki can be swapped by setting `$wgCiteResponsiveReferences = true`.
If wikis wish for some templates to keep their custom column splitting
behaviour, templates can also opt-out by setting `responsive="0"`, which
will make sure that it will keep behaving the current way even after the
feature becomes enabled by default for the wiki.
In summary, when disabled by default, pages can opt into this system
with `<references responsive />`. When enabled by default, pages can opt
out of the system with `<references responsive=0 />`.
* Deprecate cite_references_prefix/cite_references_suffix.
This message is rarely used and opens up compatibility hazards.
It was already removed by Parsoid, but the PHP implementation
still had it. It's typically used to add inline styles to the
wrapper which is more appropiately done in Common.css (or
obsoleted as part of the skin or Cite extenion itself nowadays
depending on what style in question).
It was also a HTML-style message with separated open and close
segments, which is an anti-pattern in itself.
* Declare module target explicitly and include mobile. The absence of
this stylesheet caused subtle BiDi/RTL bugs on mobile.
Bug: T33597
Change-Id: Ia535f9b722e825e71e792b36356febc3bd444387
2015-07-21 02:33:50 +00:00
|
|
|
if ( isset( $argv['responsive'] ) ) {
|
2019-11-27 12:50:05 +00:00
|
|
|
$responsive = $responsive !== '0';
|
Implement responsive columns for reference lists
This is based on the popular 'count' parameter from Template:Reflist on
English Wikipedia, which has also been adopted by many other wikis.
That template's 'count' parameter allows maximum flexibility on a per-
page basis. This was important because the template can't know how many
references the list will contain. Users typically manually add (and
later, increment) the 'count' parameter when the list exceeds a certain
threshold.
The template currently sets an exact column count (via the CSS3
property `column-count`).
This patch improves on that by instead using the closely related CSS3
`column-width` property. This automatically derives the column count
based on the available space in the browser window. It will thus create
two or three columns on a typical desktop screen, and two or no columns
on a mobile device.
The specified width is the minimum width of a column. This ensures that
the list is not split when rendered on a narrow screen or mobile device.
It also hooks into the raw list before parsing and adds the class only
when the list will contain more than a certain number of items. This
prevents very short lists from being split into multiple columns.
Templates like Template:Reflist on English Wikipedia currently are not
able to set inline styles on the list element directly, which is why
they set it on a `<div>` wrapping the `<references />` output. Because
of this, the feature of the Cite extension must not be enabled at the
same time, as that would result in both the template's wrapper and the
references list being split. The end result would involve sitations with
three columns split in four sub-columns, creating a complicated mess of
nine intermixed columns.
To provide a smooth migration for wikis, this feature can be disabled by
default using `$wgCiteResponsiveReferences = false`. Each individual
template createing reference list can then be migrated, by removing the
wrapper column styles and instead settting the new "responsive"
attribute, like so: `<references responsive />`.
Once any conflicting templates have been migrated, the default for the
wiki can be swapped by setting `$wgCiteResponsiveReferences = true`.
If wikis wish for some templates to keep their custom column splitting
behaviour, templates can also opt-out by setting `responsive="0"`, which
will make sure that it will keep behaving the current way even after the
feature becomes enabled by default for the wiki.
In summary, when disabled by default, pages can opt into this system
with `<references responsive />`. When enabled by default, pages can opt
out of the system with `<references responsive=0 />`.
* Deprecate cite_references_prefix/cite_references_suffix.
This message is rarely used and opens up compatibility hazards.
It was already removed by Parsoid, but the PHP implementation
still had it. It's typically used to add inline styles to the
wrapper which is more appropiately done in Common.css (or
obsoleted as part of the skin or Cite extenion itself nowadays
depending on what style in question).
It was also a HTML-style message with separated open and close
segments, which is an anti-pattern in itself.
* Declare module target explicitly and include mobile. The absence of
this stylesheet caused subtle BiDi/RTL bugs on mobile.
Bug: T33597
Change-Id: Ia535f9b722e825e71e792b36356febc3bd444387
2015-07-21 02:33:50 +00:00
|
|
|
} else {
|
|
|
|
$responsive = $wgCiteResponsiveReferences;
|
|
|
|
}
|
|
|
|
|
2019-11-26 11:05:51 +00:00
|
|
|
if ( !$status->isOK() ) {
|
|
|
|
// Bail out with an error.
|
|
|
|
$error = $status->getErrors()[0];
|
|
|
|
return $this->errorReporter->halfParsed( $error['message'], ...$error['params'] );
|
2015-07-18 20:55:32 +00:00
|
|
|
}
|
2011-02-22 00:07:21 +00:00
|
|
|
|
2019-11-27 12:50:05 +00:00
|
|
|
$s = $this->referencesFormat( $this->inReferencesGroup, $responsive );
|
2015-07-18 20:55:32 +00:00
|
|
|
|
|
|
|
# Append errors generated while processing <references>
|
2015-07-07 07:37:14 +00:00
|
|
|
if ( $this->mReferencesErrors ) {
|
2015-07-18 20:55:32 +00:00
|
|
|
$s .= "\n" . implode( "<br />\n", $this->mReferencesErrors );
|
2016-05-09 23:36:49 +00:00
|
|
|
$this->mReferencesErrors = [];
|
2015-07-18 20:55:32 +00:00
|
|
|
}
|
|
|
|
return $s;
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-07-24 23:08:25 +00:00
|
|
|
* Make output to be returned from the references() function.
|
|
|
|
*
|
|
|
|
* If called outside of references(), caller is responsible for ensuring
|
|
|
|
* `mInReferences` is enabled before the call and disabled after call.
|
2011-09-14 15:07:20 +00:00
|
|
|
*
|
2015-10-26 14:44:02 +00:00
|
|
|
* @param string $group
|
Implement responsive columns for reference lists
This is based on the popular 'count' parameter from Template:Reflist on
English Wikipedia, which has also been adopted by many other wikis.
That template's 'count' parameter allows maximum flexibility on a per-
page basis. This was important because the template can't know how many
references the list will contain. Users typically manually add (and
later, increment) the 'count' parameter when the list exceeds a certain
threshold.
The template currently sets an exact column count (via the CSS3
property `column-count`).
This patch improves on that by instead using the closely related CSS3
`column-width` property. This automatically derives the column count
based on the available space in the browser window. It will thus create
two or three columns on a typical desktop screen, and two or no columns
on a mobile device.
The specified width is the minimum width of a column. This ensures that
the list is not split when rendered on a narrow screen or mobile device.
It also hooks into the raw list before parsing and adds the class only
when the list will contain more than a certain number of items. This
prevents very short lists from being split into multiple columns.
Templates like Template:Reflist on English Wikipedia currently are not
able to set inline styles on the list element directly, which is why
they set it on a `<div>` wrapping the `<references />` output. Because
of this, the feature of the Cite extension must not be enabled at the
same time, as that would result in both the template's wrapper and the
references list being split. The end result would involve sitations with
three columns split in four sub-columns, creating a complicated mess of
nine intermixed columns.
To provide a smooth migration for wikis, this feature can be disabled by
default using `$wgCiteResponsiveReferences = false`. Each individual
template createing reference list can then be migrated, by removing the
wrapper column styles and instead settting the new "responsive"
attribute, like so: `<references responsive />`.
Once any conflicting templates have been migrated, the default for the
wiki can be swapped by setting `$wgCiteResponsiveReferences = true`.
If wikis wish for some templates to keep their custom column splitting
behaviour, templates can also opt-out by setting `responsive="0"`, which
will make sure that it will keep behaving the current way even after the
feature becomes enabled by default for the wiki.
In summary, when disabled by default, pages can opt into this system
with `<references responsive />`. When enabled by default, pages can opt
out of the system with `<references responsive=0 />`.
* Deprecate cite_references_prefix/cite_references_suffix.
This message is rarely used and opens up compatibility hazards.
It was already removed by Parsoid, but the PHP implementation
still had it. It's typically used to add inline styles to the
wrapper which is more appropiately done in Common.css (or
obsoleted as part of the skin or Cite extenion itself nowadays
depending on what style in question).
It was also a HTML-style message with separated open and close
segments, which is an anti-pattern in itself.
* Declare module target explicitly and include mobile. The absence of
this stylesheet caused subtle BiDi/RTL bugs on mobile.
Bug: T33597
Change-Id: Ia535f9b722e825e71e792b36356febc3bd444387
2015-07-21 02:33:50 +00:00
|
|
|
* @param bool $responsive
|
|
|
|
* @return string HTML ready for output
|
2008-06-06 20:38:04 +00:00
|
|
|
*/
|
Implement responsive columns for reference lists
This is based on the popular 'count' parameter from Template:Reflist on
English Wikipedia, which has also been adopted by many other wikis.
That template's 'count' parameter allows maximum flexibility on a per-
page basis. This was important because the template can't know how many
references the list will contain. Users typically manually add (and
later, increment) the 'count' parameter when the list exceeds a certain
threshold.
The template currently sets an exact column count (via the CSS3
property `column-count`).
This patch improves on that by instead using the closely related CSS3
`column-width` property. This automatically derives the column count
based on the available space in the browser window. It will thus create
two or three columns on a typical desktop screen, and two or no columns
on a mobile device.
The specified width is the minimum width of a column. This ensures that
the list is not split when rendered on a narrow screen or mobile device.
It also hooks into the raw list before parsing and adds the class only
when the list will contain more than a certain number of items. This
prevents very short lists from being split into multiple columns.
Templates like Template:Reflist on English Wikipedia currently are not
able to set inline styles on the list element directly, which is why
they set it on a `<div>` wrapping the `<references />` output. Because
of this, the feature of the Cite extension must not be enabled at the
same time, as that would result in both the template's wrapper and the
references list being split. The end result would involve sitations with
three columns split in four sub-columns, creating a complicated mess of
nine intermixed columns.
To provide a smooth migration for wikis, this feature can be disabled by
default using `$wgCiteResponsiveReferences = false`. Each individual
template createing reference list can then be migrated, by removing the
wrapper column styles and instead settting the new "responsive"
attribute, like so: `<references responsive />`.
Once any conflicting templates have been migrated, the default for the
wiki can be swapped by setting `$wgCiteResponsiveReferences = true`.
If wikis wish for some templates to keep their custom column splitting
behaviour, templates can also opt-out by setting `responsive="0"`, which
will make sure that it will keep behaving the current way even after the
feature becomes enabled by default for the wiki.
In summary, when disabled by default, pages can opt into this system
with `<references responsive />`. When enabled by default, pages can opt
out of the system with `<references responsive=0 />`.
* Deprecate cite_references_prefix/cite_references_suffix.
This message is rarely used and opens up compatibility hazards.
It was already removed by Parsoid, but the PHP implementation
still had it. It's typically used to add inline styles to the
wrapper which is more appropiately done in Common.css (or
obsoleted as part of the skin or Cite extenion itself nowadays
depending on what style in question).
It was also a HTML-style message with separated open and close
segments, which is an anti-pattern in itself.
* Declare module target explicitly and include mobile. The absence of
this stylesheet caused subtle BiDi/RTL bugs on mobile.
Bug: T33597
Change-Id: Ia535f9b722e825e71e792b36356febc3bd444387
2015-07-21 02:33:50 +00:00
|
|
|
private function referencesFormat( $group, $responsive ) {
|
2019-11-22 17:28:51 +00:00
|
|
|
if ( !$this->referenceStack->hasGroup( $group ) ) {
|
2008-06-06 20:38:04 +00:00
|
|
|
return '';
|
2011-02-22 00:07:21 +00:00
|
|
|
}
|
|
|
|
|
2019-11-25 11:37:07 +00:00
|
|
|
// Add new lines between the list items (ref entries) to avoid confusing tidy (T15073).
|
Implement responsive columns for reference lists
This is based on the popular 'count' parameter from Template:Reflist on
English Wikipedia, which has also been adopted by many other wikis.
That template's 'count' parameter allows maximum flexibility on a per-
page basis. This was important because the template can't know how many
references the list will contain. Users typically manually add (and
later, increment) the 'count' parameter when the list exceeds a certain
threshold.
The template currently sets an exact column count (via the CSS3
property `column-count`).
This patch improves on that by instead using the closely related CSS3
`column-width` property. This automatically derives the column count
based on the available space in the browser window. It will thus create
two or three columns on a typical desktop screen, and two or no columns
on a mobile device.
The specified width is the minimum width of a column. This ensures that
the list is not split when rendered on a narrow screen or mobile device.
It also hooks into the raw list before parsing and adds the class only
when the list will contain more than a certain number of items. This
prevents very short lists from being split into multiple columns.
Templates like Template:Reflist on English Wikipedia currently are not
able to set inline styles on the list element directly, which is why
they set it on a `<div>` wrapping the `<references />` output. Because
of this, the feature of the Cite extension must not be enabled at the
same time, as that would result in both the template's wrapper and the
references list being split. The end result would involve sitations with
three columns split in four sub-columns, creating a complicated mess of
nine intermixed columns.
To provide a smooth migration for wikis, this feature can be disabled by
default using `$wgCiteResponsiveReferences = false`. Each individual
template createing reference list can then be migrated, by removing the
wrapper column styles and instead settting the new "responsive"
attribute, like so: `<references responsive />`.
Once any conflicting templates have been migrated, the default for the
wiki can be swapped by setting `$wgCiteResponsiveReferences = true`.
If wikis wish for some templates to keep their custom column splitting
behaviour, templates can also opt-out by setting `responsive="0"`, which
will make sure that it will keep behaving the current way even after the
feature becomes enabled by default for the wiki.
In summary, when disabled by default, pages can opt into this system
with `<references responsive />`. When enabled by default, pages can opt
out of the system with `<references responsive=0 />`.
* Deprecate cite_references_prefix/cite_references_suffix.
This message is rarely used and opens up compatibility hazards.
It was already removed by Parsoid, but the PHP implementation
still had it. It's typically used to add inline styles to the
wrapper which is more appropiately done in Common.css (or
obsoleted as part of the skin or Cite extenion itself nowadays
depending on what style in question).
It was also a HTML-style message with separated open and close
segments, which is an anti-pattern in itself.
* Declare module target explicitly and include mobile. The absence of
this stylesheet caused subtle BiDi/RTL bugs on mobile.
Bug: T33597
Change-Id: Ia535f9b722e825e71e792b36356febc3bd444387
2015-07-21 02:33:50 +00:00
|
|
|
// Note: This builds a string of wikitext, not html.
|
2019-11-18 13:16:57 +00:00
|
|
|
$parserInput = "\n";
|
2019-11-18 14:49:51 +00:00
|
|
|
$indented = false;
|
2019-11-22 17:28:51 +00:00
|
|
|
$groupRefs = $this->referenceStack->getGroupRefs( $group );
|
|
|
|
foreach ( $groupRefs as $key => $value ) {
|
2019-11-18 14:49:51 +00:00
|
|
|
// This assumes extended references appear after their parent in the array.
|
|
|
|
if ( !$indented && isset( $value['extends'] ) ) {
|
|
|
|
// Hack: The nested <ol> needs to go inside of the <li>.
|
|
|
|
$parserInput = preg_replace( '/<\/li>\s*$/', '', $parserInput );
|
|
|
|
$parserInput .= Html::openElement( 'ol', [ 'class' => 'mw-extended-references' ] );
|
|
|
|
$indented = true;
|
|
|
|
} elseif ( $indented && !isset( $value['extends'] ) ) {
|
|
|
|
// FIXME: This is't closed if there is no unindented element at the end
|
|
|
|
$parserInput .= Html::closeElement( 'ol' );
|
|
|
|
$indented = false;
|
|
|
|
}
|
2019-11-18 13:16:57 +00:00
|
|
|
$parserInput .= $this->referencesFormatEntry( $key, $value ) . "\n";
|
|
|
|
}
|
|
|
|
$parserInput = Html::rawElement( 'ol', [ 'class' => [ 'references' ] ], $parserInput );
|
2018-02-28 09:59:50 +00:00
|
|
|
// Live hack: parse() adds two newlines on WM, can't reproduce it locally -ævar
|
|
|
|
$ret = rtrim( $this->mParser->recursiveTagParse( $parserInput ), "\n" );
|
2009-02-03 04:57:28 +00:00
|
|
|
|
Implement responsive columns for reference lists
This is based on the popular 'count' parameter from Template:Reflist on
English Wikipedia, which has also been adopted by many other wikis.
That template's 'count' parameter allows maximum flexibility on a per-
page basis. This was important because the template can't know how many
references the list will contain. Users typically manually add (and
later, increment) the 'count' parameter when the list exceeds a certain
threshold.
The template currently sets an exact column count (via the CSS3
property `column-count`).
This patch improves on that by instead using the closely related CSS3
`column-width` property. This automatically derives the column count
based on the available space in the browser window. It will thus create
two or three columns on a typical desktop screen, and two or no columns
on a mobile device.
The specified width is the minimum width of a column. This ensures that
the list is not split when rendered on a narrow screen or mobile device.
It also hooks into the raw list before parsing and adds the class only
when the list will contain more than a certain number of items. This
prevents very short lists from being split into multiple columns.
Templates like Template:Reflist on English Wikipedia currently are not
able to set inline styles on the list element directly, which is why
they set it on a `<div>` wrapping the `<references />` output. Because
of this, the feature of the Cite extension must not be enabled at the
same time, as that would result in both the template's wrapper and the
references list being split. The end result would involve sitations with
three columns split in four sub-columns, creating a complicated mess of
nine intermixed columns.
To provide a smooth migration for wikis, this feature can be disabled by
default using `$wgCiteResponsiveReferences = false`. Each individual
template createing reference list can then be migrated, by removing the
wrapper column styles and instead settting the new "responsive"
attribute, like so: `<references responsive />`.
Once any conflicting templates have been migrated, the default for the
wiki can be swapped by setting `$wgCiteResponsiveReferences = true`.
If wikis wish for some templates to keep their custom column splitting
behaviour, templates can also opt-out by setting `responsive="0"`, which
will make sure that it will keep behaving the current way even after the
feature becomes enabled by default for the wiki.
In summary, when disabled by default, pages can opt into this system
with `<references responsive />`. When enabled by default, pages can opt
out of the system with `<references responsive=0 />`.
* Deprecate cite_references_prefix/cite_references_suffix.
This message is rarely used and opens up compatibility hazards.
It was already removed by Parsoid, but the PHP implementation
still had it. It's typically used to add inline styles to the
wrapper which is more appropiately done in Common.css (or
obsoleted as part of the skin or Cite extenion itself nowadays
depending on what style in question).
It was also a HTML-style message with separated open and close
segments, which is an anti-pattern in itself.
* Declare module target explicitly and include mobile. The absence of
this stylesheet caused subtle BiDi/RTL bugs on mobile.
Bug: T33597
Change-Id: Ia535f9b722e825e71e792b36356febc3bd444387
2015-07-21 02:33:50 +00:00
|
|
|
if ( $responsive ) {
|
|
|
|
// Use a DIV wrap because column-count on a list directly is broken in Chrome.
|
|
|
|
// See https://bugs.chromium.org/p/chromium/issues/detail?id=498730.
|
|
|
|
$wrapClasses = [ 'mw-references-wrap' ];
|
2019-11-22 17:28:51 +00:00
|
|
|
if ( count( $groupRefs ) > 10 ) {
|
Implement responsive columns for reference lists
This is based on the popular 'count' parameter from Template:Reflist on
English Wikipedia, which has also been adopted by many other wikis.
That template's 'count' parameter allows maximum flexibility on a per-
page basis. This was important because the template can't know how many
references the list will contain. Users typically manually add (and
later, increment) the 'count' parameter when the list exceeds a certain
threshold.
The template currently sets an exact column count (via the CSS3
property `column-count`).
This patch improves on that by instead using the closely related CSS3
`column-width` property. This automatically derives the column count
based on the available space in the browser window. It will thus create
two or three columns on a typical desktop screen, and two or no columns
on a mobile device.
The specified width is the minimum width of a column. This ensures that
the list is not split when rendered on a narrow screen or mobile device.
It also hooks into the raw list before parsing and adds the class only
when the list will contain more than a certain number of items. This
prevents very short lists from being split into multiple columns.
Templates like Template:Reflist on English Wikipedia currently are not
able to set inline styles on the list element directly, which is why
they set it on a `<div>` wrapping the `<references />` output. Because
of this, the feature of the Cite extension must not be enabled at the
same time, as that would result in both the template's wrapper and the
references list being split. The end result would involve sitations with
three columns split in four sub-columns, creating a complicated mess of
nine intermixed columns.
To provide a smooth migration for wikis, this feature can be disabled by
default using `$wgCiteResponsiveReferences = false`. Each individual
template createing reference list can then be migrated, by removing the
wrapper column styles and instead settting the new "responsive"
attribute, like so: `<references responsive />`.
Once any conflicting templates have been migrated, the default for the
wiki can be swapped by setting `$wgCiteResponsiveReferences = true`.
If wikis wish for some templates to keep their custom column splitting
behaviour, templates can also opt-out by setting `responsive="0"`, which
will make sure that it will keep behaving the current way even after the
feature becomes enabled by default for the wiki.
In summary, when disabled by default, pages can opt into this system
with `<references responsive />`. When enabled by default, pages can opt
out of the system with `<references responsive=0 />`.
* Deprecate cite_references_prefix/cite_references_suffix.
This message is rarely used and opens up compatibility hazards.
It was already removed by Parsoid, but the PHP implementation
still had it. It's typically used to add inline styles to the
wrapper which is more appropiately done in Common.css (or
obsoleted as part of the skin or Cite extenion itself nowadays
depending on what style in question).
It was also a HTML-style message with separated open and close
segments, which is an anti-pattern in itself.
* Declare module target explicitly and include mobile. The absence of
this stylesheet caused subtle BiDi/RTL bugs on mobile.
Bug: T33597
Change-Id: Ia535f9b722e825e71e792b36356febc3bd444387
2015-07-21 02:33:50 +00:00
|
|
|
$wrapClasses[] = 'mw-references-columns';
|
|
|
|
}
|
|
|
|
$ret = Html::rawElement( 'div', [ 'class' => $wrapClasses ], $ret );
|
|
|
|
}
|
|
|
|
|
2010-04-17 21:07:37 +00:00
|
|
|
// done, clean up so we can reuse the group
|
2019-11-22 17:28:51 +00:00
|
|
|
$this->referenceStack->deleteGroup( $group );
|
2011-02-22 00:07:21 +00:00
|
|
|
|
2008-06-06 20:38:04 +00:00
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Format a single entry for the referencesFormat() function
|
|
|
|
*
|
2019-11-22 17:28:51 +00:00
|
|
|
* @param string|int $key The key of the reference
|
|
|
|
* @param array $val A single reference as documented at {@see ReferenceStack::$refs}
|
2019-11-18 12:36:25 +00:00
|
|
|
* @return string Wikitext, wrapped in a single <li> element
|
2008-06-06 20:38:04 +00:00
|
|
|
*/
|
2019-11-18 12:36:25 +00:00
|
|
|
private function referencesFormatEntry( $key, array $val ) {
|
2012-01-04 15:00:01 +00:00
|
|
|
$text = $this->referenceText( $key, $val['text'] );
|
2019-11-21 13:25:33 +00:00
|
|
|
$error = '';
|
|
|
|
$extraAttributes = '';
|
|
|
|
|
|
|
|
if ( isset( $val['dir'] ) ) {
|
|
|
|
$dir = strtolower( $val['dir'] );
|
|
|
|
if ( in_array( $dir, [ 'ltr', 'rtl' ] ) ) {
|
|
|
|
$extraAttributes = Html::expandAttributes( [ 'class' => 'mw-cite-dir-' . $dir ] );
|
|
|
|
} else {
|
2019-11-22 10:43:09 +00:00
|
|
|
$error .= $this->errorReporter->plain( 'cite_error_ref_invalid_dir', $val['dir'] ) . "\n";
|
2019-11-21 13:25:33 +00:00
|
|
|
}
|
|
|
|
}
|
2019-11-18 13:42:48 +00:00
|
|
|
|
|
|
|
// Fallback for a broken, and therefore unprocessed follow="…". Note this returns a <p>, not
|
|
|
|
// an <li> as expected!
|
2012-01-04 15:00:01 +00:00
|
|
|
if ( isset( $val['follow'] ) ) {
|
2012-08-30 08:41:27 +00:00
|
|
|
return wfMessage(
|
2019-11-18 13:42:48 +00:00
|
|
|
'cite_references_no_link',
|
2019-11-28 14:35:23 +00:00
|
|
|
$this->citeKeyFormatter->normalizeKey(
|
|
|
|
$this->citeKeyFormatter->getReferencesKey( $val['follow'] )
|
2019-11-18 13:42:48 +00:00
|
|
|
),
|
|
|
|
$text
|
|
|
|
)->inContentLanguage()->plain();
|
2011-02-03 21:40:55 +00:00
|
|
|
}
|
2019-11-18 13:42:48 +00:00
|
|
|
|
2019-11-18 14:01:00 +00:00
|
|
|
// This counts the number of reuses. 0 means the reference appears only 1 time.
|
2019-11-21 16:23:22 +00:00
|
|
|
if ( isset( $val['count'] ) && $val['count'] < 1 ) {
|
2019-11-18 14:01:00 +00:00
|
|
|
// Anonymous, auto-numbered references can't be reused and get marked with a -1.
|
|
|
|
if ( $val['count'] < 0 ) {
|
|
|
|
$id = $val['key'];
|
2019-11-28 14:35:23 +00:00
|
|
|
$backlinkId = $this->citeKeyFormatter->refKey( $val['key'] );
|
2019-11-18 14:01:00 +00:00
|
|
|
} else {
|
|
|
|
$id = $key . '-' . $val['key'];
|
2019-11-28 14:35:23 +00:00
|
|
|
$backlinkId = $this->citeKeyFormatter->refKey( $key, $val['key'] . '-' . $val['count'] );
|
2019-11-18 14:01:00 +00:00
|
|
|
}
|
2012-08-30 08:41:27 +00:00
|
|
|
return wfMessage(
|
2019-11-18 13:42:48 +00:00
|
|
|
'cite_references_link_one',
|
2019-11-28 14:35:23 +00:00
|
|
|
$this->citeKeyFormatter->normalizeKey( $this->citeKeyFormatter->getReferencesKey( $id ) ),
|
|
|
|
$this->citeKeyFormatter->normalizeKey( $backlinkId ),
|
2019-11-21 13:25:33 +00:00
|
|
|
$text . $error,
|
|
|
|
$extraAttributes
|
2019-11-18 13:42:48 +00:00
|
|
|
)->inContentLanguage()->plain();
|
2016-02-24 23:54:17 +00:00
|
|
|
}
|
2019-11-18 14:01:00 +00:00
|
|
|
|
2008-06-06 20:38:04 +00:00
|
|
|
// Named references with >1 occurrences
|
2019-11-18 13:42:48 +00:00
|
|
|
$backlinks = [];
|
2019-11-21 16:23:22 +00:00
|
|
|
// There is no count in case of a section preview
|
|
|
|
for ( $i = 0; $i <= ( $val['count'] ?? -1 ); $i++ ) {
|
2019-11-18 13:42:48 +00:00
|
|
|
$backlinks[] = wfMessage(
|
|
|
|
'cite_references_link_many_format',
|
2019-11-28 14:35:23 +00:00
|
|
|
$this->citeKeyFormatter->normalizeKey(
|
|
|
|
$this->citeKeyFormatter->refKey( $key, $val['key'] . '-' . $i )
|
2019-11-21 16:23:22 +00:00
|
|
|
),
|
|
|
|
$this->referencesFormatEntryNumericBacklinkLabel(
|
|
|
|
$val['number'],
|
|
|
|
$i,
|
|
|
|
$val['count']
|
2019-11-18 13:42:48 +00:00
|
|
|
),
|
|
|
|
$this->referencesFormatEntryAlternateBacklinkLabel( $i )
|
2016-02-24 23:54:17 +00:00
|
|
|
)->inContentLanguage()->plain();
|
|
|
|
}
|
2019-11-21 16:23:22 +00:00
|
|
|
return wfMessage(
|
|
|
|
'cite_references_link_many',
|
2019-11-28 14:35:23 +00:00
|
|
|
$this->citeKeyFormatter->normalizeKey(
|
|
|
|
$this->citeKeyFormatter->getReferencesKey( $key . '-' . ( $val['key'] ?? '' ) )
|
2019-11-18 13:42:48 +00:00
|
|
|
),
|
|
|
|
$this->listToText( $backlinks ),
|
2019-11-21 13:25:33 +00:00
|
|
|
$text . $error,
|
|
|
|
$extraAttributes
|
2019-11-18 13:42:48 +00:00
|
|
|
)->inContentLanguage()->plain();
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
|
|
|
|
2012-01-04 15:00:01 +00:00
|
|
|
/**
|
|
|
|
* Returns formatted reference text
|
2019-11-25 11:42:31 +00:00
|
|
|
* @param string|int $key
|
2018-11-19 15:39:34 +00:00
|
|
|
* @param string|null $text
|
|
|
|
* @return string
|
2012-01-04 15:00:01 +00:00
|
|
|
*/
|
2016-09-21 11:01:25 +00:00
|
|
|
private function referenceText( $key, $text ) {
|
2019-11-20 14:44:12 +00:00
|
|
|
if ( trim( $text ) === '' ) {
|
2019-11-22 22:17:23 +00:00
|
|
|
if ( $this->isSectionPreview ) {
|
2019-11-22 10:43:09 +00:00
|
|
|
return $this->errorReporter->plain( 'cite_warning_sectionpreview_no_text', $key );
|
2016-02-18 06:50:04 +00:00
|
|
|
}
|
2019-11-22 10:43:09 +00:00
|
|
|
return $this->errorReporter->plain( 'cite_error_references_no_text', $key );
|
2012-01-04 15:00:01 +00:00
|
|
|
}
|
|
|
|
return '<span class="reference-text">' . rtrim( $text, "\n" ) . "</span>\n";
|
|
|
|
}
|
|
|
|
|
2008-06-06 20:38:04 +00:00
|
|
|
/**
|
|
|
|
* Generate a numeric backlink given a base number and an
|
|
|
|
* offset, e.g. $base = 1, $offset = 2; = 1.2
|
|
|
|
* Since bug #5525, it correctly does 1.9 -> 1.10 as well as 1.099 -> 1.100
|
|
|
|
*
|
2017-12-28 14:55:49 +00:00
|
|
|
* @param int $base
|
|
|
|
* @param int $offset
|
2008-06-06 20:38:04 +00:00
|
|
|
* @param int $max Maximum value expected.
|
|
|
|
* @return string
|
|
|
|
*/
|
2016-09-21 11:01:25 +00:00
|
|
|
private function referencesFormatEntryNumericBacklinkLabel( $base, $offset, $max ) {
|
2008-06-06 20:38:04 +00:00
|
|
|
$scope = strlen( $max );
|
2019-09-02 18:53:09 +00:00
|
|
|
$ret = MediaWikiServices::getInstance()->getContentLanguage()->formatNum(
|
2010-04-17 21:07:37 +00:00
|
|
|
sprintf( "%s.%0{$scope}s", $base, $offset )
|
2008-06-06 20:38:04 +00:00
|
|
|
);
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate a custom format backlink given an offset, e.g.
|
2017-01-07 09:08:35 +00:00
|
|
|
* $offset = 2; = c if $this->mBacklinkLabels = [ 'a',
|
|
|
|
* 'b', 'c', ...]. Return an error if the offset > the # of
|
2008-06-06 20:38:04 +00:00
|
|
|
* array items
|
|
|
|
*
|
2017-12-28 14:55:49 +00:00
|
|
|
* @param int $offset
|
2008-06-06 20:38:04 +00:00
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
2016-09-21 11:01:25 +00:00
|
|
|
private function referencesFormatEntryAlternateBacklinkLabel( $offset ) {
|
2008-06-06 20:38:04 +00:00
|
|
|
if ( !isset( $this->mBacklinkLabels ) ) {
|
|
|
|
$this->genBacklinkLabels();
|
|
|
|
}
|
2019-10-25 08:19:08 +00:00
|
|
|
return $this->mBacklinkLabels[$offset]
|
2019-11-22 10:43:09 +00:00
|
|
|
?? $this->errorReporter->plain( 'cite_error_references_no_backlink_label', null );
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This does approximately the same thing as
|
|
|
|
* Language::listToText() but due to this being used for a
|
|
|
|
* slightly different purpose (people might not want , as the
|
2008-09-15 20:28:25 +00:00
|
|
|
* first separator and not 'and' as the second, and this has to
|
2008-06-06 20:38:04 +00:00
|
|
|
* use messages from the content language) I'm rolling my own.
|
|
|
|
*
|
2018-11-19 15:39:34 +00:00
|
|
|
* @param string[] $arr The array to format
|
2008-06-06 20:38:04 +00:00
|
|
|
* @return string
|
|
|
|
*/
|
2019-10-17 07:21:22 +00:00
|
|
|
private function listToText( array $arr ) {
|
2019-10-25 08:17:05 +00:00
|
|
|
$lastElement = array_pop( $arr );
|
|
|
|
|
|
|
|
if ( $arr === [] ) {
|
|
|
|
return (string)$lastElement;
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
2018-11-19 15:40:39 +00:00
|
|
|
|
|
|
|
$sep = wfMessage( 'cite_references_link_many_sep' )->inContentLanguage()->plain();
|
|
|
|
$and = wfMessage( 'cite_references_link_many_and' )->inContentLanguage()->plain();
|
2019-10-25 08:17:05 +00:00
|
|
|
return implode( $sep, $arr ) . $and . $lastElement;
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate the labels to pass to the
|
|
|
|
* 'cite_references_link_many_format' message, the format is an
|
2018-11-19 15:36:01 +00:00
|
|
|
* arbitrary number of tokens separated by whitespace.
|
2008-06-06 20:38:04 +00:00
|
|
|
*/
|
2016-09-21 11:01:25 +00:00
|
|
|
private function genBacklinkLabels() {
|
2012-08-30 08:41:27 +00:00
|
|
|
$text = wfMessage( 'cite_references_link_many_format_backlink_labels' )
|
|
|
|
->inContentLanguage()->plain();
|
2018-11-19 15:36:01 +00:00
|
|
|
$this->mBacklinkLabels = preg_split( '/\s+/', $text );
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets run when Parser::clearState() gets run, since we don't
|
|
|
|
* want the counts to transcend pages and other instances
|
2019-11-19 11:01:10 +00:00
|
|
|
*
|
|
|
|
* @param string $force Set to "force" to interrupt parsing
|
2008-06-06 20:38:04 +00:00
|
|
|
*/
|
2019-11-19 11:01:10 +00:00
|
|
|
public function clearState( $force = '' ) {
|
|
|
|
if ( $force === 'force' ) {
|
|
|
|
$this->mInCite = false;
|
2019-11-19 13:34:19 +00:00
|
|
|
$this->inReferencesGroup = null;
|
|
|
|
} elseif ( $this->mInCite || $this->inReferencesGroup !== null ) {
|
2019-11-19 11:01:10 +00:00
|
|
|
// Don't clear when we're in the middle of parsing a <ref> or <references> tag
|
2018-05-15 08:40:58 +00:00
|
|
|
return;
|
2011-02-22 00:07:21 +00:00
|
|
|
}
|
2019-11-22 17:28:51 +00:00
|
|
|
if ( $this->referenceStack ) {
|
|
|
|
$this->referenceStack->clear();
|
|
|
|
}
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|
|
|
|
|
2009-01-26 18:02:28 +00:00
|
|
|
/**
|
2015-08-06 17:33:01 +00:00
|
|
|
* Called at the end of page processing to append a default references
|
|
|
|
* section, if refs were used without a main references tag. If there are references
|
|
|
|
* in a custom group, and there is no references tag for it, show an error
|
|
|
|
* message for that group.
|
2014-05-18 23:06:44 +00:00
|
|
|
* If we are processing a section preview, this adds the missing
|
|
|
|
* references tags and does not add the errors.
|
2011-05-28 20:44:24 +00:00
|
|
|
*
|
2015-10-26 14:44:02 +00:00
|
|
|
* @param bool $afterParse True if called from the ParserAfterParse hook
|
2019-11-04 16:00:49 +00:00
|
|
|
* @param ParserOptions $parserOptions
|
2017-10-06 19:22:30 +00:00
|
|
|
* @param string &$text
|
2009-01-26 18:02:28 +00:00
|
|
|
*/
|
2019-11-12 11:52:55 +00:00
|
|
|
public function checkRefsNoReferences(
|
|
|
|
$afterParse,
|
|
|
|
ParserOptions $parserOptions,
|
|
|
|
&$text
|
|
|
|
) {
|
Implement responsive columns for reference lists
This is based on the popular 'count' parameter from Template:Reflist on
English Wikipedia, which has also been adopted by many other wikis.
That template's 'count' parameter allows maximum flexibility on a per-
page basis. This was important because the template can't know how many
references the list will contain. Users typically manually add (and
later, increment) the 'count' parameter when the list exceeds a certain
threshold.
The template currently sets an exact column count (via the CSS3
property `column-count`).
This patch improves on that by instead using the closely related CSS3
`column-width` property. This automatically derives the column count
based on the available space in the browser window. It will thus create
two or three columns on a typical desktop screen, and two or no columns
on a mobile device.
The specified width is the minimum width of a column. This ensures that
the list is not split when rendered on a narrow screen or mobile device.
It also hooks into the raw list before parsing and adds the class only
when the list will contain more than a certain number of items. This
prevents very short lists from being split into multiple columns.
Templates like Template:Reflist on English Wikipedia currently are not
able to set inline styles on the list element directly, which is why
they set it on a `<div>` wrapping the `<references />` output. Because
of this, the feature of the Cite extension must not be enabled at the
same time, as that would result in both the template's wrapper and the
references list being split. The end result would involve sitations with
three columns split in four sub-columns, creating a complicated mess of
nine intermixed columns.
To provide a smooth migration for wikis, this feature can be disabled by
default using `$wgCiteResponsiveReferences = false`. Each individual
template createing reference list can then be migrated, by removing the
wrapper column styles and instead settting the new "responsive"
attribute, like so: `<references responsive />`.
Once any conflicting templates have been migrated, the default for the
wiki can be swapped by setting `$wgCiteResponsiveReferences = true`.
If wikis wish for some templates to keep their custom column splitting
behaviour, templates can also opt-out by setting `responsive="0"`, which
will make sure that it will keep behaving the current way even after the
feature becomes enabled by default for the wiki.
In summary, when disabled by default, pages can opt into this system
with `<references responsive />`. When enabled by default, pages can opt
out of the system with `<references responsive=0 />`.
* Deprecate cite_references_prefix/cite_references_suffix.
This message is rarely used and opens up compatibility hazards.
It was already removed by Parsoid, but the PHP implementation
still had it. It's typically used to add inline styles to the
wrapper which is more appropiately done in Common.css (or
obsoleted as part of the skin or Cite extenion itself nowadays
depending on what style in question).
It was also a HTML-style message with separated open and close
segments, which is an anti-pattern in itself.
* Declare module target explicitly and include mobile. The absence of
this stylesheet caused subtle BiDi/RTL bugs on mobile.
Bug: T33597
Change-Id: Ia535f9b722e825e71e792b36356febc3bd444387
2015-07-21 02:33:50 +00:00
|
|
|
global $wgCiteResponsiveReferences;
|
2015-06-08 14:05:06 +00:00
|
|
|
|
|
|
|
if ( $afterParse ) {
|
|
|
|
$this->mHaveAfterParse = true;
|
|
|
|
} elseif ( $this->mHaveAfterParse ) {
|
2018-05-15 08:40:58 +00:00
|
|
|
return;
|
2011-05-31 17:49:22 +00:00
|
|
|
}
|
2011-09-14 15:07:20 +00:00
|
|
|
|
2016-02-06 12:24:58 +00:00
|
|
|
$s = '';
|
2019-11-22 17:28:51 +00:00
|
|
|
if ( $this->referenceStack ) {
|
|
|
|
foreach ( $this->referenceStack->getGroups() as $group ) {
|
2019-11-22 22:17:23 +00:00
|
|
|
if ( $group === self::DEFAULT_GROUP || $parserOptions->getIsSectionPreview() ) {
|
2019-11-22 17:28:51 +00:00
|
|
|
$this->inReferencesGroup = $group;
|
|
|
|
$s .= $this->referencesFormat( $group, $wgCiteResponsiveReferences );
|
|
|
|
$this->inReferencesGroup = null;
|
|
|
|
} else {
|
|
|
|
$s .= "\n<br />" .
|
|
|
|
$this->errorReporter->halfParsed(
|
|
|
|
'cite_error_group_refs_without_references',
|
|
|
|
Sanitizer::safeEncodeAttribute( $group )
|
|
|
|
);
|
|
|
|
}
|
2009-01-26 18:02:28 +00:00
|
|
|
}
|
|
|
|
}
|
2019-11-22 22:17:23 +00:00
|
|
|
if ( $parserOptions->getIsSectionPreview() && $s !== '' ) {
|
2016-02-08 16:02:47 +00:00
|
|
|
// provide a preview of references in its own section
|
|
|
|
$text .= "\n" . '<div class="mw-ext-cite-cite_section_preview_references" >';
|
|
|
|
$headerMsg = wfMessage( 'cite_section_preview_references' );
|
|
|
|
if ( !$headerMsg->isDisabled() ) {
|
|
|
|
$text .= '<h2 id="mw-ext-cite-cite_section_preview_references_header" >'
|
|
|
|
. $headerMsg->escaped()
|
|
|
|
. '</h2>';
|
|
|
|
}
|
|
|
|
$text .= $s . '</div>';
|
2016-02-06 12:24:58 +00:00
|
|
|
} else {
|
|
|
|
$text .= $s;
|
|
|
|
}
|
2009-01-26 18:02:28 +00:00
|
|
|
}
|
2011-09-14 15:07:20 +00:00
|
|
|
|
2008-06-06 20:38:04 +00:00
|
|
|
}
|