** dty (डोटेली/Doteli), thanks to translators जनक राज भट्ट, बिप्लब आनन्द,
मेश सिंह बोहरा, and राम प्रसाद जोशी
** luz (لئری دوٙمینی / Southern Luri)
+** olo (Livvinкarjala / Livvi-Karelian), thanks to translators Denö, Hiloin Natoi,
+ Ilja.mos, and Mashoi7
=== Other changes in 1.26 ===
* ChangeTags::tagDescription() will return false if the interface message
$title = $this->processTitle( $pageInfo['title'],
isset( $pageInfo['ns'] ) ? $pageInfo['ns'] : null );
- if ( !$title ) {
+ // $title is either an array of two titles or false.
+ if ( is_array( $title ) ) {
+ $this->pageCallback( $title );
+ list( $pageInfo['_title'], $foreignTitle ) = $title;
+ } else {
$badTitle = true;
$skip = true;
}
-
- $this->pageCallback( $title );
- list( $pageInfo['_title'], $foreignTitle ) = $title;
}
if ( $title ) {
}
}
- $this->pageOutCallback( $pageInfo['_title'], $foreignTitle,
+ // @note $pageInfo is only set if a valid $title is processed above with
+ // no error. If we have a valid $title, then pageCallback is called
+ // above, $pageInfo['title'] is set and we do pageOutCallback here.
+ // If $pageInfo['_title'] is not set, then $foreignTitle is also not
+ // set since they both come from $title above.
+ if ( array_key_exists( '_title', $pageInfo ) ) {
+ $this->pageOutCallback( $pageInfo['_title'], $foreignTitle,
$pageInfo['revisionCount'],
$pageInfo['successfulRevisionCount'],
$pageInfo );
+ }
}
/**
foreach ( (array)$bases as $base ) {
// Make hostname
// If we have an access key, use that too (ProjectHoneypot, etc.)
+ $basename = $base;
if ( is_array( $base ) ) {
if ( count( $base ) >= 2 ) {
// Access key is 1, base URL is 0
} else {
$host = "$ipReversed.{$base[0]}";
}
+ $basename = $base[0];
} else {
$host = "$ipReversed.$base";
}
$ipList = gethostbynamel( $host );
if ( $ipList ) {
- wfDebugLog( 'dnsblacklist', "Hostname $host is {$ipList[0]}, it's a proxy says $base!" );
+ wfDebugLog( 'dnsblacklist', "Hostname $host is {$ipList[0]}, it's a proxy says $basename!" );
$found = true;
break;
} else {
- wfDebugLog( 'dnsblacklist', "Requested $host, not found in $base." );
+ wfDebugLog( 'dnsblacklist', "Requested $host, not found in $basename." );
}
}
}
// Further down are some assumptions that $block is a 0-indexed array
// with (count-1) as last key. Let's make sure it is.
$block = array_values( $block );
+ if ( empty( $block ) ) {
+ // if we can't show anything, don't display this block altogether
+ return '';
+ }
$r .= $this->getLogText( $block, $queryParams, $allLogs, $isnew, $namehidden );
* @return string
*/
protected function getLogText( $block, $queryParams, $allLogs, $isnew, $namehidden ) {
+ if ( empty( $block ) ) {
+ return '';
+ }
+
# Changes message
static $nchanges = array();
static $sinceLastVisitMsg = array();
);
// Collect referenced files
$this->localFileRefs = array_unique( $this->localFileRefs );
- // If the list has been modified since last time we cached it, update the cache
- try {
- if ( $this->localFileRefs !== $this->getFileDependencies( $context->getSkin() ) ) {
- $dbw = wfGetDB( DB_MASTER );
- $dbw->replace( 'module_deps',
- array( array( 'md_module', 'md_skin' ) ), array(
- 'md_module' => $this->getName(),
- 'md_skin' => $context->getSkin(),
- 'md_deps' => FormatJson::encode( $this->localFileRefs ),
- )
- );
- }
- } catch ( Exception $e ) {
- wfDebugLog( 'resourceloader', __METHOD__ . ": failed to update DB: $e" );
- }
+ $this->saveFileDependencies( $context->getSkin(), $this->localFileRefs );
+
return $styles;
}
/**
* Get the files this module depends on indirectly for a given skin.
- * Currently these are only image files referenced by the module's CSS.
+ *
+ * These are only image files referenced by the module's stylesheet.
*
* @param string $skin Skin name
* @return array List of files
*/
- public function getFileDependencies( $skin ) {
+ protected function getFileDependencies( $skin ) {
// Try in-object cache first
if ( isset( $this->fileDeps[$skin] ) ) {
return $this->fileDeps[$skin];
}
/**
- * Set preloaded file dependency information. Used so we can load this
- * information for all modules at once.
+ * Set in-object cache for file dependencies.
+ *
+ * This is used to retrieve data in batches. See ResourceLoader::preloadModuleInfo().
+ * To save the data, use saveFileDependencies().
+ *
* @param string $skin Skin name
* @param array $deps Array of file names
*/
$this->fileDeps[$skin] = $deps;
}
+ /**
+ * Set the files this module depends on indirectly for a given skin.
+ *
+ * @since 1.26
+ * @param string $skin Skin name
+ * @param array $localFileRefs List of files
+ */
+ protected function saveFileDependencies( $skin, $localFileRefs ) {
+ try {
+ // If the list has been modified since last time we cached it, update the cache
+ if ( $localFileRefs !== $this->getFileDependencies( $skin ) ) {
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->replace( 'module_deps',
+ array( array( 'md_module', 'md_skin' ) ), array(
+ 'md_module' => $this->getName(),
+ 'md_skin' => $skin,
+ 'md_deps' => FormatJson::encode( $localFileRefs ),
+ )
+ );
+ }
+ } catch ( Exception $e ) {
+ wfDebugLog( 'resourceloader', __METHOD__ . ": failed to update DB: $e" );
+ }
+ }
+
/**
* Get the last modification timestamp of the messages in this module for a given language.
* @param string $lang Language code
}
/**
- * Set a preloaded message blob last modification timestamp. Used so we
- * can load this information for all modules at once.
+ * Set in-object cache for message blob time.
+ *
+ * This is used to retrieve data in batches. See ResourceLoader::preloadModuleInfo().
+ *
* @param string $lang Language code
* @param int $mtime UNIX timestamp
*/
'nv' => 'Diné bizaad', # Navajo
'ny' => 'Chi-Chewa', # Chichewa
'oc' => 'occitan', # Occitan
+ 'olo' => 'Livvinкarjala', # Livvi-Karelian
'om' => 'Oromoo', # Oromo
'or' => 'ଓଡ଼ିଆ', # Oriya
'os' => 'Ирон', # Ossetic, bug 29091
"createacct-imgcaptcha-help": "",
"createacct-imgcaptcha-ph": "Enter the text you see above",
"createacct-submit": "Create your account",
- "createacct-another-submit": "Create another account",
+ "createacct-another-submit": "Create account",
"createacct-benefit-heading": "{{SITENAME}} is made by people like you.",
"createacct-benefit-icon1": "icon-edits",
"createacct-benefit-head1": "{{NUMBEROFEDITS}}",
"upload-http-error": "An HTTP error occurred: $1",
"upload-copy-upload-invalid-domain": "Copy uploads are not available from this domain.",
"upload-dialog-title": "Upload file",
- "upload-dialog-error": "An error occurred",
- "upload-dialog-warning": "A warning occurred",
"upload-dialog-button-cancel": "Cancel",
"upload-dialog-button-done": "Done",
"upload-dialog-button-save": "Save",
"upload-dialog-button-upload": "Upload",
- "upload-dialog-label-select-file": "Select file",
- "upload-dialog-label-infoform-title": "Details",
- "upload-dialog-label-infoform-name": "Name",
- "upload-dialog-label-infoform-description": "Description",
- "upload-dialog-label-usage-title": "Usage",
- "upload-dialog-label-usage-filename": "File name",
+ "upload-process-error": "An error occurred",
+ "upload-process-warning": "A warning occurred",
+ "upload-form-label-select-file": "Select file",
+ "upload-form-label-infoform-title": "Details",
+ "upload-form-label-infoform-name": "Name",
+ "upload-form-label-infoform-description": "Description",
+ "upload-form-label-usage-title": "Usage",
+ "upload-form-label-usage-filename": "File name",
"backend-fail-stream": "Could not stream file \"$1\".",
"backend-fail-backup": "Could not backup file \"$1\".",
"backend-fail-notexists": "The file $1 does not exist.",
"emailccsubject": "Copy of your message to $1: $2",
"emailsent": "Email sent",
"emailsenttext": "Your email message has been sent.",
- "emailuserfooter": "This email was sent by $1 to $2 by the \"{{int:emailuser}}\" function at {{SITENAME}}.",
+ "emailuserfooter": "This email was {{GENDER:$1|sent}} by $1 to {{GENDER:$2|$2}} by the \"{{int:emailuser}}\" function at {{SITENAME}}.",
"usermessage-summary": "Leaving system message.",
"usermessage-editor": "System messenger",
"usermessage-template": "MediaWiki:UserMessage",
"upload-http-error": "Parameters:\n* $1 - error message",
"upload-copy-upload-invalid-domain": "Error message shown if a user is trying to upload (i.e. copy) a file from a website that is not in $wgCopyUploadsDomains (if set).\n\nSee also:\n* {{msg-mw|http-invalid-url}}\n* {{msg-mw|tmp-create-error}}\n* {{msg-mw|tmp-write-error}}",
"upload-dialog-title": "Title of the upload dialog box\n{{Identical|Upload file}}",
- "upload-dialog-error": "Error message from upload",
- "upload-dialog-warning": "Warning message from upload",
"upload-dialog-button-cancel": "Button to cancel the dialog\n{{Identical|Cancel}}",
"upload-dialog-button-done": "Button to close the dialog once upload is complete\n{{Identical|Done}}",
"upload-dialog-button-save": "Button to save the file\n{{Identical|Save}}",
"upload-dialog-button-upload": "Button to initiate upload\n{{Identical|Upload}}",
- "upload-dialog-label-select-file": "Label for the select file widget\n{{Identical|Select file}}",
- "upload-dialog-label-infoform-title": "Title for the information form\n{{Identical|Detail}}",
- "upload-dialog-label-infoform-name": "Label for the file name input\n{{Identical|Name}}",
- "upload-dialog-label-infoform-description": "Label for the file description input\n{{Identical|Description}}",
- "upload-dialog-label-usage-title": "Title for the insert form showing how to use the uploaded item.\n{{Identical|Usage}}",
- "upload-dialog-label-usage-filename": "Label for the file name input\n{{Identical|Filename}}",
+ "upload-process-error": "Error message from upload",
+ "upload-process-warning": "Warning message from upload",
+ "upload-form-label-select-file": "Label for the select file widget\n{{Identical|Select file}}",
+ "upload-form-label-infoform-title": "Title for the information form\n{{Identical|Detail}}",
+ "upload-form-label-infoform-name": "Label for the file name input\n{{Identical|Name}}",
+ "upload-form-label-infoform-description": "Label for the file description input\n{{Identical|Description}}",
+ "upload-form-label-usage-title": "Title for the insert form showing how to use the uploaded item.\n{{Identical|Usage}}",
+ "upload-form-label-usage-filename": "Label for the file name input\n{{Identical|Filename}}",
"backend-fail-stream": "Parameters:\n* $1 - a filename",
"backend-fail-backup": "Parameters:\n* $1 - a filename",
"backend-fail-notexists": "Parameters:\n* $1 - a filename",
--- /dev/null
+<?php
+/** Livvi-Karelian (Livvinкarjala)
+ *
+ * To improve a translation please visit https://translatewiki.net
+ *
+ * @ingroup Language
+ * @file
+ *
+ */
+
+$fallback = 'ru';
+
+$linkTrail = '/^([a-zčČšŠžŽäÄöÖ]+)(.*)$/sDu';
+
'mediawiki.Upload',
),
'messages' => array(
- 'upload-dialog-error',
- 'upload-dialog-warning',
- 'upload-dialog-label-select-file',
- 'upload-dialog-label-infoform-title',
- 'upload-dialog-label-infoform-name',
- 'upload-dialog-label-infoform-description',
- 'upload-dialog-label-usage-title',
- 'upload-dialog-label-usage-filename',
+ 'upload-process-error',
+ 'upload-process-warning',
+ 'upload-form-label-select-file',
+ 'upload-form-label-infoform-title',
+ 'upload-form-label-infoform-name',
+ 'upload-form-label-infoform-description',
+ 'upload-form-label-usage-title',
+ 'upload-form-label-usage-filename',
),
),
'mediawiki.toc' => array(
this.uploadPromise.always( function () {
if ( layout.upload.getState() === mw.Upload.State.ERROR ) {
- deferred.reject( new OO.ui.Error( mw.msg( 'upload-dialog-error' ) ) );
+ deferred.reject( new OO.ui.Error( mw.msg( 'upload-process-error' ) ) );
return false;
}
if ( layout.upload.getState() === mw.Upload.State.WARNING ) {
- deferred.reject( new OO.ui.Error( mw.msg( 'upload-dialog-error' ) ) );
+ deferred.reject( new OO.ui.Error( mw.msg( 'upload-process-error' ) ) );
return false;
}
var name;
if ( layout.upload.getState() === mw.Upload.State.ERROR ) {
- deferred.reject( new OO.ui.Error( mw.msg( 'upload-dialog-error' ) ) );
+ deferred.reject( new OO.ui.Error( mw.msg( 'upload-process-error' ) ) );
return false;
}
if ( layout.upload.getState() === mw.Upload.State.WARNING ) {
- deferred.reject( new OO.ui.Error( mw.msg( 'upload-dialog-warning' ) ) );
+ deferred.reject( new OO.ui.Error( mw.msg( 'upload-process-warning' ) ) );
return false;
}
var fieldset;
this.selectFileWidget = new OO.ui.SelectFileWidget();
- fieldset = new OO.ui.FieldsetLayout( { label: mw.msg( 'upload-dialog-label-select-file' ) } );
+ fieldset = new OO.ui.FieldsetLayout( { label: mw.msg( 'upload-form-label-select-file' ) } );
fieldset.addItems( [ this.selectFileWidget ] );
this.uploadForm = new OO.ui.FormLayout( { items: [ fieldset ] } );
} );
fieldset = new OO.ui.FieldsetLayout( {
- label: mw.msg( 'upload-dialog-label-infoform-title' )
+ label: mw.msg( 'upload-form-label-infoform-title' )
} );
fieldset.addItems( [
new OO.ui.FieldLayout( this.filenameWidget, {
- label: mw.msg( 'upload-dialog-label-infoform-name' ),
+ label: mw.msg( 'upload-form-label-infoform-name' ),
align: 'top'
} ),
new OO.ui.FieldLayout( this.descriptionWidget, {
- label: mw.msg( 'upload-dialog-label-infoform-description' ),
+ label: mw.msg( 'upload-form-label-infoform-description' ),
align: 'top'
} )
] );
this.filenameUsageWidget = new OO.ui.TextInputWidget();
fieldset = new OO.ui.FieldsetLayout( {
- label: mw.msg( 'upload-dialog-label-usage-title' )
+ label: mw.msg( 'upload-form-label-usage-title' )
} );
fieldset.addItems( [
new OO.ui.FieldLayout( this.filenameUsageWidget, {
- label: mw.msg( 'upload-dialog-label-usage-filename' ),
+ label: mw.msg( 'upload-form-label-usage-filename' ),
align: 'top'
} )
] );
{|
|[[{{{1}}}|{{{2}}}]]
|}
-!! html
+!! html/php
<table>
<tr>
<td>[[{{{1}}}|{{{2}}}]]
</td></tr></table>
+!! html/parsoid
+<table>
+<tbody><tr><td>[[<span about="#mwt5" typeof="mw:Param" data-parsoid='{"src":"{{{1}}}"}'>{{{1}}}</span>|<span about="#mwt2" typeof="mw:Param" data-parsoid='{"src":"{{{2}}}"}'>{{{2}}}</span>]]</td></tr>
+!! end
+
+# See: T2553
+!! test
+Abort table cell attribute parsing on wikilink
+!! wikitext
+{|
+| testing [[one|two]] | three || four
+| testing one two | three || four
+|}
+!! html/php
+<table>
+<tr>
+<td> testing <a href="/index.php?title=One&action=edit&redlink=1" class="new" title="One (page does not exist)">two</a> | three </td>
+<td> four
+</td>
+<td> three </td>
+<td> four
+</td></tr></table>
+
+!! html/parsoid
+<table>
+<tbody><tr data-parsoid='{"autoInsertedEnd":true,"autoInsertedStart":true}'><td data-parsoid='{"autoInsertedEnd":true}'> testing <a rel="mw:WikiLink" href="./One" title="One" data-parsoid='{"stx":"piped","a":{"href":"./One"},"sa":{"href":"one"}}'>two</a> | three </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'> four</td>
+<td data-parsoid='{"a":{"testing":null,"one":null,"two":null},"sa":{"testing":"","one":"","two":""},"autoInsertedEnd":true}'> three </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'> four</td></tr>
+</tbody></table>
+!! end
+
+!! test
+Don't abort table cell attribute parsing if wikilink is found in template arg
+!! wikitext
+{|
+| Test {{#tag:ref|One two "[[three]]" four}}
+|}
+!! html/parsoid
+<table>
+<tbody><tr><td> Test <ref about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[{"k":"1","spc":["","","",""]}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"#tag:ref","function":"#tag"},"params":{"1":{"wt":"One two \"[[three]]\" four"}},"i":0}}]}'>One two "<a rel="mw:WikiLink" href="./Three" title="Three">three</a>" four</ref></td></tr>
+</tbody></table>
!! end
!! test
</table></td></tr></tbody></table>
!! end
+!! test
+Templates: Parameters substituted at the top-level
+!! wikitext
+{{{foo|''who'' {{echo|me}}? '''never!'''}}}
+!! html/php
+<p><i>who</i> me? <b>never!</b>
+</p>
+!! html/parsoid
+<p about="#mwt2" typeof="mw:Param" data-parsoid="{"src":"{{{foo|''who'' {{echo|me}}? '''never!'''}}}"}"><i>who</i> me? <b>never!</b></p>
+!! end
+
!!test
Parser Functions: 1. Simple example
!! wikitext
{{!}} is a magic word
!! wikitext
{{!}} is a magic word there and {{!}} is still a magic word here
+| is not a magic word here but {{!}} is still a magic word here
!! html/php
<p>| is a magic word there and | is still a magic word here
+| is not a magic word here but | is still a magic word here
</p>
!! html/parsoid
-<p><span about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"!","href":"./Template:!"},"params":{},"i":0}}]}' data-parsoid='{"pi":[[]]}'>|</span> is a magic word there and <span about="#mwt2" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"!","href":"./Template:!"},"params":{},"i":0}}]}' data-parsoid='{"pi":[[]]}'>|</span> is still a magic word here</p>
+<p><span about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"pi":[[]]}' data-mw='{"parts":[{"template":{"target":{"wt":"!","href":"./Template:!"},"params":{},"i":0}}]}'>|</span> is a magic word there and <span about="#mwt2" typeof="mw:Transclusion" data-parsoid='{"pi":[[]]}' data-mw='{"parts":[{"template":{"target":{"wt":"!","href":"./Template:!"},"params":{},"i":0}}]}'>|</span> is still a magic word here
+| is not a magic word here but <span about="#mwt3" typeof="mw:Transclusion" data-parsoid='{"pi":[[]]}' data-mw='{"parts":[{"template":{"target":{"wt":"!","href":"./Template:!"},"params":{},"i":0}}]}'>|</span> is still a magic word here</p>
+
!! end
!! test
{|
|- [[foo]]
|}
-!! html
+!! html/php
<table>
</table>
+!! html/parsoid
+<table>
+<tbody><tr data-parsoid='{"startTagSrc":"|-","a":{"[[foo]]":null},"sa":{"[[foo]]":""},"autoInsertedEnd":true}'></tr>
+</tbody></table>
!!end
# Parsoid-only since PHP parser relies on Tidy for correct output
</table>
!! end
+## T111151 Remove font elements without attributes
+!! test
+5a. font tags without attributes should be dropped in scrubWikitext mode
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": true
+}
+!! html
+<font>foo</font>
+<font><font>bar</font></font>
+<font class="x">boo</font>
+!! wikitext
+foo
+bar
+<font class="x">boo</font>
+!! end
+
+!! test
+5b. font tags should not be dropped without scrubWikitext being enabled
+!! options
+parsoid={
+ "modes": ["html2wt"],
+ "scrubWikitext": false
+}
+!! html
+<font>foo</font>
+!! wikitext
+<font>foo</font>
+!! end
+
!! test
Escape nowiki DOM elements
!! options
class ImportTest extends MediaWikiLangTestCase {
private function getInputStreamSource( $xml ) {
+ if ( ini_get( 'allow_url_fopen' ) != 1 ) {
+ $this->markTestSkipped( 'bug 73283: this test needs allow_url_fopen to be enabled' );
+ }
$file = 'data:application/xml,' . $xml;
$status = ImportStreamSource::newFromFile( $file );
if ( !$status->isGood() ) {
</testsuite>
<testsuite name="skins">
<directory>skins</directory>
+ <directory>structure</directory>
+ <file>suites/LessTestSuite.php</file>
</testsuite>
<!-- As there is a class Maintenance, we cannot use the
name "maintenance" directly -->