Special:Log: Convert to HTMLForm
* All Xml generation code has been removed. * The LogEventsListGetExtraInputs hook now needs a form descriptor array and not plain HTML. See I37e0d3e81a46239750465b9299279fbbd7c7f87a. * LogPager and LogEventList also take the $day parameter for 'From date (and earlier)' and pass it to getDateCond as well. * Since FormOptions can't automatically extract the date from the request this is being done manually in the execute method of Special:Log using MWTimestamp. Bug: T117737 Change-Id: Iba3c6aa5ac40dcdee0792c2d045b238b02d76521
This commit is contained in:
parent
1d17626dc2
commit
38756eae46
7 changed files with 148 additions and 132 deletions
|
|
@ -179,6 +179,8 @@ because of Phabricator reports.
|
|||
CapsuleMultiselectWidget. The following methods may no longer be used:
|
||||
* setItemsFromData: Use setValue instead
|
||||
* getItemsData: Use getItems instead and get the data property
|
||||
* The hook 'LogEventsListGetExtraInputs' now needs a form descriptor array
|
||||
and not plain HTML.
|
||||
|
||||
=== Deprecations in 1.32 ===
|
||||
* Use of a StartProfiler.php file is deprecated in favour of placing
|
||||
|
|
|
|||
|
|
@ -2182,7 +2182,7 @@ $autocreated: Boolean, whether this was an auto-creation
|
|||
Special:Log for a specific log type
|
||||
$type: String of log type being displayed
|
||||
$logEventsList: LogEventsList object for context and access to the WebRequest
|
||||
&$input: string HTML of an input element
|
||||
&$formDescriptor: array HTMLForm's form descriptor
|
||||
|
||||
'LogEventsListShowLogExtract': Called before the string is added to OutputPage.
|
||||
Returning false will prevent the string from being added to the OutputPage.
|
||||
|
|
|
|||
|
|
@ -101,99 +101,94 @@ class LogEventsList extends ContextSource {
|
|||
* @param int|string $year Use 0 to start with no year preselected.
|
||||
* @param int|string $month A month in the 1..12 range. Use 0 to start with no month
|
||||
* preselected.
|
||||
* @param int|string $day A day in the 1..31 range. Use 0 to start with no month
|
||||
* preselected.
|
||||
* @param array|null $filter
|
||||
* @param string $tagFilter Tag to select by default
|
||||
* @param string|null $action
|
||||
*/
|
||||
public function showOptions( $types = [], $user = '', $page = '', $pattern = false, $year = 0,
|
||||
$month = 0, $filter = null, $tagFilter = '', $action = null
|
||||
$month = 0, $day = 0, $filter = null, $tagFilter = '', $action = null
|
||||
) {
|
||||
global $wgScript, $wgMiserMode;
|
||||
|
||||
$title = SpecialPage::getTitleFor( 'Log' );
|
||||
|
||||
// For B/C, we take strings, but make sure they are converted...
|
||||
$types = ( $types === '' ) ? [] : (array)$types;
|
||||
|
||||
$tagSelector = ChangeTags::buildTagFilterSelector( $tagFilter, false, $this->getContext() );
|
||||
|
||||
$html = Html::hidden( 'title', $title->getPrefixedDBkey() );
|
||||
$formDescriptor = [];
|
||||
|
||||
// Basic selectors
|
||||
$html .= $this->getTypeMenu( $types ) . "\n";
|
||||
$html .= $this->getUserInput( $user ) . "\n";
|
||||
$html .= $this->getTitleInput( $page ) . "\n";
|
||||
$html .= $this->getExtraInputs( $types ) . "\n";
|
||||
$formDescriptor['type'] = $this->getTypeMenuDesc( $types );
|
||||
$formDescriptor['user'] = $this->getUserInputDesc( $user );
|
||||
$formDescriptor['page'] = $this->getTitleInputDesc( $title );
|
||||
|
||||
// Add extra inputs if any
|
||||
$extraInputsDescriptor = $this->getExtraInputsDesc( $types );
|
||||
if ( !empty( $extraInputsDescriptor ) ) {
|
||||
$formDescriptor[ 'extra' ] = $extraInputsDescriptor;
|
||||
}
|
||||
|
||||
// Title pattern, if allowed
|
||||
if ( !$wgMiserMode ) {
|
||||
$html .= $this->getTitlePattern( $pattern ) . "\n";
|
||||
if ( !$this->getConfig()->get( 'MiserMode' ) ) {
|
||||
$formDescriptor['pattern'] = $this->getTitlePatternDesc( $pattern );
|
||||
}
|
||||
|
||||
// date menu
|
||||
$html .= Xml::tags( 'p', null, Xml::dateMenu( (int)$year, (int)$month ) );
|
||||
// Date menu
|
||||
$formDescriptor['date'] = [
|
||||
'type' => 'date',
|
||||
'label-message' => 'date'
|
||||
];
|
||||
|
||||
// Tag filter
|
||||
if ( $tagSelector ) {
|
||||
$html .= Xml::tags( 'p', null, implode( "\u{00A0}", $tagSelector ) );
|
||||
}
|
||||
$formDescriptor['tagfilter'] = [
|
||||
'type' => 'tagfilter',
|
||||
'name' => 'tagfilter',
|
||||
'label-raw' => $this->msg( 'tag-filter' )->parse(),
|
||||
];
|
||||
|
||||
// Filter links
|
||||
if ( $filter ) {
|
||||
$html .= Xml::tags( 'p', null, $this->getFilterLinks( $filter ) );
|
||||
$formDescriptor['filters'] = $this->getFiltersDesc( $filter );
|
||||
}
|
||||
|
||||
// Action filter
|
||||
if ( $action !== null ) {
|
||||
$html .= Xml::tags( 'p', null, $this->getActionSelector( $types, $action ) );
|
||||
if (
|
||||
$action !== null &&
|
||||
$this->allowedActions !== null &&
|
||||
count( $this->allowedActions ) > 0
|
||||
) {
|
||||
$formDescriptor['subtype'] = $this->getActionSelectorDesc( $types, $action );
|
||||
}
|
||||
|
||||
// Submit button
|
||||
$html .= Xml::submitButton( $this->msg( 'logeventslist-submit' )->text() );
|
||||
$htmlForm = new HTMLForm( $formDescriptor, $this->getContext() );
|
||||
$htmlForm
|
||||
->setSubmitText( $this->msg( 'logeventslist-submit' )->text() )
|
||||
->setWrapperLegendMsg( 'log' );
|
||||
|
||||
// Fieldset
|
||||
$html = Xml::fieldset( $this->msg( 'log' )->text(), $html );
|
||||
|
||||
// Form wrapping
|
||||
$html = Xml::tags( 'form', [ 'action' => $wgScript, 'method' => 'get' ], $html );
|
||||
|
||||
$this->getOutput()->addHTML( $html );
|
||||
$htmlForm->prepareForm()->displayForm( false );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $filter
|
||||
* @return string Formatted HTML
|
||||
* @return array Form descriptor
|
||||
*/
|
||||
private function getFilterLinks( $filter ) {
|
||||
// show/hide links
|
||||
$messages = [ $this->msg( 'show' )->text(), $this->msg( 'hide' )->text() ];
|
||||
// Option value -> message mapping
|
||||
$links = [];
|
||||
$hiddens = ''; // keep track for "go" button
|
||||
$linkRenderer = $this->getLinkRenderer();
|
||||
private function getFiltersDesc( $filter ) {
|
||||
$options = [];
|
||||
$default = [];
|
||||
foreach ( $filter as $type => $val ) {
|
||||
// Should the below assignment be outside the foreach?
|
||||
// Then it would have to be copied. Not certain what is more expensive.
|
||||
$query = $this->getDefaultQuery();
|
||||
$queryKey = "hide_{$type}_log";
|
||||
$options[ $this->msg( "logeventslist-{$type}-log" )->text() ] = $type;
|
||||
|
||||
$hideVal = $val ? 0 : 1;
|
||||
$query[$queryKey] = $hideVal;
|
||||
|
||||
$link = $linkRenderer->makeKnownLink(
|
||||
$this->getTitle(),
|
||||
$messages[$hideVal],
|
||||
[],
|
||||
$query
|
||||
);
|
||||
|
||||
// Message: log-show-hide-patrol
|
||||
$links[$type] = $this->msg( "log-show-hide-{$type}" )->rawParams( $link )->escaped();
|
||||
$hiddens .= Html::hidden( "hide_{$type}_log", $val ) . "\n";
|
||||
if ( $val === 0 ) {
|
||||
$default[] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
// Build links
|
||||
return '<small>' . $this->getLanguage()->pipeList( $links ) . '</small>' . $hiddens;
|
||||
return [
|
||||
'class' => 'HTMLMultiSelectField',
|
||||
'label-message' => 'logeventslist-more-filters',
|
||||
'flatlist' => true,
|
||||
'options' => $options,
|
||||
'default' => $default,
|
||||
];
|
||||
}
|
||||
|
||||
private function getDefaultQuery() {
|
||||
|
|
@ -213,22 +208,11 @@ class LogEventsList extends ContextSource {
|
|||
|
||||
/**
|
||||
* @param array $queryTypes
|
||||
* @return string Formatted HTML
|
||||
* @return array Form descriptor
|
||||
*/
|
||||
private function getTypeMenu( $queryTypes ) {
|
||||
private function getTypeMenuDesc( $queryTypes ) {
|
||||
$queryType = count( $queryTypes ) == 1 ? $queryTypes[0] : '';
|
||||
$selector = $this->getTypeSelector();
|
||||
$selector->setDefault( $queryType );
|
||||
|
||||
return $selector->getHTML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns log page selector.
|
||||
* @return XmlSelect
|
||||
* @since 1.19
|
||||
*/
|
||||
public function getTypeSelector() {
|
||||
$typesByName = []; // Temporary array
|
||||
// First pass to load the log names
|
||||
foreach ( LogPage::validTypes() as $type ) {
|
||||
|
|
@ -247,62 +231,57 @@ class LogEventsList extends ContextSource {
|
|||
unset( $typesByName[''] );
|
||||
$typesByName = [ '' => $public ] + $typesByName;
|
||||
|
||||
$select = new XmlSelect( 'type' );
|
||||
foreach ( $typesByName as $type => $name ) {
|
||||
$select->addOption( $name, $type );
|
||||
}
|
||||
|
||||
return $select;
|
||||
return [
|
||||
'class' => 'HTMLSelectField',
|
||||
'name' => 'type',
|
||||
'options' => array_flip( $typesByName ),
|
||||
'default' => $queryType,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $user
|
||||
* @return string Formatted HTML
|
||||
* @return array Form descriptor
|
||||
*/
|
||||
private function getUserInput( $user ) {
|
||||
$label = Xml::inputLabel(
|
||||
$this->msg( 'specialloguserlabel' )->text(),
|
||||
'user',
|
||||
'mw-log-user',
|
||||
15,
|
||||
$user,
|
||||
[ 'class' => 'mw-autocomplete-user' ]
|
||||
);
|
||||
|
||||
return '<span class="mw-input-with-label">' . $label . '</span>';
|
||||
private function getUserInputDesc( $user ) {
|
||||
return [
|
||||
'class' => 'HTMLUserTextField',
|
||||
'label-message' => 'specialloguserlabel',
|
||||
'name' => 'user',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
* @return string Formatted HTML
|
||||
* @return array Form descriptor
|
||||
*/
|
||||
private function getTitleInput( $title ) {
|
||||
$label = Xml::inputLabel(
|
||||
$this->msg( 'speciallogtitlelabel' )->text(),
|
||||
'page',
|
||||
'mw-log-page',
|
||||
20,
|
||||
$title
|
||||
);
|
||||
|
||||
return '<span class="mw-input-with-label">' . $label . '</span>';
|
||||
private function getTitleInputDesc( $title ) {
|
||||
return [
|
||||
'class' => 'HTMLTitleTextField',
|
||||
'label-message' => 'speciallogtitlelabel',
|
||||
'name' => 'page',
|
||||
'value' => $title,
|
||||
'required' => false
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $pattern
|
||||
* @return string Checkbox
|
||||
* @return array Form descriptor
|
||||
*/
|
||||
private function getTitlePattern( $pattern ) {
|
||||
return '<span class="mw-input-with-label">' .
|
||||
Xml::checkLabel( $this->msg( 'log-title-wildcard' )->text(), 'pattern', 'pattern', $pattern ) .
|
||||
'</span>';
|
||||
private function getTitlePatternDesc( $pattern ) {
|
||||
return [
|
||||
'type' => 'check',
|
||||
'label-message' => 'log-title-wildcard',
|
||||
'name' => 'pattern',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
* @return string
|
||||
* @return array Form descriptor
|
||||
*/
|
||||
private function getExtraInputs( $types ) {
|
||||
private function getExtraInputsDesc( $types ) {
|
||||
if ( count( $types ) == 1 ) {
|
||||
if ( $types[0] == 'suppress' ) {
|
||||
$offender = $this->getRequest()->getVal( 'offender' );
|
||||
|
|
@ -310,42 +289,45 @@ class LogEventsList extends ContextSource {
|
|||
if ( !$user || ( $user->getId() == 0 && !IP::isIPAddress( $offender ) ) ) {
|
||||
$offender = ''; // Blank field if invalid
|
||||
}
|
||||
return Xml::inputLabel( $this->msg( 'revdelete-offender' )->text(), 'offender',
|
||||
'mw-log-offender', 20, $offender );
|
||||
return [
|
||||
'type' => 'text',
|
||||
'label-message' => 'revdelete-offender',
|
||||
'name' => 'offender',
|
||||
'value' => $offender,
|
||||
];
|
||||
} else {
|
||||
// Allow extensions to add their own extra inputs
|
||||
$input = '';
|
||||
Hooks::run( 'LogEventsListGetExtraInputs', [ $types[0], $this, &$input ] );
|
||||
return $input;
|
||||
$formDescriptor = [];
|
||||
Hooks::run( 'LogEventsListGetExtraInputs', [ $types[0], $this, &$formDescriptor ] );
|
||||
return $formDescriptor;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop down menu for selection of actions that can be used to filter the log
|
||||
* @param array $types
|
||||
* @param string $action
|
||||
* @return string
|
||||
* @since 1.27
|
||||
* @return array Form descriptor
|
||||
*/
|
||||
private function getActionSelector( $types, $action ) {
|
||||
if ( $this->allowedActions === null || !count( $this->allowedActions ) ) {
|
||||
return '';
|
||||
}
|
||||
$html = '';
|
||||
$html .= Xml::label( wfMessage( 'log-action-filter-' . $types[0] )->text(),
|
||||
'action-filter-' .$types[0] ) . "\n";
|
||||
$select = new XmlSelect( 'subtype' );
|
||||
$select->addOption( wfMessage( 'log-action-filter-all' )->text(), '' );
|
||||
private function getActionSelectorDesc( $types, $action ) {
|
||||
$actionOptions = [];
|
||||
$actionOptions[ 'log-action-filter-all' ] = '';
|
||||
|
||||
foreach ( $this->allowedActions as $value ) {
|
||||
$msgKey = 'log-action-filter-' . $types[0] . '-' . $value;
|
||||
$select->addOption( wfMessage( $msgKey )->text(), $value );
|
||||
$actionOptions[ $msgKey ] = $value;
|
||||
}
|
||||
$select->setDefault( $action );
|
||||
$html .= $select->getHTML();
|
||||
return $html;
|
||||
|
||||
return [
|
||||
'class' => 'HTMLSelectField',
|
||||
'name' => 'subtype',
|
||||
'options-messages' => $actionOptions,
|
||||
'default' => $action,
|
||||
'label' => $this->msg( 'log-action-filter-' . $types[0] )->text(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -63,13 +63,14 @@ class LogPager extends ReverseChronologicalPager {
|
|||
* @param array $conds Extra conditions for the query
|
||||
* @param int|bool $year The year to start from. Default: false
|
||||
* @param int|bool $month The month to start from. Default: false
|
||||
* @param int|bool $day The day to start from. Default: false
|
||||
* @param string $tagFilter Tag
|
||||
* @param string $action Specific action (subtype) requested
|
||||
* @param int $logId Log entry ID, to limit to a single log entry.
|
||||
*/
|
||||
public function __construct( $list, $types = [], $performer = '', $title = '',
|
||||
$pattern = false, $conds = [], $year = false, $month = false, $tagFilter = '',
|
||||
$action = '', $logId = false
|
||||
$pattern = false, $conds = [], $year = false, $month = false, $day = false,
|
||||
$tagFilter = '', $action = '', $logId = false
|
||||
) {
|
||||
parent::__construct( $list->getContext() );
|
||||
$this->mConds = $conds;
|
||||
|
|
@ -80,7 +81,7 @@ class LogPager extends ReverseChronologicalPager {
|
|||
$this->limitPerformer( $performer );
|
||||
$this->limitTitle( $title, $pattern );
|
||||
$this->limitAction( $action );
|
||||
$this->getDateCond( $year, $month );
|
||||
$this->getDateCond( $year, $month, $day );
|
||||
$this->mTagFilter = $tagFilter;
|
||||
$this->limitLogId( $logId );
|
||||
|
||||
|
|
@ -91,6 +92,7 @@ class LogPager extends ReverseChronologicalPager {
|
|||
$query = parent::getDefaultQuery();
|
||||
$query['type'] = $this->typeCGI; // arrays won't work here
|
||||
$query['user'] = $this->performer;
|
||||
$query['day'] = $this->mDay;
|
||||
$query['month'] = $this->mMonth;
|
||||
$query['year'] = $this->mYear;
|
||||
|
||||
|
|
@ -104,8 +106,12 @@ class LogPager extends ReverseChronologicalPager {
|
|||
if ( count( $this->types ) ) {
|
||||
return $filters;
|
||||
}
|
||||
|
||||
$request_filters = $this->getRequest()->getArray( "wpfilters" );
|
||||
$request_filters = $request_filters === null ? [] : $request_filters;
|
||||
|
||||
foreach ( $wgFilterLogTypes as $type => $default ) {
|
||||
$hide = $this->getRequest()->getBool( "hide_{$type}_log", $default );
|
||||
$hide = !in_array( $type, $request_filters );
|
||||
|
||||
$filters[$type] = $hide;
|
||||
if ( $hide ) {
|
||||
|
|
@ -413,6 +419,10 @@ class LogPager extends ReverseChronologicalPager {
|
|||
return $this->mMonth;
|
||||
}
|
||||
|
||||
public function getDay() {
|
||||
return $this->mDay;
|
||||
}
|
||||
|
||||
public function getTagFilter() {
|
||||
return $this->mTagFilter;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ class SpecialLog extends SpecialPage {
|
|||
$opts->add( 'pattern', false );
|
||||
$opts->add( 'year', null, FormOptions::INTNULL );
|
||||
$opts->add( 'month', null, FormOptions::INTNULL );
|
||||
$opts->add( 'day', null, FormOptions::INTNULL );
|
||||
$opts->add( 'tagfilter', '' );
|
||||
$opts->add( 'offset', '' );
|
||||
$opts->add( 'dir', '' );
|
||||
|
|
@ -59,6 +60,17 @@ class SpecialLog extends SpecialPage {
|
|||
$this->parseParams( $opts, (string)$par );
|
||||
}
|
||||
|
||||
// Set date values
|
||||
$dateString = $this->getRequest()->getVal( 'wpdate' );
|
||||
if ( !empty( $dateString ) ) {
|
||||
$dateStamp = MWTimestamp::getInstance( $dateString . ' 00:00:00' );
|
||||
$dateStamp->setTimezone( $this->getConfig()->get( 'Localtimezone' ) );
|
||||
|
||||
$opts->setValue( 'year', (int)$dateStamp->format( 'Y' ) );
|
||||
$opts->setValue( 'month', (int)$dateStamp->format( 'm' ) );
|
||||
$opts->setValue( 'day', (int)$dateStamp->format( 'd' ) );
|
||||
}
|
||||
|
||||
# Don't let the user get stuck with a certain date
|
||||
if ( $opts->getValue( 'offset' ) || $opts->getValue( 'dir' ) == 'prev' ) {
|
||||
$opts->setValue( 'year', '' );
|
||||
|
|
@ -214,6 +226,7 @@ class SpecialLog extends SpecialPage {
|
|||
$extraConds,
|
||||
$opts->getValue( 'year' ),
|
||||
$opts->getValue( 'month' ),
|
||||
$opts->getValue( 'day' ),
|
||||
$opts->getValue( 'tagfilter' ),
|
||||
$opts->getValue( 'subtype' ),
|
||||
$opts->getValue( 'logid' )
|
||||
|
|
@ -235,6 +248,7 @@ class SpecialLog extends SpecialPage {
|
|||
$pager->getPattern(),
|
||||
$pager->getYear(),
|
||||
$pager->getMonth(),
|
||||
$pager->getDay(),
|
||||
$pager->getFilterParams(),
|
||||
$pager->getTagFilter(),
|
||||
$pager->getAction()
|
||||
|
|
|
|||
|
|
@ -2136,6 +2136,9 @@
|
|||
"speciallogtitlelabel": "Target (title or {{ns:user}}:username for user):",
|
||||
"log": "Logs",
|
||||
"logeventslist-submit": "Show",
|
||||
"logeventslist-more-filters": "More filters:",
|
||||
"logeventslist-patrol-log": "Patrol log",
|
||||
"logeventslist-tag-log": "Tag log",
|
||||
"all-logs-page": "All public logs",
|
||||
"alllogstext": "Combined display of all available logs of {{SITENAME}}.\nYou can narrow down the view by selecting a log type, the username (case-sensitive), or the affected page (also case-sensitive).",
|
||||
"logempty": "No matching items in log.",
|
||||
|
|
@ -2506,6 +2509,7 @@
|
|||
"uctop": "(current)",
|
||||
"month": "From month (and earlier):",
|
||||
"year": "From year (and earlier):",
|
||||
"date": "From date (and earlier):",
|
||||
"sp-contributions-newbies": "Show contributions of new accounts only",
|
||||
"sp-contributions-newbies-sub": "For new accounts",
|
||||
"sp-contributions-newbies-title": "User contributions for new accounts",
|
||||
|
|
|
|||
|
|
@ -2336,6 +2336,9 @@
|
|||
"speciallogtitlelabel": "Used in [[Special:Log]] as a label for an input field with which the log can be filtered. This filter selects for pages or users on which a log action was performed.",
|
||||
"log": "{{doc-special|Log}}\n{{Identical|Log}}",
|
||||
"logeventslist-submit": "Submit button on [[Special:Log]]\n{{Identical|Show}}",
|
||||
"logeventslist-more-filters": "More filters label on [[Special:Log]]",
|
||||
"logeventslist-patrol-log": "Patrol log option label on [[Special:Log]]",
|
||||
"logeventslist-tag-log": "Patrol log option label on [[Special:Log]]",
|
||||
"all-logs-page": "{{doc-logpage}}\nTitle of [[Special:Log]].",
|
||||
"alllogstext": "Header of [[Special:Log]]",
|
||||
"logempty": "Used as warning when there are no items to show.",
|
||||
|
|
@ -2706,6 +2709,7 @@
|
|||
"uctop": "This message is used in [[Special:Contributions]]. It is used to show that a particular edit was the last made to a page. Example: 09:57, 11 February 2008 (hist) (diff) Pagename (edit summary) (current)\n{{Identical|Current}}",
|
||||
"month": "Used in [[Special:Contributions]] and history pages ([{{fullurl:Sandbox|action=history}} example]), as label for a dropdown box to select a specific month to view the edits made in that month, and the earlier months. See also {{msg-mw|year}}.",
|
||||
"year": "Used in [[Special:Contributions]] and history pages ([{{fullurl:Sandbox|action=history}} example]), as label for an input box to select a specific year to view the edits made in that year, and the earlier years.\n\nSee also:\n* {{msg-mw|month}}",
|
||||
"date": "Used in [[Special:Contributions]] and history pages ([{{fullurl:Sandbox|action=history}} example]), as label for an input box to select a specific date to view the edits made on that date, and earlier.",
|
||||
"sp-contributions-newbies": "Text of radio button on special page [[Special:Contributions]].",
|
||||
"sp-contributions-newbies-sub": "Note at the top of the page of results for a search on [[Special:Contributions]] where 'Show contributions for new accounts only' has been selected.",
|
||||
"sp-contributions-newbies-title": "The page title in your browser bar, but not the page title.\n\nSee also:\n* {{msg-mw|Sp-contributions-newbies-sub}}",
|
||||
|
|
|
|||
Loading…
Reference in a new issue