meaning that JavaScript is no longer executed in these browser versions.
* Browser support for Opera 11 lowered from Grade A to Grade C.
* Removed IEFixes module which existed purely to provide support for MSIE versions
+ below 7 (conditionally loaded only for those browsers).
* Deprecated SpecialPageFactory::getList() in favor of
SpecialPageFactory::getNames()
- below 7 (conditionally loaded only for those browsers).
* Action::checkCanExecute() no longer has a return value.
* Removed cleanupForIRC(), loadFromCurRow(), newFromCurRow(), notifyRC2UDP()
and sendToUDP() from RecentChange.php. (deprecated since 1.22)
== MediaWiki ==
-MediaWiki is a popular and free, open-source wiki software package written in
-PHP. It serves as the platform for Wikipedia and the other projects of the Wikimedia
-Foundation, which deliver content in over 280 languages to more than half a billion
-people each month. MediaWiki's reliability and robust feature set have earned it a
-large and vibrant community of third-party users and developers.
+MediaWiki is a free and open-source wiki software package written in PHP. It
+serves as the platform for Wikipedia and the other projects of the Wikimedia
+Foundation, which deliver content in over 280 languages to more than half a
+billion people each month. MediaWiki's reliability and robust feature set have
+earned it a large and vibrant community of third-party users and developers.
MediaWiki is:
-* feature-rich and extensible, both on-wiki and with over 2,000 extensions;
+* feature-rich and extensible, both on-wiki and with hundreds of extensions;
* scalable and suitable for both small and large sites;
-* available in your language; and
-* simple to install, working on most hardware/software combinations.
+* simple to install, working on most hardware/software combinations; and
+* available in your language.
For system requirements, installation, and upgrade details, see the files
RELEASE-NOTES, INSTALL, and UPGRADE.
* Seeking help from a person?
** https://www.mediawiki.org/wiki/Communication
* Looking to file a bug report or a feature request?
-** https://bugzilla.wikimedia.org/
+** https://bugs.mediawiki.org/
* Interested in helping out?
** https://www.mediawiki.org/wiki/How_to_contribute
** In source text of the form '{$A}'{$B}' or `{$A}`{$B}`, where variable A
does not exist yet variable B does, the latter may not be replaced.
However, this difference is unlikely to arise in practice.
+* (T67278) RFC, PMID, and ISBN "magic links" must be surrounded by non-word
+ characters on both sides.
== Compatibility ==
'ResourceLoaderFileModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderFileModule.php',
'ResourceLoaderFilePageModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderFilePageModule.php',
'ResourceLoaderFilePath' => __DIR__ . '/includes/resourceloader/ResourceLoaderFilePath.php',
+ 'ResourceLoaderImage' => __DIR__ . '/includes/resourceloader/ResourceLoaderImage.php',
+ 'ResourceLoaderImageModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderImageModule.php',
'ResourceLoaderLanguageDataModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderLanguageDataModule.php',
'ResourceLoaderLanguageNamesModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderLanguageNamesModule.php',
'ResourceLoaderModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderModule.php',
'ResourceLoaderSkinModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderSkinModule.php',
'ResourceLoaderStartUpModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderStartUpModule.php',
'ResourceLoaderUserCSSPrefsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php',
+ 'ResourceLoaderUserDefaultsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserDefaultsModule.php',
'ResourceLoaderUserGroupsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserGroupsModule.php',
'ResourceLoaderUserModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserModule.php',
- 'ResourceLoaderUserDefaultsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserDefaultsModule.php',
'ResourceLoaderUserOptionsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserOptionsModule.php',
'ResourceLoaderUserTokensModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserTokensModule.php',
'ResourceLoaderWikiModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderWikiModule.php',
],
"license": "GPL-2.0",
"support": {
- "issues": "https://bugzilla.wikimedia.org/",
+ "issues": "https://bugs.mediawiki.org/",
"irc": "irc://irc.freenode.net/mediawiki",
"wiki": "https://www.mediawiki.org/"
},
'BeforeParserFetchFileAndTitle': Before an image is rendered by Parser.
$parser: Parser object
$nt: the image title
-&$options: array of options to RepoGroup::findFile
+&$options: array of options to RepoGroup::findFile. If it contains 'broken'
+ as a key then the file will appear as a broken thumbnail.
&$descQuery: query string to add to thumbnail URL
-FIXME: Where does the below sentence fit in?
-If 'broken' is a key in $options then the file will appear as a broken thumbnail.
-
'BeforeParserFetchTemplateAndtitle': Before a template is fetched by Parser.
$parser: Parser object
$title: title of the template
Use the $status object to indicate whether the edit should be allowed, and to provide
a reason for disallowing it. Return false to abort the edit, and true to continue.
Returning true if $status->isOK() returns false means "don't save but continue user
-interaction", e.g. show the edit form.
+interaction", e.g. show the edit form. $status->apiHookResult can be set to an array
+to be returned by api.php action=edit. This is used to deliver captchas.
$context: object implementing the IContextSource interface.
$content: content of the edit box, as a Content object.
$status: Status object to represent errors, etc.
}
}
- wfRunHooks( 'GetAutoPromoteGroups', array( $user, &$promote ) );
+ Hooks::run( 'GetAutoPromoteGroups', array( $user, &$promote ) );
return $promote;
}
return in_array( 'bot', User::getGroupPermissions( $user->getGroups() ) );
default:
$result = null;
- wfRunHooks( 'AutopromoteCondition', array( $cond[0],
+ Hooks::run( 'AutopromoteCondition', array( $cond[0],
array_slice( $cond, 1 ), $user, &$result ) );
if ( $result === null ) {
throw new MWException( "Unrecognized condition {$cond[0]} for autopromotion!" );
$this->forcedTargetID = $user; // needed for foreign users
}
if ( $by ) { // local user
- $this->setBlocker( User::newFromID( $by ) );
+ $this->setBlocker( User::newFromId( $by ) );
} else { // foreign user
$this->setBlocker( $byText );
}
protected function initFromRow( $row ) {
$this->setTarget( $row->ipb_address );
if ( $row->ipb_by ) { // local user
- $this->setBlocker( User::newFromID( $row->ipb_by ) );
+ $this->setBlocker( User::newFromId( $row->ipb_by ) );
} else { // foreign user
$this->setBlocker( $row->ipb_by_text );
}
if ( $this->isAutoblocking() && $this->getType() == self::TYPE_USER ) {
wfDebug( "Doing retroactive autoblocks for " . $this->getTarget() . "\n" );
- $continue = wfRunHooks(
+ $continue = Hooks::run(
'PerformRetroactiveAutoblock', array( $this, &$blockIds ) );
if ( $continue ) {
}
# Allow hooks to cancel the autoblock.
- if ( !wfRunHooks( 'AbortAutoblock', array( $autoblockIP, &$this ) ) ) {
+ if ( !Hooks::run( 'AbortAutoblock', array( $autoblockIP, &$this ) ) ) {
wfDebug( "Autoblock aborted by hook.\n" );
return false;
}
$emptyTags[] = $row->vt_tag;
}
- wfRunHooks( 'ListDefinedTags', array( &$emptyTags ) );
+ Hooks::run( 'ListDefinedTags', array( &$emptyTags ) );
$emptyTags = array_filter( array_unique( $emptyTags ) );
# Provide a mechanism for extensions to hook in.
$collationObject = null;
- wfRunHooks( 'Collation::factory', array( $collationName, &$collationObject ) );
+ Hooks::run( 'Collation::factory', array( $collationName, &$collationObject ) );
if ( $collationObject instanceof Collation ) {
return $collationObject;
/**
* A few constants that might be needed during LocalSettings.php.
*
- * Note: these constants must all be resolvable at compile time by HipHop,
- * since this file will not be executed during request startup for a compiled
- * MediaWiki.
- *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
define( 'MW_SUPPORTS_PARSERFIRSTCALLINIT', 1 );
define( 'MW_SUPPORTS_LOCALISATIONCACHE', 1 );
define( 'MW_SUPPORTS_CONTENTHANDLER', 1 );
+define( 'MW_EDITFILTERMERGED_SUPPORTS_API', 1 );
/**@}*/
/** Support for $wgResourceModules */
function edit() {
global $wgOut, $wgRequest, $wgUser;
// Allow extensions to modify/prevent this form or submission
- if ( !wfRunHooks( 'AlternateEdit', array( $this ) ) ) {
+ if ( !Hooks::run( 'AlternateEdit', array( $this ) ) ) {
return;
}
}
if ( !$this->mTitle->getArticleID() ) {
- wfRunHooks( 'EditFormPreloadText', array( &$this->textbox1, &$this->mTitle ) );
+ Hooks::run( 'EditFormPreloadText', array( &$this->textbox1, &$this->mTitle ) );
} else {
- wfRunHooks( 'EditFormInitialText', array( $this ) );
+ Hooks::run( 'EditFormInitialText', array( $this ) );
}
}
throw new PermissionsError( $action, $permErrors );
}
- wfRunHooks( 'EditPage::showReadOnlyForm:initial', array( $this, &$wgOut ) );
+ Hooks::run( 'EditPage::showReadOnlyForm:initial', array( $this, &$wgOut ) );
$wgOut->setRobotPolicy( 'noindex,nofollow' );
$wgOut->setPageTitle( wfMessage(
$this->section === 'new' ? 'MediaWiki:addsection-editintro' : '' );
// Allow extensions to modify form data
- wfRunHooks( 'EditPage::importFormData', array( $this, $request ) );
+ Hooks::run( 'EditPage::importFormData', array( $this, $request ) );
wfProfileOut( __METHOD__ );
}
$sectionanchor = $resultDetails['sectionanchor'];
// Give extensions a chance to modify URL query on update
- wfRunHooks(
+ Hooks::run(
'ArticleUpdateBeforeRedirect',
array( $this->mArticle, &$sectionanchor, &$extraQuery )
);
protected function runPostMergeFilters( Content $content, Status $status, User $user ) {
// Run old style post-section-merge edit filter
if ( !ContentHandler::runLegacyHooks( 'EditFilterMerged',
- array( $this, $content, &$this->hookError, $this->summary ) ) ) {
-
+ array( $this, $content, &$this->hookError, $this->summary ) )
+ ) {
# Error messages etc. could be handled within the hook...
$status->fatal( 'hookaborted' );
$status->value = self::AS_HOOK_ERROR;
}
// Run new style post-section-merge edit filter
- if ( !wfRunHooks( 'EditFilterMergedContent',
- array( $this->mArticle->getContext(), $content, $status, $this->summary,
- $user, $this->minoredit ) ) ) {
-
+ if ( !Hooks::run( 'EditFilterMergedContent',
+ array( $this->mArticle->getContext(), $content, $status, $this->summary,
+ $user, $this->minoredit ) )
+ ) {
# Error messages etc. could be handled within the hook...
- // XXX: $status->value may already be something informative...
- $this->hookError = $status->getWikiText();
- $status->fatal( 'hookaborted' );
- $status->value = self::AS_HOOK_ERROR;
+ if ( $status->isGood() ) {
+ $status->fatal( 'hookaborted' );
+ // Not setting $this->hookError here is a hack to allow the hook
+ // to cause a return to the edit page without $this->hookError
+ // being set. This is used by ConfirmEdit to display a captcha
+ // without any error message cruft.
+ } else {
+ $this->hookError = $status->getWikiText();
+ }
+ // Use the existing $status->value if the hook set it
+ if ( !$status->value ) {
+ $status->value = self::AS_HOOK_ERROR;
+ }
return false;
} elseif ( !$status->isOK() ) {
# ...or the hook could be expecting us to produce an error
wfProfileIn( __METHOD__ );
wfProfileIn( __METHOD__ . '-checks' );
- if ( !wfRunHooks( 'EditPage::attemptSave', array( $this ) ) ) {
+ if ( !Hooks::run( 'EditPage::attemptSave', array( $this ) ) ) {
wfDebug( "Hook 'EditPage::attemptSave' aborted article saving\n" );
$status->fatal( 'hookaborted' );
$status->value = self::AS_HOOK_ERROR;
wfProfileOut( __METHOD__ );
return $status;
}
- if ( !wfRunHooks(
+ if ( !Hooks::run(
'EditFilter',
array( $this, $this->textbox1, $this->section, &$this->hookError, $this->summary ) )
) {
* Send the edit form and related headers to $wgOut
* @param callable|null $formCallback That takes an OutputPage parameter; will be called
* during form output near the top, for captchas and the like.
+ *
+ * The $formCallback parameter is deprecated since MediaWiki 1.25. Please
+ * use the EditPage::showEditForm:fields hook instead.
*/
function showEditForm( $formCallback = null ) {
global $wgOut, $wgUser;
$previewOutput = $this->getPreviewText();
}
- wfRunHooks( 'EditPage::showEditForm:initial', array( &$this, &$wgOut ) );
+ Hooks::run( 'EditPage::showEditForm:initial', array( &$this, &$wgOut ) );
$this->setHeaders();
) );
if ( is_callable( $formCallback ) ) {
+ wfWarn( 'The $formCallback parameter to ' . __METHOD__ . 'is deprecated' );
call_user_func_array( $formCallback, array( &$wgOut ) );
}
. Xml::closeElement( 'div' )
);
- wfRunHooks( 'EditPage::showEditForm:fields', array( &$this, &$wgOut ) );
+ Hooks::run( 'EditPage::showEditForm:fields', array( &$this, &$wgOut ) );
// Put these up at the top to ensure they aren't lost on early form submission
$this->showFormBeforeText();
}
# This hook seems slightly odd here, but makes things more
# consistent for extensions.
- wfRunHooks( 'OutputPageBeforeHTML', array( &$wgOut, &$text ) );
+ Hooks::run( 'OutputPageBeforeHTML', array( &$wgOut, &$text ) );
$wgOut->addHTML( $text );
if ( $this->mTitle->getNamespace() == NS_CATEGORY ) {
$this->mArticle->closeShowCategory();
if ( $newContent ) {
ContentHandler::runLegacyHooks( 'EditPageGetDiffText', array( $this, &$newContent ) );
- wfRunHooks( 'EditPageGetDiffContent', array( $this, &$newContent ) );
+ Hooks::run( 'EditPageGetDiffContent', array( $this, &$newContent ) );
$popts = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang );
$newContent = $newContent->preSaveTransform( $this->mTitle, $wgUser, $popts );
*/
protected function showTosSummary() {
$msg = 'editpage-tos-summary';
- wfRunHooks( 'EditPageTosSummary', array( $this->mTitle, &$msg ) );
+ Hooks::run( 'EditPageTosSummary', array( $this->mTitle, &$msg ) );
if ( !wfMessage( $msg )->isDisabled() ) {
global $wgOut;
$wgOut->addHTML( '<div class="mw-tos-summary">' );
'[[' . wfMessage( 'copyrightpage' )->inContentLanguage()->text() . ']]' );
}
// Allow for site and per-namespace customization of contribution/copyright notice.
- wfRunHooks( 'EditPageCopyrightWarning', array( $title, &$copywarnMsg ) );
+ Hooks::run( 'EditPageCopyrightWarning', array( $title, &$copywarnMsg ) );
return "<div id=\"editpage-copywarn\">\n" .
call_user_func_array( 'wfMessage', $copywarnMsg )->$format() . "\n</div>";
Html::openElement( 'tbody' );
foreach ( $output->getLimitReportData() as $key => $value ) {
- if ( wfRunHooks( 'ParserLimitReportFormat',
+ if ( Hooks::run( 'ParserLimitReportFormat',
array( $key, &$value, &$limitReport, true, true )
) ) {
$keyMsg = wfMessage( $key );
$wgOut->addHTML( " <span class='editHelp'>{$edithelp}</span>\n" );
$wgOut->addHTML( "</div><!-- editButtons -->\n" );
- wfRunHooks( 'EditPage::showStandardInputs:options', array( $this, $wgOut, &$tabindex ) );
+ Hooks::run( 'EditPage::showStandardInputs:options', array( $this, $wgOut, &$tabindex ) );
$wgOut->addHTML( "</div><!-- editOptions -->\n" );
}
protected function showConflict() {
global $wgOut;
- if ( wfRunHooks( 'EditPageBeforeConflictDiff', array( &$this, &$wgOut ) ) ) {
+ if ( Hooks::run( 'EditPageBeforeConflictDiff', array( &$this, &$wgOut ) ) ) {
$wgOut->wrapWikiMsg( '<h2>$1</h2>', "yourdiff" );
$content1 = $this->toEditContent( $this->textbox1 );
$content = $this->toEditContent( $this->textbox1 );
$previewHTML = '';
- if ( !wfRunHooks(
+ if ( !Hooks::run(
'AlternateEditPreview',
array( $this, &$content, &$previewHTML, &$this->mParserOutput ) )
) {
}
$parserOptions = $this->mArticle->makeParserOptions( $this->mArticle->getContext() );
- $parserOptions->setEditSection( false );
$parserOptions->setIsPreview( true );
$parserOptions->setIsSectionPreview( !is_null( $this->section ) && $this->section !== '' );
$hook_args = array( $this, &$content );
ContentHandler::runLegacyHooks( 'EditPageGetPreviewText', $hook_args );
- wfRunHooks( 'EditPageGetPreviewContent', $hook_args );
+ Hooks::run( 'EditPageGetPreviewContent', $hook_args );
$parserOptions->enableLimitReport();
# For CSS/JS pages, we should have called the ShowRawCssJs hook here.
# But it's now deprecated, so never mind
- $content = $content->preSaveTransform( $this->mTitle, $wgUser, $parserOptions );
- $parserOutput = $content->getParserOutput(
- $this->getArticle()->getTitle(),
- null,
- $parserOptions
+ $pstContent = $content->preSaveTransform( $this->mTitle, $wgUser, $parserOptions );
+ $parserOutput = $pstContent->getParserOutput( $this->mTitle, null, $parserOptions );
+
+ # Try to stash the edit for the final submission step
+ # @todo: different date format preferences cause cache misses
+ ApiStashEdit::stashEditFromPreview(
+ $this->getArticle(), $content, $pstContent,
+ $parserOutput, $parserOptions, $parserOptions, wfTimestampNow()
);
+ $parserOutput->setEditSectionTokens( false ); // no section edit links
$previewHTML = $parserOutput->getText();
$this->mParserOutput = $parserOutput;
$wgOut->addParserOutputMetadata( $parserOutput );
$toolbar = '<div id="toolbar"></div>';
- wfRunHooks( 'EditPageBeforeEditToolbar', array( &$toolbar ) );
+ Hooks::run( 'EditPageBeforeEditToolbar', array( &$toolbar ) );
return $toolbar;
}
$checkboxes['watch'] = $watchThisHtml;
}
}
- wfRunHooks( 'EditPageBeforeEditChecks', array( &$this, &$checkboxes, &$tabindex ) );
+ Hooks::run( 'EditPageBeforeEditChecks', array( &$this, &$checkboxes, &$tabindex ) );
return $checkboxes;
}
$buttons['diff'] = Html::submitButton( wfMessage( 'showdiff' )->text(),
$attribs );
- wfRunHooks( 'EditPageBeforeEditButtons', array( &$this, &$buttons, &$tabindex ) );
+ Hooks::run( 'EditPageBeforeEditButtons', array( &$this, &$buttons, &$tabindex ) );
return $buttons;
}
$wgOut->prepareErrorPage( wfMessage( 'nosuchsectiontitle' ) );
$res = wfMessage( 'nosuchsectiontext', $this->section )->parseAsBlock();
- wfRunHooks( 'EditPageNoSuchSection', array( &$this, &$res ) );
+ Hooks::run( 'EditPageNoSuchSection', array( &$this, &$res ) );
$wgOut->addHTML( $res );
$wgOut->returnToMain( false, $this->mTitle );
# Default JOIN, to be overridden...
$join['revision'] = array( 'INNER JOIN', 'page_id=rev_page AND page_latest=rev_id' );
# One, and only one hook should set this, and return false
- if ( wfRunHooks( 'WikiExporter::dumpStableQuery', array( &$tables, &$opts, &$join ) ) ) {
+ if ( Hooks::run( 'WikiExporter::dumpStableQuery', array( &$tables, &$opts, &$join ) ) ) {
wfProfileOut( __METHOD__ );
throw new MWException( __METHOD__ . " given invalid history dump type." );
}
$result = null; // Assuring $result is not undefined, if exception occurs early
try {
- wfRunHooks( 'ModifyExportQuery',
+ Hooks::run( 'ModifyExportQuery',
array( $this->db, &$tables, &$cond, &$opts, &$join ) );
# Do the query!
strval( $row->page_restrictions ) ) . "\n";
}
- wfRunHooks( 'XmlDumpWriterOpenPage', array( $this, &$out, $row, $title ) );
+ Hooks::run( 'XmlDumpWriterOpenPage', array( $this, &$out, $row, $title ) );
return $out;
}
$out .= " <sha1/>\n";
}
- wfRunHooks( 'XmlDumpWriterWriteRevision', array( &$this, &$out, $row, $text ) );
+ Hooks::run( 'XmlDumpWriterWriteRevision', array( &$this, &$out, $row, $text ) );
$out .= " </revision>\n";
}
if ( $status->isOK() ) {
- wfRunHooks( 'FileDeleteComplete', array( &$file, &$oldimage, &$page, &$user, &$reason ) );
+ Hooks::run( 'FileDeleteComplete', array( &$file, &$oldimage, &$page, &$user, &$reason ) );
}
return $status;
if ( self::$viewers === false ) {
self::$viewers = $wgGitRepositoryViewers;
- wfRunHooks( 'GitViewers', array( &self::$viewers ) );
+ Hooks::run( 'GitViewers', array( &self::$viewers ) );
}
return self::$viewers;
*
* @return DatabaseBase
*/
-function &wfGetDB( $db, $groups = array(), $wiki = false ) {
+function wfGetDB( $db, $groups = array(), $wiki = false ) {
return wfGetLB( $wiki )->getConnection( $db, $groups, $wiki );
}
*
* @return LBFactory
*/
-function &wfGetLBFactory() {
+function wfGetLBFactory() {
return LBFactory::singleton();
}
* @param string|null $deprecatedVersion Optionally mark hook as deprecated with version number
*
* @return bool True if no handler aborted the hook
+ * @deprecated 1.25
*/
function wfRunHooks( $event, array $args = array(), $deprecatedVersion = null ) {
return Hooks::run( $event, $args, $deprecatedVersion );
*/
public function finishImportPage( $title, $origTitle, $revCount, $sRevCount, $pageInfo ) {
$args = func_get_args();
- return wfRunHooks( 'AfterImportPage', $args );
+ return Hooks::run( 'AfterImportPage', $args );
}
/**
$tag = $this->reader->name;
$type = $this->reader->nodeType;
- if ( !wfRunHooks( 'ImportHandleToplevelXMLTag', array( $this ) ) ) {
+ if ( !Hooks::run( 'ImportHandleToplevelXMLTag', array( $this ) ) ) {
// Do nothing
} elseif ( $tag == 'mediawiki' && $type == XmlReader::END_ELEMENT ) {
break;
$tag = $this->reader->name;
- if ( !wfRunHooks( 'ImportHandleLogItemXMLTag', array(
+ if ( !Hooks::run( 'ImportHandleLogItemXMLTag', array(
$this, $logInfo
) ) ) {
// Do nothing
if ( $badTitle ) {
// The title is invalid, bail out of this page
$skip = true;
- } elseif ( !wfRunHooks( 'ImportHandlePageXMLTag', array( $this,
+ } elseif ( !Hooks::run( 'ImportHandlePageXMLTag', array( $this,
&$pageInfo ) ) ) {
// Do nothing
} elseif ( in_array( $tag, $normalFields ) ) {
$tag = $this->reader->name;
- if ( !wfRunHooks( 'ImportHandleRevisionXMLTag', array(
+ if ( !Hooks::run( 'ImportHandleRevisionXMLTag', array(
$this, $pageInfo, $revisionInfo
) ) ) {
// Do nothing
$tag = $this->reader->name;
- if ( !wfRunHooks( 'ImportHandleUploadXMLTag', array(
+ if ( !Hooks::run( 'ImportHandleUploadXMLTag', array(
$this, $pageInfo
) ) ) {
// Do nothing
$dummy = new DummyLinker; // dummy linker instance for bc on the hooks
$ret = null;
- if ( !wfRunHooks( 'LinkBegin',
+ if ( !Hooks::run( 'LinkBegin',
array( $dummy, $target, &$html, &$customAttribs, &$query, &$options, &$ret ) )
) {
wfProfileOut( __METHOD__ );
}
$ret = null;
- if ( wfRunHooks( 'LinkEnd', array( $dummy, $target, $options, &$html, &$attribs, &$ret ) ) ) {
+ if ( Hooks::run( 'LinkEnd', array( $dummy, $target, $options, &$html, &$attribs, &$ret ) ) ) {
$ret = Html::rawElement( 'a', $attribs, $html );
}
*/
public static function makeSelfLinkObj( $nt, $html = '', $query = '', $trail = '', $prefix = '' ) {
$ret = "<strong class=\"selflink\">{$prefix}{$html}</strong>{$trail}";
- if ( !wfRunHooks( 'SelfLinkBegin', array( $nt, &$html, &$trail, &$prefix, &$ret ) ) ) {
+ if ( !Hooks::run( 'SelfLinkBegin', array( $nt, &$html, &$trail, &$prefix, &$ret ) ) ) {
return $ret;
}
$alt = self::fnamePart( $url );
}
$img = '';
- $success = wfRunHooks( 'LinkerMakeExternalImage', array( &$url, &$alt, &$img ) );
+ $success = Hooks::run( 'LinkerMakeExternalImage', array( &$url, &$alt, &$img ) );
if ( !$success ) {
wfDebug( "Hook LinkerMakeExternalImage changed the output of external image "
. "with url {$url} and alt text {$alt} to {$img}\n", true );
) {
$res = null;
$dummy = new DummyLinker;
- if ( !wfRunHooks( 'ImageBeforeProduceHTML', array( &$dummy, &$title,
+ if ( !Hooks::run( 'ImageBeforeProduceHTML', array( &$dummy, &$title,
&$file, &$frameParams, &$handlerParams, &$time, &$res ) ) ) {
return $res;
}
'title' => $alt
);
- if ( !wfRunHooks( 'LinkerMakeMediaLinkFile',
+ if ( !Hooks::run( 'LinkerMakeMediaLinkFile',
array( $title, $file, &$html, &$attribs, &$ret ) ) ) {
wfDebug( "Hook LinkerMakeMediaLinkFile changed the output of link "
. "with url {$url} and text {$html} to {$ret}\n", true );
}
$attribs['rel'] = Parser::getExternalLinkRel( $url, $title );
$link = '';
- $success = wfRunHooks( 'LinkerMakeExternalLink',
+ $success = Hooks::run( 'LinkerMakeExternalLink',
array( &$url, &$text, &$link, &$attribs, $linktype ) );
if ( !$success ) {
wfDebug( "Hook LinkerMakeExternalLink changed the output of link "
$items[] = self::emailLink( $userId, $userText );
}
- wfRunHooks( 'UserToolLinksEdit', array( $userId, $userText, &$items ) );
+ Hooks::run( 'UserToolLinksEdit', array( $userId, $userText, &$items ) );
if ( $items ) {
return wfMessage( 'word-separator' )->plain()
$auto = $match[2];
$post = $match[3];
$comment = null;
- wfRunHooks( 'FormatAutocomments', array( &$comment, $pre, $auto, $post, $title, $local ) );
+ Hooks::run( 'FormatAutocomments', array( &$comment, $pre, $auto, $post, $title, $local ) );
if ( $comment === null ) {
$link = '';
if ( $title ) {
/**
* @since 1.20
*/
- wfRunHooks( 'NamespaceIsMovable', array( $index, &$result ) );
+ Hooks::run( 'NamespaceIsMovable', array( $index, &$result ) );
return $result;
}
if ( is_array( $wgExtraNamespaces ) ) {
$namespaces += $wgExtraNamespaces;
}
- wfRunHooks( 'CanonicalNamespaces', array( &$namespaces ) );
+ Hooks::run( 'CanonicalNamespaces', array( &$namespaces ) );
}
return $namespaces;
}
$offsetRel = $relativeTo->offsetForUser( $user );
$ts = '';
- if ( wfRunHooks( 'GetHumanTimestamp', array( &$ts, $this, $relativeTo, $user, $lang ) ) ) {
+ if ( Hooks::run( 'GetHumanTimestamp', array( &$ts, $this, $relativeTo, $user, $lang ) ) ) {
$ts = $lang->getHumanTimestamp( $this, $relativeTo, $user );
}
$ts = '';
$diff = $this->diff( $relativeTo );
- if ( wfRunHooks(
+ if ( Hooks::run(
'GetRelativeTimestamp',
array( &$ts, &$diff, $this, $relativeTo, $user, $lang )
) ) {
static function getVariableIDs() {
if ( !self::$mVariableIDsInitialised ) {
# Get variable IDs
- wfRunHooks( 'MagicWordwgVariableIDs', array( &self::$mVariableIDs ) );
+ Hooks::run( 'MagicWordwgVariableIDs', array( &self::$mVariableIDs ) );
self::$mVariableIDsInitialised = true;
}
return self::$mVariableIDs;
*/
static function getDoubleUnderscoreArray() {
if ( is_null( self::$mDoubleUnderscoreArray ) ) {
- wfRunHooks( 'GetDoubleUnderscoreIDs', array( &self::$mDoubleUnderscoreIDs ) );
+ Hooks::run( 'GetDoubleUnderscoreIDs', array( &self::$mDoubleUnderscoreIDs ) );
self::$mDoubleUnderscoreArray = new MagicWordArray( self::$mDoubleUnderscoreIDs );
}
return self::$mDoubleUnderscoreArray;
}
$unused = null; // To pass it by reference
- wfRunHooks( 'BeforeInitialize', array( &$title, &$unused, &$output, &$user, $request, $this ) );
+ Hooks::run( 'BeforeInitialize', array( &$title, &$unused, &$output, &$user, $request, $this ) );
// Invalid titles. Bug 21776: The interwikis must redirect even if the page name is empty.
if ( is_null( $title ) || ( $title->getDBkey() == '' && !$title->isExternal() )
&& ( $request->getVal( 'title' ) === null
|| $title->getPrefixedDBkey() != $request->getVal( 'title' ) )
&& !count( $request->getValueNames( array( 'action', 'title' ) ) )
- && wfRunHooks( 'TestCanonicalRedirect', array( $request, $title, $output ) )
+ && Hooks::run( 'TestCanonicalRedirect', array( $request, $title, $output ) )
) {
if ( $title->isSpecialPage() ) {
list( $name, $subpage ) = SpecialPageFactory::resolveAlias( $title->getDBkey() );
// Give extensions a change to ignore/handle redirects as needed
$ignoreRedirect = $target = false;
- wfRunHooks( 'InitializeArticleMaybeRedirect',
+ Hooks::run( 'InitializeArticleMaybeRedirect',
array( &$title, &$request, &$ignoreRedirect, &$target, &$article ) );
// Follow redirects only for... redirects.
$title = $this->context->getTitle();
$user = $this->context->getUser();
- if ( !wfRunHooks( 'MediaWikiPerformAction',
+ if ( !Hooks::run( 'MediaWikiPerformAction',
array( $output, $page, $title, $user, $request, $this ) )
) {
wfProfileOut( __METHOD__ );
return;
}
- if ( wfRunHooks( 'UnknownAction', array( $request->getVal( 'action', 'view' ), $page ) ) ) {
+ if ( Hooks::run( 'UnknownAction', array( $request->getVal( 'action', 'view' ), $page ) ) ) {
$output->setStatusCode( 404 );
$output->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
}
$redirUrl = preg_replace( '#^http://#', 'https://', $oldUrl );
// ATTENTION: This hook is likely to be removed soon due to overall design of the system.
- if ( wfRunHooks( 'BeforeHttpsRedirect', array( $this->context, &$redirUrl ) ) ) {
+ if ( Hooks::run( 'BeforeHttpsRedirect', array( $this->context, &$redirUrl ) ) ) {
if ( $request->wasPosted() ) {
// This is weird and we'd hope it almost never happens. This
global $IP;
# Allow media handling extensions adding MIME-types and MIME-info
- wfRunHooks( 'MimeMagicInit', array( $this ) );
+ Hooks::run( 'MimeMagicInit', array( $this ) );
$types = MM_WELL_KNOWN_MIME_TYPES;
}
# Media handling extensions can improve the MIME detected
- wfRunHooks( 'MimeMagicImproveFromExtension', array( $this, $ext, &$mime ) );
+ Hooks::run( 'MimeMagicImproveFromExtension', array( $this, $ext, &$mime ) );
if ( isset( $this->mMimeTypeAliases[$mime] ) ) {
$mime = $this->mMimeTypeAliases[$mime];
# people will hopefully nag and submit patches :)
$mime = false;
# Some strings by reference for performance - assuming well-behaved hooks
- wfRunHooks(
+ Hooks::run(
'MimeMagicGuessFromContent',
array( $this, &$head, &$tail, $file, &$mime )
);
}
}
- wfRunHooks( 'MovePageCheckPermissions',
+ Hooks::run( 'MovePageCheckPermissions',
array( $this->oldTitle, $this->newTitle, $user, $reason, $status )
);
}
// Hook for extensions to say a title can't be moved for technical reasons
- wfRunHooks( 'MovePageIsValidMove', array( $this->oldTitle, $this->newTitle, $status ) );
+ Hooks::run( 'MovePageIsValidMove', array( $this->oldTitle, $this->newTitle, $status ) );
return $status;
}
public function move( User $user, $reason, $createRedirect ) {
global $wgCategoryCollation;
- wfRunHooks( 'TitleMove', array( $this->oldTitle, $this->newTitle, $user ) );
+ Hooks::run( 'TitleMove', array( $this->oldTitle, $this->newTitle, $user ) );
// If it is a file, move it first.
// It is done before all other moving stuff is done because it's hard to revert.
$dbw->commit( __METHOD__ );
- wfRunHooks( 'TitleMoveComplete', array( &$this->oldTitle, &$this->newTitle, &$user, $pageid, $redirid, $reason ) );
+ Hooks::run( 'TitleMoveComplete', array( &$this->oldTitle, &$this->newTitle, &$user, $pageid, $redirid, $reason ) );
return Status::newGood();
}
$newpage->updateRevisionOn( $dbw, $nullRevision );
- wfRunHooks( 'NewRevisionFromEditComplete',
+ Hooks::run( 'NewRevisionFromEditComplete',
array( $newpage, $nullRevision, $nullRevision->getParentId(), $user ) );
$newpage->doEditUpdates( $nullRevision, $user,
$redirectRevision->insertOn( $dbw );
$redirectArticle->updateRevisionOn( $dbw, $redirectRevision, 0 );
- wfRunHooks( 'NewRevisionFromEditComplete',
+ Hooks::run( 'NewRevisionFromEditComplete',
array( $redirectArticle, $redirectRevision, false, $user ) );
$redirectArticle->doEditUpdates( $redirectRevision, $user, array( 'created' => true ) );
$headers = headers_list();
$foundVary = false;
foreach ( $headers as $header ) {
- if ( substr( $header, 0, 5 ) == 'Vary:' ) {
+ $headerName = strtolower( substr( $header, 0, 5 ) );
+ if ( $headerName == 'vary:' ) {
$foundVary = true;
break;
}
// bug 44570: the core page itself may not change, but resources might
$modifiedTimes['sepoch'] = wfTimestamp( TS_MW, time() - $config->get( 'SquidMaxage' ) );
}
- wfRunHooks( 'OutputPageCheckLastModified', array( &$modifiedTimes ) );
+ Hooks::run( 'OutputPageCheckLastModified', array( &$modifiedTimes ) );
$maxModified = max( $modifiedTimes );
$this->mLastModified = wfTimestamp( TS_RFC2822, $maxModified );
}
# Add the remaining categories to the skin
- if ( wfRunHooks(
+ if ( Hooks::run(
'OutputPageMakeCategoryLinks',
array( &$this, $categories, &$this->mCategoryLinks ) )
) {
// Link flags are ignored for now, but may in the future be
// used to mark individual language links.
$linkFlags = array();
- wfRunHooks( 'LanguageLinks', array( $this->getTitle(), &$this->mLanguageLinks, &$linkFlags ) );
- wfRunHooks( 'OutputPageParserOutput', array( &$this, $parserOutput ) );
+ Hooks::run( 'LanguageLinks', array( $this->getTitle(), &$this->mLanguageLinks, &$linkFlags ) );
+ Hooks::run( 'OutputPageParserOutput', array( &$this, $parserOutput ) );
}
/**
*/
public function addParserOutputText( $parserOutput ) {
$text = $parserOutput->getText();
- wfRunHooks( 'OutputPageBeforeHTML', array( &$this, &$text ) );
+ Hooks::run( 'OutputPageBeforeHTML', array( &$this, &$text ) );
$this->addHTML( $text );
}
),
$config->get( 'CacheVaryCookies' )
);
- wfRunHooks( 'GetCacheVaryCookies', array( $this, &$cookies ) );
+ Hooks::run( 'GetCacheVaryCookies', array( $this, &$cookies ) );
}
return $cookies;
}
$redirect = $this->mRedirect;
$code = $this->mRedirectCode;
- if ( wfRunHooks( "BeforePageRedirect", array( $this, &$redirect, &$code ) ) ) {
+ if ( Hooks::run( "BeforePageRedirect", array( $this, &$redirect, &$code ) ) ) {
if ( $code == '301' || $code == '303' ) {
if ( !$config->get( 'DebugRedirects' ) ) {
$message = HttpStatus::getMessage( $code );
// Hook that allows last minute changes to the output page, e.g.
// adding of CSS or Javascript by extensions.
- wfRunHooks( 'BeforePageDisplay', array( &$this, &$sk ) );
+ Hooks::run( 'BeforePageDisplay', array( &$this, &$sk ) );
wfProfileIn( 'Output-skin' );
$sk->outputPage();
}
// This hook allows last minute changes to final overall output by modifying output buffer
- wfRunHooks( 'AfterFinalPageOutput', array( $this ) );
+ Hooks::run( 'AfterFinalPageOutput', array( $this ) );
$this->sendCacheControl();
// Allow skins and extensions to add body attributes they need
$sk->addToBodyAttributes( $this, $bodyAttrs );
- wfRunHooks( 'OutputPageBodyAttributes', array( $this, $sk, &$bodyAttrs ) );
+ Hooks::run( 'OutputPageBodyAttributes', array( $this, $sk, &$bodyAttrs ) );
$ret .= Html::openElement( 'body', $bodyAttrs ) . "\n";
// Use the 'ResourceLoaderGetConfigVars' hook if the variable is not
// page-dependant but site-wide (without state).
// Alternatively, you may want to use OutputPage->addJsConfigVars() instead.
- wfRunHooks( 'MakeGlobalVariablesScript', array( &$vars, $this ) );
+ Hooks::run( 'MakeGlobalVariablesScript', array( &$vars, $this ) );
// Merge in variables from addJsConfigVars last
return array_merge( $vars, $this->getJsConfigVars() );
self::searchPreferences( $user, $context, $defaultPreferences );
self::miscPreferences( $user, $context, $defaultPreferences );
- wfRunHooks( 'GetPreferences', array( $user, &$defaultPreferences ) );
+ Hooks::run( 'GetPreferences', array( $user, &$defaultPreferences ) );
self::loadPreferenceValues( $user, $context, $defaultPreferences );
self::$defaultPreferences = $defaultPreferences;
$user->setOption( $key, $value );
}
- wfRunHooks( 'PreferencesFormPreSave', array( $formData, $form, $user, &$result ) );
+ Hooks::run( 'PreferencesFormPreSave', array( $formData, $form, $user, &$result ) );
$user->saveSettings();
}
*/
function getLegend( $key ) {
$legend = parent::getLegend( $key );
- wfRunHooks( 'PreferencesGetLegend', array( $this, $key, &$legend ) );
+ Hooks::run( 'PreferencesGetLegend', array( $this, $key, &$legend ) );
return $legend;
}
}
$search = $title->getText();
if ( $ns[0] == NS_MAIN ) {
$ns = $namespaces; // no explicit prefix, use default namespaces
- wfRunHooks( 'PrefixSearchExtractNamespace', array( &$ns, &$search ) );
+ Hooks::run( 'PrefixSearchExtractNamespace', array( &$ns, &$search ) );
}
return $this->searchBackend( $ns, $search, $limit, $offset );
}
$namespaces = array( $title->getNamespace() );
$search = '';
} else {
- wfRunHooks( 'PrefixSearchExtractNamespace', array( &$namespaces, &$search ) );
+ Hooks::run( 'PrefixSearchExtractNamespace', array( &$namespaces, &$search ) );
}
return $this->searchBackend( $namespaces, $search, $limit, $offset );
}
}
$srchres = array();
- if ( wfRunHooks( 'PrefixSearchBackend', array( $namespaces, $search, $limit, &$srchres, $offset ) ) ) {
+ if ( Hooks::run( 'PrefixSearchBackend', array( $namespaces, $search, $limit, &$srchres, $offset ) ) ) {
return $this->titles( $this->defaultSearchBackend( $namespaces, $search, $limit, $offset ) );
}
return $this->strings( $this->handleResultFromHook( $srchres, $namespaces, $search, $limit ) );
* you can also return an array of message name and its parameters
*/
$errorMsg = '';
- if ( !wfRunHooks( 'ProtectionForm::save', array( $this->mArticle, &$errorMsg, $reasonstr ) ) ) {
+ if ( !Hooks::run( 'ProtectionForm::save', array( $this->mArticle, &$errorMsg, $reasonstr ) ) ) {
if ( $errorMsg == '' ) {
$errorMsg = array( 'hookaborted' );
}
"</td></tr>";
}
# Give extensions a chance to add items to the form
- wfRunHooks( 'ProtectionForm::buildForm', array( $this->mArticle, &$out ) );
+ Hooks::run( 'ProtectionForm::buildForm', array( $this->mArticle, &$out ) );
$out .= Xml::closeElement( 'tbody' ) . Xml::closeElement( 'table' );
$out->addHTML( Xml::element( 'h2', null, $protectLogPage->getName()->text() ) );
LogEventsList::showLogExtract( $out, 'protect', $this->mTitle );
# Let extensions add other relevant log extracts
- wfRunHooks( 'ProtectionForm::showLogExtract', array( $this->mArticle, $out ) );
+ Hooks::run( 'ProtectionForm::showLogExtract', array( $this->mArticle, $out ) );
}
}
$this->mId = $rev_id !== null ? $rev_id : $dbw->insertId();
- wfRunHooks( 'RevisionInsertComplete', array( &$this, $data, $flags ) );
+ Hooks::run( 'RevisionInsertComplete', array( &$this, $data, $flags ) );
wfProfileOut( __METHOD__ );
return $this->mId;
*/
public static function validateEmail( $addr ) {
$result = null;
- if ( !wfRunHooks( 'isValidEmailAddr', array( $addr, &$result ) ) ) {
+ if ( !Hooks::run( 'isValidEmailAddr', array( $addr, &$result ) ) ) {
return $result;
}
wfProfileOut( $fname . '-memcached' );
// Most of the config is out, some might want to run hooks here.
-wfRunHooks( 'SetupAfterCache' );
+Hooks::run( 'SetupAfterCache' );
wfProfileIn( $fname . '-session' );
if ( !is_object( $wgAuth ) ) {
$wgAuth = new AuthPlugin;
- wfRunHooks( 'AuthPluginSetup', array( &$wgAuth ) );
+ Hooks::run( 'AuthPluginSetup', array( &$wgAuth ) );
}
/**
* @param string $title The DB key form the title
* @param string $fragment The link fragment (after the "#")
* @param string $interwiki The interwiki prefix
- * @param boolean $canoncialNamespace If true, use the canonical name for
+ * @param bool $canoncialNamespace If true, use the canonical name for
* $ns instead of the localized version.
* @return string The prefixed form of the title
*/
}
$result = true;
- wfRunHooks( 'TitleIsMovable', array( $this, &$result ) );
+ Hooks::run( 'TitleIsMovable', array( $this, &$result ) );
return $result;
}
# It's called here again to make sure hook functions can force this
# method to return true even outside the MediaWiki namespace.
- wfRunHooks( 'TitleIsCssOrJsPage', array( $this, &$isCssOrJsPage ), '1.25' );
+ Hooks::run( 'TitleIsCssOrJsPage', array( $this, &$isCssOrJsPage ), '1.25' );
return $isCssOrJsPage;
}
# Finally, add the fragment.
$url .= $this->getFragmentForURL();
- wfRunHooks( 'GetFullURL', array( &$this, &$url, $query ) );
+ Hooks::run( 'GetFullURL', array( &$this, &$url, $query ) );
return $url;
}
$dbkey = wfUrlencode( $this->getPrefixedDBkey() );
if ( $query == '' ) {
$url = str_replace( '$1', $dbkey, $wgArticlePath );
- wfRunHooks( 'GetLocalURL::Article', array( &$this, &$url ) );
+ Hooks::run( 'GetLocalURL::Article', array( &$this, &$url ) );
} else {
global $wgVariantArticlePath, $wgActionPaths, $wgContLang;
$url = false;
}
}
- wfRunHooks( 'GetLocalURL::Internal', array( &$this, &$url, $query ) );
+ Hooks::run( 'GetLocalURL::Internal', array( &$this, &$url, $query ) );
// @todo FIXME: This causes breakage in various places when we
// actually expected a local URL and end up with dupe prefixes.
$url = $wgServer . $url;
}
}
- wfRunHooks( 'GetLocalURL', array( &$this, &$url, $query ) );
+ Hooks::run( 'GetLocalURL', array( &$this, &$url, $query ) );
return $url;
}
$query = self::fixUrlQueryArgs( $query, $query2 );
$server = $wgInternalServer !== false ? $wgInternalServer : $wgServer;
$url = wfExpandUrl( $server . $this->getLocalURL( $query ), PROTO_HTTP );
- wfRunHooks( 'GetInternalURL', array( &$this, &$url, $query ) );
+ Hooks::run( 'GetInternalURL', array( &$this, &$url, $query ) );
return $url;
}
public function getCanonicalURL( $query = '', $query2 = false ) {
$query = self::fixUrlQueryArgs( $query, $query2 );
$url = wfExpandUrl( $this->getLocalURL( $query ) . $this->getFragmentForURL(), PROTO_CANONICAL );
- wfRunHooks( 'GetCanonicalURL', array( &$this, &$url, $query ) );
+ Hooks::run( 'GetCanonicalURL', array( &$this, &$url, $query ) );
return $url;
}
private function checkQuickPermissions( $action, $user, $errors,
$doExpensiveQueries, $short
) {
- if ( !wfRunHooks( 'TitleQuickPermissions',
+ if ( !Hooks::run( 'TitleQuickPermissions',
array( $this, $user, $action, &$errors, $doExpensiveQueries, $short ) )
) {
return $errors;
private function checkPermissionHooks( $action, $user, $errors, $doExpensiveQueries, $short ) {
// Use getUserPermissionsErrors instead
$result = '';
- if ( !wfRunHooks( 'userCan', array( &$this, &$user, $action, &$result ) ) ) {
+ if ( !Hooks::run( 'userCan', array( &$this, &$user, $action, &$result ) ) ) {
return $result ? array() : array( array( 'badaccess-group0' ) );
}
// Check getUserPermissionsErrors hook
- if ( !wfRunHooks( 'getUserPermissionsErrors', array( &$this, &$user, $action, &$result ) ) ) {
+ if ( !Hooks::run( 'getUserPermissionsErrors', array( &$this, &$user, $action, &$result ) ) ) {
$errors = $this->resultToError( $errors, $result );
}
// Check getUserPermissionsErrorsExpensive hook
if (
$doExpensiveQueries
&& !( $short && count( $errors ) > 0 )
- && !wfRunHooks( 'getUserPermissionsErrorsExpensive', array( &$this, &$user, $action, &$result ) )
+ && !Hooks::run( 'getUserPermissionsErrorsExpensive', array( &$this, &$user, $action, &$result ) )
) {
$errors = $this->resultToError( $errors, $result );
}
if ( !$whitelisted ) {
# If the title is not whitelisted, give extensions a chance to do so...
- wfRunHooks( 'TitleReadWhitelist', array( $this, $user, &$whitelisted ) );
+ Hooks::run( 'TitleReadWhitelist', array( $this, $user, &$whitelisted ) );
if ( !$whitelisted ) {
$errors[] = $this->missingPermissionError( $action, $short );
}
$types = array_diff( $types, array( 'upload' ) );
}
- wfRunHooks( 'TitleGetRestrictionTypes', array( $this, &$types ) );
+ Hooks::run( 'TitleGetRestrictionTypes', array( $this, &$types ) );
wfDebug( __METHOD__ . ': applicable restrictions to [[' .
$this->getPrefixedText() . ']] are {' . implode( ',', $types ) . "}\n" );
$urls[] = $this->getInternalUrl( 'action=raw&ctype=text/css' );
}
- wfRunHooks( 'TitleSquidURLs', array( $this, &$urls ) );
+ Hooks::run( 'TitleSquidURLs', array( $this, &$urls ) );
return $urls;
}
*/
public function exists() {
$exists = $this->getArticleID() != 0;
- wfRunHooks( 'TitleExists', array( $this, &$exists ) );
+ Hooks::run( 'TitleExists', array( $this, &$exists ) );
return $exists;
}
* @param Title $title
* @param bool|null $isKnown
*/
- wfRunHooks( 'TitleIsAlwaysKnown', array( $this, &$isKnown ) );
+ Hooks::run( 'TitleIsAlwaysKnown', array( $this, &$isKnown ) );
if ( !is_null( $isKnown ) ) {
return $isKnown;
// on the Title object passed in, and should probably
// tell the users to run updateCollations.php --force
// in order to re-sort existing category relations.
- wfRunHooks( 'GetDefaultSortkey', array( $this, &$unprefixed ) );
+ Hooks::run( 'GetDefaultSortkey', array( $this, &$unprefixed ) );
if ( $prefix !== '' ) {
# Separate with a line feed, so the unprefixed part is only used as
# a tiebreaker when two pages have the exact same prefix.
}
}
- wfRunHooks( 'TitleGetEditNotices', array( $this, $oldid, &$notices ) );
+ Hooks::run( 'TitleGetEditNotices', array( $this, $oldid, &$notices ) );
return $notices;
}
}
*/
static function newFromResult( $res ) {
$array = null;
- if ( !wfRunHooks( 'TitleArrayFromResult', array( &$array, $res ) ) ) {
+ if ( !Hooks::run( 'TitleArrayFromResult', array( &$array, $res ) ) ) {
return null;
}
if ( $array === null ) {
// Loading from session failed. Load defaults.
$this->loadDefaults();
}
- wfRunHooks( 'UserLoadAfterLoadFromSession', array( $this ) );
+ Hooks::run( 'UserLoadAfterLoadFromSession', array( $this ) );
break;
default:
wfProfileOut( __METHOD__ );
static $reservedUsernames = false;
if ( !$reservedUsernames ) {
$reservedUsernames = $wgReservedUsernames;
- wfRunHooks( 'UserGetReservedNames', array( &$reservedUsernames ) );
+ Hooks::run( 'UserGetReservedNames', array( &$reservedUsernames ) );
}
// Certain names may be reserved for batch processes.
$result = false; //init $result to false for the internal checks
- if ( !wfRunHooks( 'isValidPassword', array( $password, &$result, $this ) ) ) {
+ if ( !Hooks::run( 'isValidPassword', array( $password, &$result, $this ) ) ) {
$status->error( $result );
return $status;
}
);
}
// Give extensions a chance to force an expiration
- wfRunHooks( 'ResetPasswordExpiration', array( $this, &$newExpire ) );
+ Hooks::run( 'ResetPasswordExpiration', array( $this, &$newExpire ) );
$this->mPasswordExpires = $newExpire;
}
$this->mRegistration = wfTimestamp( TS_MW );
$this->mGroups = array();
- wfRunHooks( 'UserLoadDefaults', array( $this, $name ) );
+ Hooks::run( 'UserLoadDefaults', array( $this, $name ) );
wfProfileOut( __METHOD__ );
}
*/
private function loadFromSession() {
$result = null;
- wfRunHooks( 'UserLoadFromSession', array( $this, &$result ) );
+ Hooks::run( 'UserLoadFromSession', array( $this, &$result ) );
if ( $result !== null ) {
return $result;
}
: array()
);
- wfRunHooks( 'UserLoadFromDatabase', array( $this, &$s ) );
+ Hooks::run( 'UserLoadFromDatabase', array( $this, &$s ) );
if ( $s !== false ) {
// Initialise user table data
}
$defOpt['skin'] = Skin::normalizeKey( $wgDefaultSkin );
- wfRunHooks( 'UserGetDefaultOptions', array( &$defOpt ) );
+ Hooks::run( 'UserGetDefaultOptions', array( &$defOpt ) );
return $defOpt;
}
}
// Extensions
- wfRunHooks( 'GetBlockedStatus', array( &$this ) );
+ Hooks::run( 'GetBlockedStatus', array( &$this ) );
wfProfileOut( __METHOD__ );
}
public function pingLimiter( $action = 'edit', $incrBy = 1 ) {
// Call the 'PingLimiter' hook
$result = false;
- if ( !wfRunHooks( 'PingLimiter', array( &$this, $action, &$result, $incrBy ) ) ) {
+ if ( !Hooks::run( 'PingLimiter', array( &$this, $action, &$result, $incrBy ) ) ) {
return $result;
}
wfDebug( __METHOD__ . ": self-talk page, ignoring any blocks\n" );
}
- wfRunHooks( 'UserIsBlockedFrom', array( $this, $title, &$blocked, &$allowUsertalk ) );
+ Hooks::run( 'UserIsBlockedFrom', array( $this, $title, &$blocked, &$allowUsertalk ) );
wfProfileOut( __METHOD__ );
return $blocked;
$ip = $this->getRequest()->getIP();
}
$blocked = false;
- wfRunHooks( 'UserIsBlockedGlobally', array( &$this, $ip, &$blocked ) );
+ Hooks::run( 'UserIsBlockedGlobally', array( &$this, $ip, &$blocked ) );
$this->mBlockedGlobally = (bool)$blocked;
return $this->mBlockedGlobally;
}
*/
public function getNewMessageLinks() {
$talks = array();
- if ( !wfRunHooks( 'UserRetrieveNewTalks', array( &$this, &$talks ) ) ) {
+ if ( !Hooks::run( 'UserRetrieveNewTalks', array( &$this, &$talks ) ) ) {
return $talks;
} elseif ( !$this->getNewtalk() ) {
return array();
*/
public function getEmail() {
$this->load();
- wfRunHooks( 'UserGetEmail', array( $this, &$this->mEmail ) );
+ Hooks::run( 'UserGetEmail', array( $this, &$this->mEmail ) );
return $this->mEmail;
}
*/
public function getEmailAuthenticationTimestamp() {
$this->load();
- wfRunHooks( 'UserGetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
+ Hooks::run( 'UserGetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
return $this->mEmailAuthenticated;
}
}
$this->invalidateEmail();
$this->mEmail = $str;
- wfRunHooks( 'UserSetEmail', array( $this, &$this->mEmail ) );
+ Hooks::run( 'UserSetEmail', array( $this, &$this->mEmail ) );
}
/**
}
}
- wfRunHooks( 'UserResetAllOptions', array( $this, &$newOptions, $this->mOptions, $resetKinds ) );
+ Hooks::run( 'UserResetAllOptions', array( $this, &$newOptions, $this->mOptions, $resetKinds ) );
$this->mOptions = $newOptions;
$this->mOptionsLoaded = true;
return false;
} else {
$https = $this->getBoolOption( 'prefershttps' );
- wfRunHooks( 'UserRequiresHTTPS', array( $this, &$https ) );
+ Hooks::run( 'UserRequiresHTTPS', array( $this, &$https ) );
if ( $https ) {
$https = wfCanIPUseHTTPS( $this->getRequest()->getIP() );
}
public function getRights() {
if ( is_null( $this->mRights ) ) {
$this->mRights = self::getGroupPermissions( $this->getEffectiveGroups() );
- wfRunHooks( 'UserGetRights', array( $this, &$this->mRights ) );
+ Hooks::run( 'UserGetRights', array( $this, &$this->mRights ) );
// Force reindexation of rights when a hook has unset one of them
$this->mRights = array_values( array_unique( $this->mRights ) );
}
$this->getAutomaticGroups( $recache ) // implicit groups
) );
// Hook for additional groups
- wfRunHooks( 'UserEffectiveGroups', array( &$this, &$this->mEffectiveGroups ) );
+ Hooks::run( 'UserEffectiveGroups', array( &$this, &$this->mEffectiveGroups ) );
// Force reindexation of groups when a hook has unset one of them
$this->mEffectiveGroups = array_values( array_unique( $this->mEffectiveGroups ) );
wfProfileOut( __METHOD__ );
* @param string $group Name of the group to add
*/
public function addGroup( $group ) {
- if ( wfRunHooks( 'UserAddGroup', array( $this, &$group ) ) ) {
+ if ( Hooks::run( 'UserAddGroup', array( $this, &$group ) ) ) {
$dbw = wfGetDB( DB_MASTER );
if ( $this->getId() ) {
$dbw->insert( 'user_groups',
*/
public function removeGroup( $group ) {
$this->load();
- if ( wfRunHooks( 'UserRemoveGroup', array( $this, &$group ) ) ) {
+ if ( Hooks::run( 'UserRemoveGroup', array( $this, &$group ) ) ) {
$dbw = wfGetDB( DB_MASTER );
$dbw->delete( 'user_groups',
array(
// If we're working on user's talk page, we should update the talk page message indicator
if ( $title->getNamespace() == NS_USER_TALK && $title->getText() == $this->getName() ) {
- if ( !wfRunHooks( 'UserClearNewTalkNotification', array( &$this, $oldid ) ) ) {
+ if ( !Hooks::run( 'UserClearNewTalkNotification', array( &$this, $oldid ) ) ) {
return;
}
$cookies['Token'] = false;
}
- wfRunHooks( 'UserSetCookies', array( $this, &$session, &$cookies ) );
+ Hooks::run( 'UserSetCookies', array( $this, &$session, &$cookies ) );
foreach ( $session as $name => $value ) {
$request->setSessionData( $name, $value );
* Log this user out.
*/
public function logout() {
- if ( wfRunHooks( 'UserLogout', array( &$this ) ) ) {
+ if ( Hooks::run( 'UserLogout', array( &$this ) ) ) {
$this->doLogout();
}
}
$this->saveOptions();
- wfRunHooks( 'UserSaveSettings', array( $this ) );
+ Hooks::run( 'UserSaveSettings', array( $this ) );
$this->clearSharedCache();
$this->getUserPage()->invalidateCache();
}
// and fire the ConfirmEmailComplete hook on redundant confirmations.
if ( !$this->isEmailConfirmed() ) {
$this->setEmailAuthenticationTimestamp( wfTimestampNow() );
- wfRunHooks( 'ConfirmEmailComplete', array( $this ) );
+ Hooks::run( 'ConfirmEmailComplete', array( $this ) );
}
return true;
}
$this->mEmailTokenExpires = null;
$this->setEmailAuthenticationTimestamp( null );
$this->mEmail = '';
- wfRunHooks( 'InvalidateEmailComplete', array( $this ) );
+ Hooks::run( 'InvalidateEmailComplete', array( $this ) );
return true;
}
public function setEmailAuthenticationTimestamp( $timestamp ) {
$this->load();
$this->mEmailAuthenticated = $timestamp;
- wfRunHooks( 'UserSetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
+ Hooks::run( 'UserSetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
}
/**
return false;
}
$canSend = $this->isEmailConfirmed();
- wfRunHooks( 'UserCanSendEmail', array( &$this, &$canSend ) );
+ Hooks::run( 'UserCanSendEmail', array( &$this, &$canSend ) );
return $canSend;
}
global $wgEmailAuthentication;
$this->load();
$confirmed = true;
- if ( wfRunHooks( 'EmailConfirmed', array( &$this, &$confirmed ) ) ) {
+ if ( Hooks::run( 'EmailConfirmed', array( &$this, &$confirmed ) ) ) {
if ( $this->isAnon() ) {
return false;
}
}
// Allow extensions (e.g. OAuth) to say false
- if ( !wfRunHooks( 'UserIsEveryoneAllowed', array( $right ) ) ) {
+ if ( !Hooks::run( 'UserIsEveryoneAllowed', array( $right ) ) ) {
$cache[$right] = false;
return false;
}
} else {
self::$mAllRights = self::$mCoreRights;
}
- wfRunHooks( 'UserGetAllRights', array( &self::$mAllRights ) );
+ Hooks::run( 'UserGetAllRights', array( &self::$mAllRights ) );
}
return self::$mAllRights;
}
$groups = $wgImplicitGroups;
# Deprecated, use $wgImplicitGroups instead
- wfRunHooks( 'UserGetImplicitGroups', array( &$groups ), '1.25' );
+ Hooks::run( 'UserGetImplicitGroups', array( &$groups ), '1.25' );
return $groups;
}
$this->mOptionsLoaded = true;
- wfRunHooks( 'UserLoadOptions', array( $this, &$this->mOptions ) );
+ Hooks::run( 'UserLoadOptions', array( $this, &$this->mOptions ) );
}
/**
// Allow hooks to abort, for instance to save to a global profile.
// Reset options to default state before saving.
- if ( !wfRunHooks( 'UserSaveOptions', array( $this, &$saveOptions ) ) ) {
+ if ( !Hooks::run( 'UserSaveOptions', array( $this, &$saveOptions ) ) ) {
return;
}
*/
static function newFromResult( $res ) {
$userArray = null;
- if ( !wfRunHooks( 'UserArrayFromResult', array( &$userArray, $res ) ) ) {
+ if ( !Hooks::run( 'UserArrayFromResult', array( &$userArray, $res ) ) ) {
return null;
}
if ( $userArray === null ) {
);
}
- wfRunHooks( 'WebRequestPathInfoRouter', array( $router ) );
+ Hooks::run( 'WebRequestPathInfoRouter', array( $router ) );
$matches = $router->parse( $path );
}
}
# Allow extensions to improve our guess
- wfRunHooks( 'GetIP', array( &$ip ) );
+ Hooks::run( 'GetIP', array( &$ip ) );
if ( !$ip ) {
throw new MWException( "Unable to determine IP." );
$func = $options['raw'] ? 'setrawcookie' : 'setcookie';
- if ( wfRunHooks( 'WebResponseSetCookie', array( &$name, &$value, &$expire, $options ) ) ) {
+ if ( Hooks::run( 'WebResponseSetCookie', array( &$name, &$value, &$expire, $options ) ) ) {
wfDebugLog( 'cookie',
$func . ': "' . implode( '", "',
array(
public static function label( $label, $id, $attribs = array() ) {
$a = array( 'for' => $id );
- # FIXME avoid copy pasting below:
- if ( isset( $attribs['class'] ) ) {
- $a['class'] = $attribs['class'];
- }
- if ( isset( $attribs['title'] ) ) {
- $a['title'] = $attribs['title'];
+ foreach ( array( 'class', 'title' ) as $attr ) {
+ if ( isset( $attribs[$attr] ) ) {
+ $a[$attr] = $attribs[$attr];
+ }
}
return self::element( 'label', $a, $label );
$page = $this->page;
$user = $this->getUser();
- if ( wfRunHooks( 'CustomEditor', array( $page, $user ) ) ) {
+ if ( Hooks::run( 'CustomEditor', array( $page, $user ) ) ) {
$editor = new EditPage( $page );
$editor->edit();
}
$this->fields = $this->getFormFields();
// Give hooks a chance to alter the form, adding extra fields or text etc
- wfRunHooks( 'ActionModifyFormFields', array( $this->getName(), &$this->fields, $this->page ) );
+ Hooks::run( 'ActionModifyFormFields', array( $this->getName(), &$this->fields, $this->page ) );
$form = new HTMLForm( $this->fields, $this->getContext(), $this->getName() );
$form->setSubmitCallback( array( $this, 'onSubmit' ) );
$this->alterForm( $form );
// Give hooks a chance to alter the form, adding extra fields or text etc
- wfRunHooks( 'ActionBeforeFormDisplay', array( $this->getName(), &$form, $this->page ) );
+ Hooks::run( 'ActionBeforeFormDisplay', array( $this->getName(), &$form, $this->page ) );
return $form;
}
'</fieldset></form>'
);
- wfRunHooks( 'PageHistoryBeforeList', array( &$this->page, $this->getContext() ) );
+ Hooks::run( 'PageHistoryBeforeList', array( &$this->page, $this->getContext() ) );
// Create and output the list.
$pager = new HistoryPager( $this, $year, $month, $tagFilter, $conds );
$queryInfo['options'],
$this->tagFilter
);
- wfRunHooks( 'PageHistoryPager::getQueryInfo', array( &$this, &$queryInfo ) );
+ Hooks::run( 'PageHistoryPager::getQueryInfo', array( &$this, &$queryInfo ) );
return $queryInfo;
}
}
}
// Allow extension to add their own links here
- wfRunHooks( 'HistoryRevisionTools', array( $rev, &$tools ) );
+ Hooks::run( 'HistoryRevisionTools', array( $rev, &$tools ) );
if ( $tools ) {
$s2 .= ' ' . $this->msg( 'parentheses' )->rawParams( $lang->pipeList( $tools ) )->escaped();
$s .= ' <span class="mw-changeslist-separator">. .</span> ' . $s2;
}
- wfRunHooks( 'PageHistoryLineEnding', array( $this, &$row, &$s, &$classes ) );
+ Hooks::run( 'PageHistoryLineEnding', array( $this, &$row, &$s, &$classes ) );
$attribs = array();
if ( $classes ) {
$pageInfo = $this->pageInfo();
// Allow extensions to add additional information
- wfRunHooks( 'InfoAction', array( $this->getContext(), &$pageInfo ) );
+ Hooks::run( 'InfoAction', array( $this->getContext(), &$pageInfo ) );
// Render page information
foreach ( $pageInfo as $header => $infoTable ) {
$response->header( 'HTTP/1.x 404 Not Found' );
}
- if ( !wfRunHooks( 'RawPageViewBeforeOutput', array( &$this, &$text ) ) ) {
+ if ( !Hooks::run( 'RawPageViewBeforeOutput', array( &$this, &$text ) ) ) {
wfDebug( __METHOD__ . ": RawPageViewBeforeOutput hook broke raw page output.\n" );
}
$page = WikiPage::factory( $title );
$status = Status::newFatal( 'hookaborted' );
- if ( wfRunHooks( 'WatchArticle', array( &$user, &$page, &$status ) ) ) {
+ if ( Hooks::run( 'WatchArticle', array( &$user, &$page, &$status ) ) ) {
$status = Status::newGood();
$user->addWatch( $title, $checkRights );
- wfRunHooks( 'WatchArticleComplete', array( &$user, &$page ) );
+ Hooks::run( 'WatchArticleComplete', array( &$user, &$page ) );
}
return $status;
$page = WikiPage::factory( $title );
$status = Status::newFatal( 'hookaborted' );
- if ( wfRunHooks( 'UnwatchArticle', array( &$user, &$page, &$status ) ) ) {
+ if ( Hooks::run( 'UnwatchArticle', array( &$user, &$page, &$status ) ) ) {
$status = Status::newGood();
$user->removeWatch( $title );
- wfRunHooks( 'UnwatchArticleComplete', array( &$user, &$page ) );
+ Hooks::run( 'UnwatchArticleComplete', array( &$user, &$page ) );
}
return $status;
*/
public function getFinalDescription() {
$desc = $this->getDescription();
- wfRunHooks( 'APIGetDescription', array( &$this, &$desc ) );
+ Hooks::run( 'APIGetDescription', array( &$this, &$desc ) );
$desc = self::escapeWikiText( $desc );
if ( is_array( $desc ) ) {
$desc = join( "\n", $desc );
}
$msgs = array( $msg );
- wfRunHooks( 'APIGetDescriptionMessages', array( $this, &$msgs ) );
+ Hooks::run( 'APIGetDescriptionMessages', array( $this, &$msgs ) );
return $msgs;
}
) + ( isset( $params['token'] ) ? $params['token'] : array() );
}
- wfRunHooks( 'APIGetAllowedParams', array( &$this, &$params, $flags ) );
+ Hooks::run( 'APIGetAllowedParams', array( &$this, &$params, $flags ) );
return $params;
}
*/
public function getFinalParamDescription() {
$desc = $this->getParamDescription();
- wfRunHooks( 'APIGetParamDescription', array( &$this, &$desc ) );
+ Hooks::run( 'APIGetParamDescription', array( &$this, &$desc ) );
if ( !$desc ) {
$desc = array();
}
}
- wfRunHooks( 'APIGetParamDescriptionMessages', array( $this, &$msgs ) );
+ Hooks::run( 'APIGetParamDescriptionMessages', array( $this, &$msgs ) );
return $msgs;
}
$loginForm = new LoginForm();
$loginForm->setContext( $context );
- wfRunHooks( 'AddNewAccountApiForm', array( $this, $loginForm ) );
+ Hooks::run( 'AddNewAccountApiForm', array( $this, $loginForm ) );
$loginForm->load();
$status = $loginForm->addNewaccountInternal();
// Save settings (including confirmation token)
$user->saveSettings();
- wfRunHooks( 'AddNewAccount', array( $user, $params['mailpassword'] ) );
+ Hooks::run( 'AddNewAccount', array( $user, $params['mailpassword'] ) );
if ( $params['mailpassword'] ) {
$logAction = 'byemail';
}
// Give extensions a chance to modify the API result data
- wfRunHooks( 'AddNewAccountApiResult', array( $this, $loginForm, &$result ) );
+ Hooks::run( 'AddNewAccountApiResult', array( $this, $loginForm, &$result ) );
$apiResult->addValue( null, 'createaccount', $result );
}
list( $params['undo'], $params['undoafter'] ) =
array( $params['undoafter'], $params['undo'] );
}
- $undoafterRev = Revision::newFromID( $params['undoafter'] );
+ $undoafterRev = Revision::newFromId( $params['undoafter'] );
}
- $undoRev = Revision::newFromID( $params['undo'] );
+ $undoRev = Revision::newFromId( $params['undo'] );
if ( is_null( $undoRev ) || $undoRev->isDeleted( Revision::DELETED_TEXT ) ) {
$this->dieUsageMsg( array( 'nosuchrevid', $params['undo'] ) );
}
'model' => $contentHandler->getModelID(),
'wpEditToken' => $params['token'],
'wpIgnoreBlankSummary' => '',
- 'wpIgnoreBlankArticle' => true
+ 'wpIgnoreBlankArticle' => true,
+ 'wpIgnoreSelfRedirect' => true,
);
if ( !is_null( $params['summary'] ) ) {
// Run hooks
// Handle APIEditBeforeSave parameters
$r = array();
- if ( !wfRunHooks( 'APIEditBeforeSave', array( $ep, $content, &$r ) ) ) {
+ if ( !Hooks::run( 'APIEditBeforeSave', array( $ep, $content, &$r ) ) ) {
if ( count( $r ) ) {
$r['result'] = 'Failure';
$apiResult->addValue( null, $this->getModuleName(), $r );
switch ( $status->value ) {
case EditPage::AS_HOOK_ERROR:
case EditPage::AS_HOOK_ERROR_EXPECTED:
- $this->dieUsageMsg( 'hookaborted' );
+ if ( isset( $status->apiHookResult ) ) {
+ $r = $status->apiHookResult;
+ $r['result'] = 'Failure';
+ $apiResult->addValue( null, $this->getModuleName(), $r );
+ return;
+ } else {
+ $this->dieUsageMsg( 'hookaborted' );
+ }
case EditPage::AS_PARSE_ERROR:
$this->dieUsage( $status->getMessage(), 'parseerror' );
)
);
- if ( wfRunHooks( 'ApiFormatHighlight', array( $context, $result, $mime, $format ) ) ) {
+ if ( Hooks::run( 'ApiFormatHighlight', array( $context, $result, $mime, $format ) ) ) {
$out->addHTML(
Html::element( 'pre', array( 'class' => 'api-pretty-content' ), $result )
);
$module->modifyHelp( $help, $options );
- wfRunHooks( 'APIHelpModifyOutput', array( $module, &$help, $options ) );
+ Hooks::run( 'APIHelpModifyOutput', array( $module, &$help, $options ) );
$out .= join( "\n", $help );
}
// @todo FIXME: Split back and frontend from this hook.
// @todo FIXME: This hook should be placed in the backend
$injected_html = '';
- wfRunHooks( 'UserLoginComplete', array( &$user, &$injected_html ) );
+ Hooks::run( 'UserLoginComplete', array( &$user, &$injected_html ) );
$result['result'] = 'Success';
$result['lguserid'] = intval( $user->getId() );
// Give extensions to do something after user logout
$injected_html = '';
- wfRunHooks( 'UserLogoutComplete', array( &$user, &$injected_html, $oldName ) );
+ Hooks::run( 'UserLogoutComplete', array( &$user, &$injected_html, $oldName ) );
}
public function isReadMode() {
if ( $uselang === 'user' ) {
$uselang = $this->getUser()->getOption( 'language' );
$uselang = RequestContext::sanitizeLangCode( $uselang );
- wfRunHooks( 'UserGetLanguageObject', array( $this->getUser(), &$uselang, $this ) );
+ Hooks::run( 'UserGetLanguageObject', array( $this->getUser(), &$uselang, $this ) );
} elseif ( $uselang === 'content' ) {
global $wgContLang;
$uselang = $wgContLang->getCode();
}
// Allow extra cleanup and logging
- wfRunHooks( 'ApiMain::onException', array( $this, $e ) );
+ Hooks::run( 'ApiMain::onException', array( $this, $e ) );
// Log it
if ( !( $e instanceof UsageException ) ) {
// Allow extensions to stop execution for arbitrary reasons.
$message = false;
- if ( !wfRunHooks( 'ApiCheckCanExecute', array( $module, $user, &$message ) ) ) {
+ if ( !Hooks::run( 'ApiCheckCanExecute', array( $module, $user, &$message ) ) ) {
$this->dieUsageMsg( $message );
}
}
// Execute
$module->profileIn();
$module->execute();
- wfRunHooks( 'APIAfterExecute', array( &$module ) );
+ Hooks::run( 'APIAfterExecute', array( &$module ) );
$module->profileOut();
$this->reportUnusedParams();
$this->search( $search, $limit, $namespaces, $resolveRedir, $results );
// Allow hooks to populate extracts and images
- wfRunHooks( 'ApiOpenSearchSuggest', array( &$results ) );
+ Hooks::run( 'ApiOpenSearchSuggest', array( &$results ) );
// Trim extracts, if necessary
$length = $this->getConfig()->get( 'OpenSearchDescriptionLength' );
// Find matching titles as Title objects
$searcher = new TitlePrefixSearch;
$titles = $searcher->searchWithVariants( $search, $limit, $namespaces );
+ if ( !$titles ) {
+ return;
+ }
if ( $resolveRedir ) {
// Query for redirects
if ( !$isDryRun ) {
$generator->executeGenerator( $this );
- wfRunHooks( 'APIQueryGeneratorAfterExecute', array( &$generator, &$this ) );
+ Hooks::run( 'APIQueryGeneratorAfterExecute', array( &$generator, &$this ) );
} else {
// Prevent warnings from being reported on these parameters
$main = $this->getMain();
*
* @param ApiResult|array &$result
* @param array $path
- * @return boolean Whether the data fit
+ * @return bool Whether the data fit
*/
public function populateGeneratorData( &$result, array $path = array() ) {
if ( $result instanceof ApiResult ) {
if ( !is_null( $oldid ) || !is_null( $pageid ) || !is_null( $page ) ) {
if ( !is_null( $oldid ) ) {
// Don't use the parser cache
- $rev = Revision::newFromID( $oldid );
+ $rev = Revision::newFromId( $oldid );
if ( !$rev ) {
$this->dieUsage( "There is no revision ID $oldid", 'missingrev' );
}
// Link flags are ignored for now, but may in the future be
// included in the result.
$linkFlags = array();
- wfRunHooks( 'LanguageLinks', array( $titleObj, &$langlinks, &$linkFlags ) );
+ Hooks::run( 'LanguageLinks', array( $titleObj, &$langlinks, &$linkFlags ) );
}
} else {
$langlinks = false;
$this->requireOnlyOneParameter( $params, 'rcid', 'revid' );
if ( isset( $params['rcid'] ) ) {
- $rc = RecentChange::newFromID( $params['rcid'] );
+ $rc = RecentChange::newFromId( $params['rcid'] );
if ( !$rc ) {
$this->dieUsageMsg( array( 'nosuchrcid', $params['rcid'] ) );
}
$cacheMode, $module->getCacheMode( $params ) );
$module->profileIn();
$module->execute();
- wfRunHooks( 'APIQueryAfterExecute', array( &$module ) );
+ Hooks::run( 'APIQueryAfterExecute', array( &$module ) );
$module->profileOut();
}
'import' => array( 'ApiQueryInfo', 'getImportToken' ),
'watch' => array( 'ApiQueryInfo', 'getWatchToken' ),
);
- wfRunHooks( 'APIQueryInfoTokens', array( &$this->tokenFunctions ) );
+ Hooks::run( 'APIQueryInfoTokens', array( &$this->tokenFunctions ) );
return $this->tokenFunctions;
}
$pageInfo['preload'] = '';
} else {
$text = null;
- wfRunHooks( 'EditFormPreloadText', array( &$text, &$title ) );
+ Hooks::run( 'EditFormPreloadText', array( &$text, &$title ) );
$pageInfo['preload'] = $text;
}
$this->tokenFunctions = array(
'patrol' => array( 'ApiQueryRecentChanges', 'getPatrolToken' )
);
- wfRunHooks( 'APIQueryRecentChangesTokens', array( &$this->tokenFunctions ) );
+ Hooks::run( 'APIQueryRecentChangesTokens', array( &$this->tokenFunctions ) );
return $this->tokenFunctions;
}
$this->tokenFunctions = array(
'rollback' => array( 'ApiQueryRevisions', 'getRollbackToken' )
);
- wfRunHooks( 'APIQueryRevisionsTokens', array( &$this->tokenFunctions ) );
+ Hooks::run( 'APIQueryRevisionsTokens', array( &$this->tokenFunctions ) );
return $this->tokenFunctions;
}
// DifferenceEngine returns a rather ambiguous empty
// string if that's not the case
if ( $params['diffto'] != 0 ) {
- $difftoRev = Revision::newFromID( $params['diffto'] );
+ $difftoRev = Revision::newFromId( $params['diffto'] );
if ( !$difftoRev ) {
$this->dieUsageMsg( array( 'nosuchrevid', $params['diffto'] ) );
}
$data['favicon'] = wfExpandUrl( $favicon, PROTO_RELATIVE );
}
- wfRunHooks( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
+ Hooks::run( 'APIQuerySiteInfoGeneralInfo', array( $this, &$data ) );
return $this->getResult()->addValue( 'query', $property, $data );
}
$data['admins'] = intval( SiteStats::numberingroup( 'sysop' ) );
$data['jobs'] = intval( SiteStats::jobs() );
- wfRunHooks( 'APIQuerySiteInfoStatisticsInfo', array( &$data ) );
+ Hooks::run( 'APIQuerySiteInfoStatisticsInfo', array( &$data ) );
return $this->getResult()->addValue( 'query', $property, $data );
}
'rollback' => 'rollback',
'userrights' => 'userrights',
);
- wfRunHooks( 'ApiQueryTokensRegisterTypes', array( &$salts ) );
+ Hooks::run( 'ApiQueryTokensRegisterTypes', array( &$salts ) );
ksort( $salts );
wfProfileOut( __METHOD__ );
}
$this->tokenFunctions = array(
'userrights' => array( 'ApiQueryUsers', 'getUserrightsToken' ),
);
- wfRunHooks( 'APIQueryUsersTokens', array( &$this->tokenFunctions ) );
+ Hooks::run( 'APIQueryUsersTokens', array( &$this->tokenFunctions ) );
return $this->tokenFunctions;
}
)
),
);
- wfRunHooks( 'ApiRsdServiceApis', array( &$apis ) );
+ Hooks::run( 'ApiRsdServiceApis', array( &$apis ) );
return $apis;
}
$this->dieUsage( "Unsupported content model/format", 'badmodelformat' );
}
- $text = trim( $params['text'] ); // needed so the key SHA1's match
+ // Trim and fix newlines so the key SHA1's match (see RequestContext::getText())
+ $text = rtrim( str_replace( "\r\n", "\n", $params['text'] ) );
$textContent = ContentHandler::makeContent(
$text, $title, $params['contentmodel'], $params['contentformat'] );
$editInfo = false;
$status = 'ratelimited';
} elseif ( $wgMemc->lock( $key, 0, 30 ) ) {
- $contentFormat = $content->getDefaultFormat();
- $editInfo = $page->prepareContentForEdit( $content, null, $user, $contentFormat );
- $wgMemc->unlock( $key );
+ $format = $content->getDefaultFormat();
+ $editInfo = $page->prepareContentForEdit( $content, null, $user, $format, false );
$status = 'error'; // default
+ $unlocker = new ScopedCallback( function() use ( $key ) {
+ global $wgMemc;
+ $wgMemc->unlock( $key );
+ } );
} else {
$editInfo = false;
$status = 'busy';
}
if ( $editInfo && $editInfo->output ) {
- $parserOutput = $editInfo->output;
- // If an item is renewed, mind the cache TTL determined by config and parser functions
- $since = time() - wfTimestamp( TS_UNIX, $parserOutput->getTimestamp() );
- $ttl = min( $parserOutput->getCacheExpiry() - $since, 5 * 60 );
- if ( $ttl > 0 && !$parserOutput->getFlag( 'vary-revision' ) ) {
- // Only store what is actually needed
- $stashInfo = (object)array(
- 'pstContent' => $editInfo->pstContent,
- 'output' => $editInfo->output,
- 'timestamp' => $editInfo->timestamp
- );
+ list( $stashInfo, $ttl ) = self::buildStashValue(
+ $editInfo->pstContent, $editInfo->output, $editInfo->timestamp
+ );
+ if ( $stashInfo ) {
$ok = $wgMemc->set( $key, $stashInfo, $ttl );
if ( $ok ) {
$status = 'stashed';
}
/**
- * Get the temporary prepared edit stash key for a user
+ * Attempt to cache PST content and corresponding parser output in passing
*
- * @param Title $title
- * @param Content $content
- * @param User $user User to get parser options from
- * @return string
+ * This method can be called when the output was already generated for other
+ * reasons. Parsing should not be done just to call this method, however.
+ * $pstOpts must be that of the user doing the edit preview. If $pOpts does
+ * not match the options of WikiPage::makeParserOptions( 'canonical' ), this
+ * will do nothing. Provided the values are cacheable, they will be stored
+ * in memcached so that final edit submission might make use of them.
+ *
+ * @param Article|WikiPage $page Page title
+ * @param Content $content Proposed page content
+ * @param Content $pstContent The result of preSaveTransform() on $content
+ * @param ParserOutput $pOut The result of getParserOutput() on $pstContent
+ * @param ParserOptions $pstOpts Options for $pstContent (MUST be for prospective author)
+ * @param ParserOptions $pOpts Options for $pOut
+ * @param string $timestamp TS_MW timestamp of parser output generation
+ * @return bool Success
*/
- protected static function getStashKey(
- Title $title, Content $content, User $user
+ public static function stashEditFromPreview(
+ Page $page, Content $content, Content $pstContent, ParserOutput $pOut,
+ ParserOptions $pstOpts, ParserOptions $pOpts, $timestamp
) {
- return wfMemcKey( 'prepared-edit',
- md5( $title->getPrefixedDBkey() ), // handle rename races
- $content->getModel(),
- $content->getDefaultFormat(),
- sha1( $content->serialize( $content->getDefaultFormat() ) ),
- $user->getId() ?: md5( $user->getName() ), // account for user parser options
- $user->getId() ? $user->getTouched() : '-' // handle preference change races
- );
+ global $wgMemc;
+
+ // getIsPreview() controls parser function behavior that references things
+ // like user/revision that don't exists yet. The user/text should already
+ // be set correctly by callers, just double check the preview flag.
+ if ( !$pOpts->getIsPreview() ) {
+ return false; // sanity
+ } elseif ( $pOpts->getIsSectionPreview() ) {
+ return false; // short-circuit (need the full content)
+ }
+
+ // PST parser options are for the user (handles signatures, etc...)
+ $user = $pstOpts->getUser();
+ // Get a key based on the source text, format, and user preferences
+ $key = self::getStashKey( $page->getTitle(), $content, $user );
+
+ // Parser output options must match cannonical options.
+ // Treat some options as matching that are different but don't matter.
+ $canonicalPOpts = $page->makeParserOptions( 'canonical' );
+ $canonicalPOpts->setIsPreview( true ); // force match
+ $canonicalPOpts->setTimestamp( $pOpts->getTimestamp() ); // force match
+ if ( !$pOpts->matches( $canonicalPOpts ) ) {
+ wfDebugLog( 'StashEdit', "Uncacheable preview output for key '$key' (options)." );
+ return false;
+ }
+
+ // Build a value to cache with a proper TTL
+ list( $stashInfo, $ttl ) = self::buildStashValue( $pstContent, $pOut, $timestamp );
+ if ( !$stashInfo ) {
+ wfDebugLog( 'StashEdit', "Uncacheable parser output for key '$key' (rev/TTL)." );
+ return false;
+ }
+
+ $ok = $wgMemc->set( $key, $stashInfo, $ttl );
+ if ( !$ok ) {
+ wfDebugLog( 'StashEdit', "Failed to cache preview parser output for key '$key'." );
+ } else {
+ wfDebugLog( 'StashEdit', "Cached preview output for key '$key'." );
+ }
+
+ return $ok;
}
/**
if ( $wgMemc->lock( $key, 30, 30 ) ) {
$editInfo = $wgMemc->get( $key );
$wgMemc->unlock( $key );
- $sec = microtime( true ) - $start;
- wfDebugLog( 'StashEdit', "Waited $sec seconds on '$key'." );
}
+ $sec = microtime( true ) - $start;
+ wfDebugLog( 'StashEdit', "Waited $sec seconds on '$key'." );
}
if ( !is_object( $editInfo ) || !$editInfo->output ) {
+ wfDebugLog( 'StashEdit', "No cache value for key '$key'." );
return false;
}
return $editInfo;
}
+ /**
+ * Get the temporary prepared edit stash key for a user
+ *
+ * This key can be used for caching prepared edits provided:
+ * - a) The $user was used for PST options
+ * - b) The parser output was made from the PST using cannonical matching options
+ *
+ * @param Title $title
+ * @param Content $content
+ * @param User $user User to get parser options from
+ * @return string
+ */
+ protected static function getStashKey( Title $title, Content $content, User $user ) {
+ $hash = sha1( implode( ':', array(
+ $content->getModel(),
+ $content->getDefaultFormat(),
+ sha1( $content->serialize( $content->getDefaultFormat() ) ),
+ $user->getId() ?: md5( $user->getName() ), // account for user parser options
+ $user->getId() ? $user->getTouched() : '-' // handle preference change races
+ ) ) );
+
+ return wfMemcKey( 'prepared-edit', md5( $title->getPrefixedDBkey() ), $hash );
+ }
+
+ /**
+ * Build a value to store in memcached based on the PST content and parser output
+ *
+ * This makes a simple version of WikiPage::prepareContentForEdit() as stash info
+ *
+ * @param Content $pstContent
+ * @param ParserOutput $parserOutput
+ * @param string $timestamp TS_MW
+ * @return array (stash info array, TTL in seconds) or (null, 0)
+ */
+ protected static function buildStashValue(
+ Content $pstContent, ParserOutput $parserOutput, $timestamp
+ ) {
+ // If an item is renewed, mind the cache TTL determined by config and parser functions
+ $since = time() - wfTimestamp( TS_UNIX, $parserOutput->getTimestamp() );
+ $ttl = min( $parserOutput->getCacheExpiry() - $since, 5 * 60 );
+ if ( $ttl > 0 && !$parserOutput->getFlag( 'vary-revision' ) ) {
+ // Only store what is actually needed
+ $stashInfo = (object)array(
+ 'pstContent' => $pstContent,
+ 'output' => $parserOutput,
+ 'timestamp' => $timestamp
+ );
+ return array( $stashInfo, $ttl );
+ }
+
+ return array( null, 0 );
+ }
+
public function getAllowedParams() {
return array(
'title' => array(
foreach ( $names as $name ) {
$types[$name] = array( 'ApiQueryInfo', 'get' . ucfirst( $name ) . 'Token' );
}
- wfRunHooks( 'ApiTokensGetTokenTypes', array( &$types ) );
+ Hooks::run( 'ApiTokensGetTokenTypes', array( &$types ) );
ksort( $types );
wfProfileOut( __METHOD__ );
}
if ( $retval[1] ) {
- wfRunHooks( 'FileUndeleteComplete',
+ Hooks::run( 'FileUndeleteComplete',
array( $titleObj, $params['fileids'], $this->getUser(), $params['reason'] ) );
}
"apihelp-block-param-anononly": "Заблякаваць толькі ананімных удзельнікаў (напрыклад, забараніць ананімныя праўкі з гэтага IP-адрасу).",
"apihelp-block-param-nocreate": "Забарона стварэньня рахункаў.",
"apihelp-block-param-autoblock": "Аўтаматычна блякаваць апошні ўжыты IP-адрас, а таксама ўсе наступныя IP-адрасы, зь якіх будуць спробы ўваходу.",
- "apihelp-block-param-noemail": "Забараняе ўдзельніку дасылаць лісты электроннай пошты празь вікі (трэба мець права «blockemail»)."
+ "apihelp-block-param-noemail": "Забараняе ўдзельніку дасылаць лісты электроннай пошты празь вікі (трэба мець права «blockemail»).",
+ "apihelp-block-param-hidename": "Схаваць імя ўдзельніка з журналу блякаваньняў (патрабуе права «hideuser»).",
+ "apihelp-block-param-allowusertalk": "Дазволіць удзельніку рэдагаваць уласную старонку гутарак (залежыць ад $wgBlockAllowsUTEdit)."
}
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "Palapa"
+ ]
+ },
+ "apihelp-block-description": "Blokiraj korisnika",
+ "apihelp-block-param-reason": "Razlog za blokadu",
+ "apihelp-delete-description": "Obriši stranicu.",
+ "apihelp-edit-param-minor": "Mala izmjena."
+}
"apihelp-block-param-nocreate": "Et Neu-Aanmelde verbeede",
"apihelp-block-param-autoblock": "Dun automattesch de läzde <i lang=\"en\" xml:lang=\"en\">IP</i>-Adräß schpärre, di dä Metmaacher jehatt hät, un och all di <i lang=\"en\" xml:lang=\"en\">IP</i>-Adräße, vun wo dä versöhk, jet ze ändere.",
"apihelp-block-param-watchuser": "Donn de Metmaachersigg un de Klaafsigg dohzoh op mig Oppaßleß säze.",
+ "apihelp-compare-description": "Donn de Ongerscheide zwesche zwai Sigge beschtemme.\n\nDo moß derför jeweils en Väsjohn, ene Tettel, odder ener Sigg iehr Kännong aanjävve, för de beide Sigge.",
+ "apihelp-compare-param-fromtitle": "Der Tettel vun dä eezte Sigg zom verjlihsche.",
+ "apihelp-compare-param-fromid": "De Kännong vun dä eezte Sigg zom verjlihsche.",
+ "apihelp-compare-param-fromrev": "De Väsjohn vun dä zwaite Sigg zom verjlihsche.",
+ "apihelp-compare-param-totitle": "Der Tettel vun dä zwaite Sigg zom verjlihsche.",
+ "apihelp-compare-param-toid": "De Kännong vun dä zwaite Sigg zom verjlihsche.",
+ "apihelp-compare-param-torev": "De Väsjohn vun dä zwaite Sigg zom verjlihsche.",
+ "apihelp-compare-example-1": "Fengk de Ongerscheide zwesche dä Väsjohne 1 un 2",
"apihelp-createaccount-description": "Ene neue Zohjang för ene Metmaacher aanlähje.",
"apihelp-createaccount-param-name": "Der Nahme för dä Metmaacher.",
"apihelp-createaccount-param-password": "Et Paßwoot (Weed ävver it jebruc un övverjange, wann <code lang=\"en\" xml:lang=\"en\">$1mailpassword</code> jesaz es)",
+ "apihelp-createaccount-param-realname": "Dämm Medmaacher singe reschtejje Nahme - kann fott blihve.",
"apihelp-delete-description": "Schmieß en Sigg fott.",
"apihelp-delete-param-watch": "Donn die Sigg en Ding Oppassliss opnemme.",
"apihelp-delete-param-unwatch": "Schmiiß di Sigg us Dinge Oppassless erus.",
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "Jagwar"
+ ]
+ },
+ "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page Torohevitra be kokoa]\n* [https://www.mediawiki.org/wiki/API:FAQ Fanontaniana miverina matetika]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Lisitry ny mailaka manaraka]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Filazana API]\n* [https://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts Baogy & hataka]\n</div>\n<strong>Status:</strong> \nTokony mandeha avokoa ny fitaovana aseho eto amin'ity pehy ity, na dia izany aza mbola am-panamboarana ny API ary mety hiova na oviana na oviana. Araho amin'ny alalan'ny fisoratana ny mailakao ao amin'ny [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce lisitra fampielezana] ny fiovana.\n\n<strong>Hataka diso:</strong> \nRehefa alefa ao amin'i API ny hata, ho alefa miaraka amin'ny lakile \"MediaWiki-API-Error\" ny header HTTP ary samy homen-tsanda mitovy ny header ary ny kaodin-kadisoana. Ho an'ny torohay fanampiny dia jereo https://www.mediawiki.org/wiki/API:Errors_and_warnings.",
+ "apihelp-main-param-action": "Inona ny zavatra ho atao.",
+ "apihelp-main-param-format": "Format mivoaka",
+ "apihelp-createaccount-param-name": "Anaram-pikambana."
+}
"Bjankuloski06"
]
},
- "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page Ð\94окÑ\83менÑ\82аÑ\86иÑ\98а]\n* [https://www.mediawiki.org/wiki/API:FAQ ЧÐ\9fÐ\9f]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Ð\9fоÑ\88Ñ\82енÑ\81ки Ñ\81пиÑ\81ок]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce СоопÑ\88Ñ\82ениÑ\98а за Ð\9fÑ\80илогоÑ\82]\n* [https://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts Ð\93Ñ\80еÑ\88ки и баÑ\80аÑ\9aа]\n</div>\n<strong>СÑ\82аÑ\82Ñ\83Ñ\81:</strong> СиÑ\82е Ñ\81Ñ\82авки на Ñ\81Ñ\82Ñ\80аниÑ\86ава би Ñ\82Ñ\80ебало да Ñ\80абоÑ\82аÑ\82, но Ð\9fÑ\80илогоÑ\82 Ñ\81епак е во акÑ\82ивна Ñ\80азÑ\80абоÑ\82ка, Ñ\88Ñ\82о знаÑ\87и дека може да Ñ\81е Ñ\81мени во Ñ\81екое вÑ\80еме. Ð\9eбÑ\98авиÑ\82е за измени можеÑ\82е да ги дознаваÑ\82е ако Ñ\81е пÑ\80иÑ\98авиÑ\82е на [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ поÑ\88Ñ\82енÑ\81киоÑ\82 Ñ\81пиÑ\81ок â\80\9ethe mediawiki-api-announceâ\80\9c].\n\n<strong>Ð\9fогÑ\80еÑ\88ни баÑ\80аÑ\9aа:</strong> Ð\9aога Ð\9fÑ\80илогот ќе добие погрешни барања, ќе се испрати HTTP-заглавие со клучот „MediaWiki-API-Error“ и потоа на вредностите на заглавието и шифрата на грешката што ќе се појават ќе им биде зададена истата вредност. ПОвеќе информации ќе најдете на https://www.mediawiki.org/wiki/API:Errors_and_warnings.",
+ "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page Ð\94окÑ\83менÑ\82аÑ\86иÑ\98а]\n* [https://www.mediawiki.org/wiki/API:FAQ ЧÐ\9fÐ\9f]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Ð\9fоÑ\88Ñ\82енÑ\81ки Ñ\81пиÑ\81ок]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce СоопÑ\88Ñ\82ениÑ\98а за Ð\98звÑ\80Ñ\88никоÑ\82]\n* [https://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts Ð\93Ñ\80еÑ\88ки и баÑ\80аÑ\9aа]\n</div>\n<strong>СÑ\82аÑ\82Ñ\83Ñ\81:</strong> СиÑ\82е Ñ\81Ñ\82авки на Ñ\81Ñ\82Ñ\80аниÑ\86ава би Ñ\82Ñ\80ебало да Ñ\80абоÑ\82аÑ\82, но Ð\98звÑ\80Ñ\88никоÑ\82 Ñ\81епак е во акÑ\82ивна Ñ\80азÑ\80абоÑ\82ка, Ñ\88Ñ\82о знаÑ\87и дека може да Ñ\81е Ñ\81мени во Ñ\81екое вÑ\80еме. Ð\9eбÑ\98авиÑ\82е за измени можеÑ\82е да ги дознаваÑ\82е ако Ñ\81е пÑ\80иÑ\98авиÑ\82е на [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ поÑ\88Ñ\82енÑ\81киоÑ\82 Ñ\81пиÑ\81ок â\80\9ethe mediawiki-api-announceâ\80\9c].\n\n<strong>Ð\9fогÑ\80еÑ\88ни баÑ\80аÑ\9aа:</strong> Ð\9aога Ð\98звÑ\80Ñ\88никот ќе добие погрешни барања, ќе се испрати HTTP-заглавие со клучот „MediaWiki-API-Error“ и потоа на вредностите на заглавието и шифрата на грешката што ќе се појават ќе им биде зададена истата вредност. ПОвеќе информации ќе најдете на https://www.mediawiki.org/wiki/API:Errors_and_warnings.",
"apihelp-main-param-action": "Кое дејство да се изврши.",
"apihelp-main-param-format": "Формат на изводот.",
"apihelp-main-param-maxlag": "Максималниот заостаток може да се користи кога МедијаВики е воспоставен на грозд умножен од базата. За да спречите дополнителни заостатоци од дејства, овој параметар му наложува на клиентот да почека додека заостатокот не се намали под укажаната вредност. Во случај на преголем заостаток, системт ја дава грешката со код „maxlag“ со порака од обликот „Го чекам $host: има заостаток од $lag секунди“.<br />Погл. https://www.mediawiki.org/wiki/Manual:Maxlag_parameter за повеќе информации.",
"apihelp-options-example-reset": "Врати ги сите поставки по основно",
"apihelp-options-example-change": "Смени ги поставките „skinЗ“ и „hideminor“",
"apihelp-options-example-complex": "Врати ги сите нагодувања по основно, а потоа задај ги „skin“ и „nickname“",
- "apihelp-paraminfo-description": "Ð\9dабави инÑ\84оÑ\80маÑ\86ии за пÑ\80илоÑ\88ки (API) модули.",
+ "apihelp-paraminfo-description": "Ð\9dабави инÑ\84оÑ\80маÑ\86ии за извÑ\80Ñ\88ниÑ\87ки (API) модули.",
"apihelp-paraminfo-param-modules": "Список на називи на модули (вредности на параметрите action= и format=, или пак „main“). Може да се укажат подмодули со „+“.",
"apihelp-paraminfo-param-helpformat": "Формат на помошните низи.",
"apihelp-paraminfo-param-querymodules": "Список на називи на модули за барања (вредност на параметарот prop=, meta= или list=). Користете го „$1modules=query+foo“ наместо „$1querymodules=foo“.",
"apihelp-protect-param-reason": "Причиина за (од)заштитување",
"apihelp-protect-example-protect": "Заштити страница",
"apihelp-purge-param-forcelinkupdate": "Поднови ги табелите со врски.",
- "apihelp-purge-example-simple": "Ð\9fÑ\80евÑ\87иÑ\82аÑ\98 ги â\80\9eÐ\93лавна Ñ\81Ñ\82Ñ\80аниÑ\86аâ\80\9c и â\80\9eÐ\9fÑ\80илог“",
+ "apihelp-purge-example-simple": "Ð\9fÑ\80евÑ\87иÑ\82аÑ\98 ги â\80\9eÐ\93лавна Ñ\81Ñ\82Ñ\80аниÑ\86аâ\80\9c и â\80\9eÐ\98звÑ\80Ñ\88ник“",
"apihelp-query-param-list": "Кои списоци да се набават.",
"apihelp-query-param-meta": "Кои метаподатоци да се набават.",
"apihelp-query+allcategories-description": "Наброј ги сите категории.",
"apihelp-xmlfm-description": "Давај го изводот во XML-формат (подобрен испис во HTML).",
"apihelp-yaml-description": "Давај го изводот во YAML-формат.",
"apihelp-yamlfm-description": "Давај го изводот во YAML-формат (подобрен испис во HTML).",
- "api-format-title": "РезÑ\83лÑ\82аÑ\82 од Ð\9fÑ\80илогот на МедијаВики",
- "api-format-prettyprint-header": "Ја гледате HTML-претставата на форматот $1. HTML е добар за отстранување на грешки, но не е погоден за употреб во прилог.\n\nУкажете го параметарот за формат за да го смените изводниот формат. За да ги видите претставите на форматот $1 вон HTML, задајте format=$2.\n\nПовеќе информации ќе најдете на [https://www.mediawiki.org/wiki/API целосната документација], или пак [[Special:ApiHelp/main|помош со прилогот]].",
+ "api-format-title": "РезÑ\83лÑ\82аÑ\82 од Ð\98звÑ\80Ñ\88никот на МедијаВики",
+ "api-format-prettyprint-header": "Ја гледате HTML-претставата на форматот $1. HTML е добар за отстранување на грешки, но не е погоден за употреба во извршник.\n\nУкажете го параметарот за формат за да го смените изводниот формат. За да ги видите претставите на форматот $1 вон HTML, задајте format=$2.\n\nПовеќе информации ќе најдете на [https://www.mediawiki.org/wiki/API целосната документација], или пак [[Special:ApiHelp/main|помош со извршникот]].",
"api-orm-param-props": "Полиња за пребарување.",
"api-orm-param-limit": "Макс. број на редови во изводот.",
"api-pageset-param-titles": "Список на наслови на кои ќе се работи",
"api-pageset-param-pageids": "Список на назнаки за страници на кои ќе се работи",
"api-pageset-param-revids": "Список на назнаки на преработки на кои ќе се работи",
"api-pageset-param-generator": "Дај го списокот на страници на кои ќе се работи исполнувајќи го укажаниот модул за барање.\n\n'''НАПОМЕНА:''' називите на создавачките параметри мора да ја имаат претставката „g“. Погледајте ги примерите.",
- "api-help-title": "Ð\9fомоÑ\88 Ñ\81о Ð\9fÑ\80илогот на МедијаВики",
- "api-help-lead": "Ð\9eва е Ñ\81амоÑ\81оздадена докÑ\83менÑ\82аÑ\86иÑ\81ка Ñ\81Ñ\82Ñ\80аниÑ\86а за Ð\9fÑ\80илогоÑ\82 на Ð\9cедиÑ\98аÐ\92ики.\n\nDocumentation and examples: https://www.mediawiki.org/wiki/API",
+ "api-help-title": "Ð\9fомоÑ\88 Ñ\81о Ð\98звÑ\80Ñ\88никот на МедијаВики",
+ "api-help-lead": "Ð\9eва е Ñ\81амоÑ\81оздадена докÑ\83менÑ\82аÑ\86иÑ\81ка Ñ\81Ñ\82Ñ\80аниÑ\86а за извÑ\80Ñ\88никоÑ\82 на Ð\9cедиÑ\98аÐ\92ики.\n\nÐ\94окÑ\83менÑ\82аÑ\86иÑ\98а и пÑ\80имеÑ\80и: https://www.mediawiki.org/wiki/API",
"api-help-main-header": "Главен модул",
"api-help-flag-deprecated": "Овој модул е застарен.",
"api-help-flag-internal": "<strong>Овој модул е внатрешен или нестабилен.</strong> Работењето може да му се промени без предупредување.",
"api-help-permissions-granted-to": "{{PLURAL:$1|Доделена на}: $2",
"api-help-right-apihighlimits": "Уоптреба на повисоки ограничувања за приложни барања (бавни барања: $1; брзи барања: $2). Ограничувањата за бавни барања важат и за повеќевредносни параметри.",
"api-credits-header": "Признанија",
- "api-credits": "РазÑ\80абоÑ\82Ñ\83ваÑ\87и на Ð\9fÑ\80илогот:\n* Роан Катау (главен резработувач од септември 2007 до 2009 г.)\n* Виктор Василев\n* Брајан Тонг Мињ\n* Сем Рид\n* Јуриј Астрахан (создавач, главен разработувач од септември 2006 до септември 2007 г.)\n* Brad Jorsch (главен разработувач од 2013 г. до денес)\n\nВашите коментари, предлози и прашања испраќајте ги на mediawiki-api@lists.wikimedia.org\nа грешките пријавувајте ги на https://bugzilla.wikimedia.org/."
+ "api-credits": "РазÑ\80абоÑ\82Ñ\83ваÑ\87и на Ð\98звÑ\80Ñ\88никот:\n* Роан Катау (главен резработувач од септември 2007 до 2009 г.)\n* Виктор Василев\n* Брајан Тонг Мињ\n* Сем Рид\n* Јуриј Астрахан (создавач, главен разработувач од септември 2006 до септември 2007 г.)\n* Brad Jorsch (главен разработувач од 2013 г. до денес)\n\nВашите коментари, предлози и прашања испраќајте ги на mediawiki-api@lists.wikimedia.org\nа грешките пријавувајте ги на https://bugzilla.wikimedia.org/."
}
"Siebrand",
"Sjoerddebruin",
"Robin0van0der0vliet",
- "Mar(c)"
+ "Mar(c)",
+ "Valhallasw"
]
},
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page Documentatie]\n* [https://www.mediawiki.org/wiki/API:FAQ FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api E-maillijst]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API-aankondigingen]\n* [https://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts Bugs & verzoeken]\n</div>\n<strong>Status:</strong> Alle functies die op deze pagina worden weergegeven horen te werken. Aan de API wordt actief gewerkt, en deze kan gewijzigd worden. Abonneer u op de [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ e-maillijst mediawiki-api-announce] voor meldingen over aanpassingen.\n\n<strong>Foutieve verzoeken:</strong> als de API foutieve verzoeken ontvangt, wordt er geantwoord met een HTTP-header met de sleutel \"MediaWiki-API-Error\" en daarna worden de waarde van de header en de foutcode op dezelfde waarde ingesteld. Zie https://www.mediawiki.org/wiki/API:Errors_and_warnings voor meer informatie.",
"apihelp-main-param-maxlag": "De maximale vertraging kan gebruikt worden als MediaWiki is geïnstalleerd op een databasecluster die gebruik maakt van replicatie. Om te voorkomen dat handelingen nog meer databasereplicatievertraging veroorzaken, kan deze parameter er voor zorgen dat de client wacht totdat de replicatievertraging lager is dan de aangegeven waarde. In het geval van buitensporige vertraging, wordt de foutcode \"maxlag\" teruggegeven met een bericht als \"Waiting for $host: $lag seconds lagged\".<br />Zie https://www.mediawiki.org/wiki/Manual:Maxlag_parameter voor mee informatie.",
"apihelp-main-param-smaxage": "Stelt de header \"s-maxage\" in op het aangegeven aantal seconden. Foutmeldingen komen nooit in de cache.",
"apihelp-main-param-maxage": "Stelt de header \"max-age\" in op het aangegeven aantal seconden. Foutmeldingen komen nooit in de cache.",
+ "apihelp-main-param-assert": "Controleer of de gebruiker ingelogd is als \"user\" is meegegeven, en of de gebruiker het bot-gebruikersrecht heeft als \"bot\" is meegegeven.",
+ "apihelp-main-param-requestid": "Elke waarde die hier gegeven wordt wordt aan het antwoord toegevoegd. Dit kan gebruikt worden om verzoeken te onderscheiden.",
+ "apihelp-main-param-servedby": "Voeg de hostnaam van de server die de aanvraag heeft afgehandeld toe aan het antwoord.",
+ "apihelp-main-param-curtimestamp": "Voeg de huidige tijd toe aan het antwoord.",
"apihelp-block-description": "Gebruiker blokkeren.",
"apihelp-block-param-reason": "Reden voor blokkade.",
"apihelp-edit-example-edit": "Pagina bewerken",
--- /dev/null
+{
+ "@metadata": {
+ "authors": [
+ "Veeven"
+ ]
+ },
+ "apihelp-feedrecentchanges-example-simple": "ఇటీవలి మార్పులను చూడండి"
+}
"apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page/zh 文档]\n* [https://www.mediawiki.org/wiki/API:FAQ/zh 常见问题]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api 邮件列表]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API公告]\n* [https://bugzilla.wikimedia.org/buglist.cgi?component=API&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=bugs.delta_ts 程序错误与功能请求]\n</div>\n<strong>状态信息:</strong> 本页所展示的所有特性都应正常工作,但是API仍在开发当中,将会随时变化。请订阅[https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ mediawiki-api-announce 邮件列表]以便获得更新通知。\n\n<strong>错误请求:</strong> 当API收到错误请求时,HTTP header将会返回一个包含\"MediaWiki-API-Error\"的值,随后header的值与error code将会送回并设置为相同的值。详细信息请参阅 https://www.mediawiki.org/wiki/API:Errors_and_warnings 。",
"apihelp-main-param-action": "要执行的操作。",
"apihelp-main-param-format": "输出的格式。",
+ "apihelp-main-param-assert": "如果设置为“user”就验证用户是否登录,或如果设置为“bot”就验证是否有机器人用户权限。",
"apihelp-main-param-servedby": "包含保存结果请求的主机名。",
"apihelp-main-param-curtimestamp": "在结果中包括当前时间戳。",
"apihelp-main-param-origin": "当通过跨域名AJAX请求(CORS)访问API时,设置此作为起始域名。这必须包括在任何pre-flight请求中,并因此必须是请求的URI的一部分(而不是POST正文)。这必须匹配Origin中的一个起点:从头到底,因此它已经设置为像http://zh.wikipedia.org或https://meta.wikimedia.org的东西。如果此参数不匹配Origin: header,就返回403错误响应。如果此参数匹配Origin: header并且起点被白名单,将设置一个Access-Control-Allow-Origin开头。",
"apihelp-compare-param-fromid": "要比较的第一个页面 ID。",
"apihelp-compare-param-fromrev": "要比较的第一个修订版本。",
"apihelp-compare-param-totitle": "要比较的第二个标题。",
- "apihelp-compare-param-toid": "è¦\81æ¯\94è¾\83ç\9a\84第ä¸\80个页面 ID。",
+ "apihelp-compare-param-toid": "è¦\81æ¯\94è¾\83ç\9a\84第äº\8c个页面 ID。",
"apihelp-compare-param-torev": "要比较的第二个修订版本。",
"apihelp-compare-example-1": "在版本1和2中创建差异",
"apihelp-createaccount-description": "创建一个新用户账户。",
"apihelp-query+alldeletedrevisions-param-miser-user-namespace": "'''注意:'''由于[https://www.mediawiki.org/wiki/Manual:$wgMiserMode miser模式],同时使用$1user和$1namespace将导致继续前返回少于“$1limit”个结果,在极端条件下可能不返回任何结果。",
"apihelp-query+alldeletedrevisions-example-user": "列出由User:Example作出的最近50次已删除贡献",
"apihelp-query+alldeletedrevisions-example-ns-main": "列出最近50次已删除的主名字空间修订",
+ "apihelp-query+allfileusages-param-prefix": "搜索此值开头的所有文件标题。",
"apihelp-query+allfileusages-param-limit": "要返回的总计项目。",
"apihelp-query+allfileusages-param-dir": "罗列所采用的方向。",
"apihelp-query+allfileusages-example-unique": "列出唯一性的文件标题",
"apihelp-query+categorymembers-param-endsortkey": "请改用$1endhexsortkey。",
"apihelp-query+categorymembers-example-simple": "获取[[:Category:Physics]]中的前10个页面。",
"apihelp-query+categorymembers-example-generator": "获取关于[[:Category:Physics]]中的前10个页面的页面信息。",
+ "apihelp-query+contributors-description": "获取对一个页面的登录贡献者列表和匿名贡献数。",
+ "apihelp-query+contributors-param-limit": "返回的贡献数。",
"apihelp-query+contributors-example-simple": "显示[[首页]]的贡献",
"apihelp-query+deletedrevisions-example-titles": "列出[[首页]]和[[Talk:首页]]的已删除修订,包含内容",
"apihelp-query+deletedrevs-paraminfo-modes": "{{PLURAL:$1|模式}}:$2",
"apihelp-query+deletedrevs-param-from": "从此标题开始列出。",
"apihelp-query+deletedrevs-param-to": "列出至此标题为止。",
+ "apihelp-query+deletedrevs-param-user": "只列出此用户做出的修订。",
+ "apihelp-query+deletedrevs-param-excludeuser": "不要列出此用户做出的修订。",
"apihelp-query+deletedrevs-param-namespace": "只列出此名字空间的页面。",
"apihelp-query+deletedrevs-example-mode1": "列出最近已删除的对首页和Talk:首页的贡献,带内容(模式1)",
"apihelp-query+deletedrevs-example-mode2": "列出由Bob作出的最近50次已删除贡献(模式2)",
"apihelp-query+links-example-simple": "从[[首页]]获取链接",
"apihelp-query+links-example-generator": "获取有关[[首页]]链接页面的信息",
"apihelp-query+links-example-namespaces": "获取用户和模板名字空间中来自[[首页]]的链接",
+ "apihelp-query+linkshere-param-namespace": "只包括这些名字空间的页面。",
"apihelp-query+linkshere-param-limit": "返回多少。",
+ "apihelp-query+linkshere-param-show": "只显示符合以下标准的项:\n;redirect:只显示重定向。\n;!redirects:只显示非重定向。",
"apihelp-query+linkshere-example-simple": "获取链接至[[首页]]的页面列表",
"apihelp-query+linkshere-example-generator": "获取有关链接至[[首页]]的页面的信息",
"apihelp-query+logevents-description": "从日志获取事件。",
"apihelp-emailuser-param-text": "郵件內容。",
"apihelp-emailuser-param-ccme": "寄送一份此郵件的複本給我。",
"apihelp-emailuser-example-email": "寄送電子郵件給使用者 \"WikiSysop\" 使用內容 \"Content\"",
- "apihelp-expandtemplates-description": "展開所有於 wikitext 中的樣板。",
+ "apihelp-expandtemplates-description": "展開所有於 wikitext 中模板。",
"apihelp-expandtemplates-param-title": "頁面標題。",
"apihelp-expandtemplates-param-text": "要轉換的 Wikitext。",
"apihelp-login-param-name": "使用者名稱。",
return $prefixes[$table];
} else {
$prefix = null;
- wfRunHooks( 'BacklinkCacheGetPrefix', array( $table, &$prefix ) );
+ Hooks::run( 'BacklinkCacheGetPrefix', array( $table, &$prefix ) );
if ( $prefix ) {
return $prefix;
} else {
break;
default:
$conds = null;
- wfRunHooks( 'BacklinkCacheGetConditions', array( $table, $this->title, &$conds ) );
+ Hooks::run( 'BacklinkCacheGetConditions', array( $table, $this->title, &$conds ) );
if ( !$conds ) {
throw new MWException( "Invalid table \"$table\" in " . __CLASS__ );
}
return false;
}
// Allow extensions to disable caching
- return wfRunHooks( 'HTMLFileCache::useFileCache', array( $context ) );
+ return Hooks::run( 'HTMLFileCache::useFileCache', array( $context ) );
}
/**
# Allow extensions an opportunity to adjust the data for this
# fallback
- wfRunHooks( 'LocalisationCacheRecacheFallback', array( $this, $csCode, &$csData ) );
+ Hooks::run( 'LocalisationCacheRecacheFallback', array( $this, $csCode, &$csData ) );
# Merge the data for this fallback into the final array
if ( $csCode === $code ) {
}
# Run hooks
$purgeBlobs = true;
- wfRunHooks( 'LocalisationCacheRecache', array( $this, $code, &$allData, &$purgeBlobs ) );
+ Hooks::run( 'LocalisationCacheRecache', array( $this, $code, &$allData, &$purgeBlobs ) );
if ( is_null( $allData['namespaceNames'] ) ) {
wfProfileOut( __METHOD__ );
global $wgContLang;
MessageBlobStore::getInstance()->updateMessage( $wgContLang->lcfirst( $msg ) );
- wfRunHooks( 'MessageCacheReplace', array( $title, $text ) );
+ Hooks::run( 'MessageCacheReplace', array( $title, $text ) );
wfProfileOut( __METHOD__ );
}
$lckey = $wgContLang->lcfirst( $lckey );
}
- wfRunHooks( 'MessageCache::get', array( &$lckey ) );
+ Hooks::run( 'MessageCache::get', array( &$lckey ) );
if ( ord( $lckey ) < 128 ) {
$uckey = ucfirst( $lckey );
} else {
// XXX: This is not cached in process cache, should it?
$message = false;
- wfRunHooks( 'MessagesPreLoad', array( $title, &$message ) );
+ Hooks::run( 'MessagesPreLoad', array( $title, &$message ) );
if ( $message !== false ) {
return $message;
}
public static function newFromContext( ResourceLoaderContext $context ) {
$cache = new self();
- if ( $context->getOnly() === 'styles' ) {
+ if ( $context->getImage() ) {
+ $cache->mType = 'image';
+ } elseif ( $context->getOnly() === 'styles' ) {
$cache->mType = 'css';
} else {
$cache->mType = 'js';
// Get all query values
$queryVals = $context->getRequest()->getValues();
foreach ( $queryVals as $query => $val ) {
- if ( $query === 'modules' || $query === 'version' || $query === '*' ) {
+ if ( in_array( $query, array( 'modules', 'image', 'variant', 'version', '*' ) ) ) {
+ // Use file cache regardless of the value of this parameter
continue; // note: &* added as IE fix
} elseif ( $query === 'skin' && $val === $wgDefaultSkin ) {
continue;
continue;
} elseif ( $query === 'debug' && $val === 'false' ) {
continue;
+ } elseif ( $query === 'format' && $val === 'rasterized' ) {
+ continue;
}
return false;
$user = $context->getUser();
$sk = $context->getSkin();
$list = null;
- if ( wfRunHooks( 'FetchChangesList', array( $user, &$sk, &$list ) ) ) {
+ if ( Hooks::run( 'FetchChangesList', array( $user, &$sk, &$list ) ) ) {
$new = $context->getRequest()->getBool( 'enhanced', $user->getOption( 'usenewrc' ) );
return $new ? new EnhancedChangesList( $context ) : new OldChangesList( $context );
* @param ResultWrapper|array $rows
*/
public function initChangesListRows( $rows ) {
- wfRunHooks( 'ChangesListInitRows', array( $this, $rows ) );
+ Hooks::run( 'ChangesListInitRows', array( $this, $rows ) );
}
/**
# RTL/LTR marker
$articlelink .= $this->getLanguage()->getDirMark();
- wfRunHooks( 'ChangesListInsertArticleLink',
+ Hooks::run( 'ChangesListInsertArticleLink',
array( &$this, &$articlelink, &$s, &$rc, $unpatrolled, $watched ) );
$s .= " $articlelink";
$rc->mAttribs['rc_namespace'] . '-' . $rc->mAttribs['rc_title'] );
}
- if ( !wfRunHooks( 'OldChangesListRecentChangesLine', array( &$this, &$html, $rc, &$classes ) ) ) {
+ if ( !Hooks::run( 'OldChangesListRecentChangesLine', array( &$this, &$html, $rc, &$classes ) ) ) {
wfProfileOut( __METHOD__ );
return false;
/**
* @param RecentChange $rc
* @param string[] &$classes
- * @param boolean $watched
+ * @param bool $watched
*
* @return string
*/
public function getPerformer() {
if ( $this->mPerformer === false ) {
if ( $this->mAttribs['rc_user'] ) {
- $this->mPerformer = User::newFromID( $this->mAttribs['rc_user'] );
+ $this->mPerformer = User::newFromId( $this->mAttribs['rc_user'] );
} else {
$this->mPerformer = User::newFromName( $this->mAttribs['rc_user_text'], false );
}
$this->mAttribs['rc_id'] = $dbw->insertId();
# Notify extensions
- wfRunHooks( 'RecentChange_save', array( &$this ) );
+ Hooks::run( 'RecentChange_save', array( &$this ) );
# Notify external application via UDP
if ( !$noudp ) {
$editor = $this->getPerformer();
$title = $this->getTitle();
- if ( wfRunHooks( 'AbortEmailNotification', array( $editor, $title, $this ) ) ) {
+ if ( Hooks::run( 'AbortEmailNotification', array( $editor, $title, $this ) ) ) {
# @todo FIXME: This would be better as an extension hook
$enotif = new EmailNotification();
$enotif->notifyOnPageChange( $editor, $title,
// Automatic patrol needs "autopatrol", ordinary patrol needs "patrol"
$right = $auto ? 'autopatrol' : 'patrol';
$errors = array_merge( $errors, $this->getTitle()->getUserPermissionsErrors( $right, $user ) );
- if ( !wfRunHooks( 'MarkPatrolled', array( $this->getAttribute( 'rc_id' ), &$user, false ) ) ) {
+ if ( !Hooks::run( 'MarkPatrolled', array( $this->getAttribute( 'rc_id' ), &$user, false ) ) ) {
$errors[] = array( 'hookaborted' );
}
// Users without the 'autopatrol' right can't patrol their
$this->reallyMarkPatrolled();
// Log this patrol event
PatrolLog::record( $this, $auto, $user );
- wfRunHooks( 'MarkPatrolledComplete', array( $this->getAttribute( 'rc_id' ), &$user, false ) );
+ Hooks::run( 'MarkPatrolledComplete', array( $this->getAttribute( 'rc_id' ), &$user, false ) );
return array();
}
$lossy = ( $lossy === 'lossy' ); // string flag, convert to boolean for convenience
$result = false;
- wfRunHooks( 'ConvertContent', array( $this, $toModel, $lossy, &$result ) );
+ Hooks::run( 'ConvertContent', array( $this, $toModel, $lossy, &$result ) );
return $result;
}
$po = new ParserOutput();
- if ( wfRunHooks( 'ContentGetParserOutput',
+ if ( Hooks::run( 'ContentGetParserOutput',
array( $this, $title, $revId, $options, $generateHtml, &$po ) ) ) {
// Save and restore the old value, just in case something is reusing
$options->setRedirectTarget( $oldRedir );
}
- wfRunHooks( 'ContentAlterParserOutput', array( $this, $title, $po ) );
+ Hooks::run( 'ContentAlterParserOutput', array( $this, $title, $po ) );
return $po;
}
$model = MWNamespace::getNamespaceContentModel( $ns );
// Hook can determine default model
- if ( !wfRunHooks( 'ContentHandlerDefaultModelFor', array( $title, &$model ) ) ) {
+ if ( !Hooks::run( 'ContentHandlerDefaultModelFor', array( $title, &$model ) ) ) {
if ( !is_null( $model ) ) {
return $model;
}
}
// Hook can force JS/CSS
- wfRunHooks( 'TitleIsCssOrJsPage', array( $title, &$isCssOrJsPage ), '1.25' );
+ Hooks::run( 'TitleIsCssOrJsPage', array( $title, &$isCssOrJsPage ), '1.25' );
// Is this a .css subpage of a user page?
$isJsCssSubpage = NS_USER == $ns
$isWikitext = $isWikitext && !$isCssOrJsPage && !$isJsCssSubpage;
// Hook can override $isWikitext
- wfRunHooks( 'TitleIsWikitextPage', array( $title, &$isWikitext ), '1.25' );
+ Hooks::run( 'TitleIsWikitextPage', array( $title, &$isWikitext ), '1.25' );
if ( !$isWikitext ) {
switch ( $ext ) {
if ( empty( $wgContentHandlers[$modelId] ) ) {
$handler = null;
- wfRunHooks( 'ContentHandlerForModelID', array( $modelId, &$handler ) );
+ Hooks::run( 'ContentHandlerForModelID', array( $modelId, &$handler ) );
if ( $handler === null ) {
throw new MWException( "No handler for model '$modelId' registered in \$wgContentHandlers" );
$pageLang = wfGetLangObj( $lang );
}
- wfRunHooks( 'PageContentLanguage', array( $title, &$pageLang, $wgLang ) );
+ Hooks::run( 'PageContentLanguage', array( $title, &$pageLang, $wgLang ) );
return wfGetLangObj( $pageLang );
}
public function canBeUsedOn( Title $title ) {
$ok = true;
- wfRunHooks( 'ContentModelCanBeUsedOn', array( $this->getModelID(), $title, &$ok ) );
+ Hooks::run( 'ContentModelCanBeUsedOn', array( $this->getModelID(), $title, &$ok ) );
return $ok;
}
}
// call the hook functions
- $ok = wfRunHooks( $event, $args );
+ $ok = Hooks::run( $event, $args );
// see if the hook changed the text
foreach ( $contentTexts as $k => $orig ) {
# Inserting a new section
$subject = $sectionTitle ? wfMessage( 'newsectionheaderdefaultlevel' )
->rawParams( $sectionTitle )->inContentLanguage()->text() . "\n\n" : '';
- if ( wfRunHooks( 'PlaceNewSection', array( $this, $oldtext, $subject, &$text ) ) ) {
+ if ( Hooks::run( 'PlaceNewSection', array( $this, $oldtext, $subject, &$text ) ) ) {
$text = strlen( trim( $oldtext ) ) > 0
? "{$oldtext}\n\n{$subject}{$text}"
: "{$subject}{$text}";
$code = $request->getVal( 'uselang', $user->getOption( 'language' ) );
$code = self::sanitizeLangCode( $code );
- wfRunHooks( 'UserGetLanguageObject', array( $user, &$code, $this ) );
+ Hooks::run( 'UserGetLanguageObject', array( $user, &$code, $this ) );
if ( $code === $this->getConfig()->get( 'LanguageCode' ) ) {
$this->lang = $wgContLang;
wfProfileIn( __METHOD__ . '-createskin' );
$skin = null;
- wfRunHooks( 'RequestContextCreateSkin', array( $this, &$skin ) );
+ Hooks::run( 'RequestContextCreateSkin', array( $this, &$skin ) );
$factory = SkinFactory::getDefaultInstance();
// If the hook worked try to set a skin from it
/** Maximum time to wait before retry */
const DEADLOCK_DELAY_MAX = 1500000;
-# ------------------------------------------------------------------------------
-# Variables
-# ------------------------------------------------------------------------------
-
protected $mLastQuery = '';
protected $mDoneWrites = false;
protected $mPHPError = false;
*/
protected $allViews = null;
-# ------------------------------------------------------------------------------
-# Accessors
-# ------------------------------------------------------------------------------
- # These optionally set a variable and return the previous state
-
/**
* A string describing the current software version, and possibly
* other details in a user-friendly way. Will be listed on Special:Version, etc.
return $this->getSqlFilePath( 'update-keys.sql' );
}
-# ------------------------------------------------------------------------------
-# Other functions
-# ------------------------------------------------------------------------------
+ /**
+ * Get the type of the DBMS, as it appears in $wgDBtype.
+ *
+ * @return string
+ */
+ abstract function getType();
+
+ /**
+ * Open a connection to the database. Usually aborts on failure
+ *
+ * @param string $server Database server host
+ * @param string $user Database user name
+ * @param string $password Database user password
+ * @param string $dbName Database name
+ * @return bool
+ * @throws DBConnectionError
+ */
+ abstract function open( $server, $user, $password, $dbName );
+
+ /**
+ * Fetch the next row from the given result object, in object form.
+ * Fields can be retrieved with $row->fieldname, with fields acting like
+ * member variables.
+ * If no more rows are available, false is returned.
+ *
+ * @param ResultWrapper|stdClass $res Object as returned from DatabaseBase::query(), etc.
+ * @return stdClass|bool
+ * @throws DBUnexpectedError Thrown if the database returns an error
+ */
+ abstract function fetchObject( $res );
+
+ /**
+ * Fetch the next row from the given result object, in associative array
+ * form. Fields are retrieved with $row['fieldname'].
+ * If no more rows are available, false is returned.
+ *
+ * @param ResultWrapper $res Result object as returned from DatabaseBase::query(), etc.
+ * @return array|bool
+ * @throws DBUnexpectedError Thrown if the database returns an error
+ */
+ abstract function fetchRow( $res );
+
+ /**
+ * Get the number of rows in a result object
+ *
+ * @param mixed $res A SQL result
+ * @return int
+ */
+ abstract function numRows( $res );
+
+ /**
+ * Get the number of fields in a result object
+ * @see http://www.php.net/mysql_num_fields
+ *
+ * @param mixed $res A SQL result
+ * @return int
+ */
+ abstract function numFields( $res );
+
+ /**
+ * Get a field name in a result object
+ * @see http://www.php.net/mysql_field_name
+ *
+ * @param mixed $res A SQL result
+ * @param int $n
+ * @return string
+ */
+ abstract function fieldName( $res, $n );
+
+ /**
+ * Get the inserted value of an auto-increment row
+ *
+ * The value inserted should be fetched from nextSequenceValue()
+ *
+ * Example:
+ * $id = $dbw->nextSequenceValue( 'page_page_id_seq' );
+ * $dbw->insert( 'page', array( 'page_id' => $id ) );
+ * $id = $dbw->insertId();
+ *
+ * @return int
+ */
+ abstract function insertId();
+
+ /**
+ * Change the position of the cursor in a result object
+ * @see http://www.php.net/mysql_data_seek
+ *
+ * @param mixed $res A SQL result
+ * @param int $row
+ */
+ abstract function dataSeek( $res, $row );
+
+ /**
+ * Get the last error number
+ * @see http://www.php.net/mysql_errno
+ *
+ * @return int
+ */
+ abstract function lastErrno();
+
+ /**
+ * Get a description of the last error
+ * @see http://www.php.net/mysql_error
+ *
+ * @return string
+ */
+ abstract function lastError();
+
+ /**
+ * mysql_fetch_field() wrapper
+ * Returns false if the field doesn't exist
+ *
+ * @param string $table Table name
+ * @param string $field Field name
+ *
+ * @return Field
+ */
+ abstract function fieldInfo( $table, $field );
+
+ /**
+ * Get information about an index into an object
+ * @param string $table Table name
+ * @param string $index Index name
+ * @param string $fname Calling function name
+ * @return mixed Database-specific index description class or false if the index does not exist
+ */
+ abstract function indexInfo( $table, $index, $fname = __METHOD__ );
+
+ /**
+ * Get the number of rows affected by the last write query
+ * @see http://www.php.net/mysql_affected_rows
+ *
+ * @return int
+ */
+ abstract function affectedRows();
+
+ /**
+ * Wrapper for addslashes()
+ *
+ * @param string $s String to be slashed.
+ * @return string Slashed string.
+ */
+ abstract function strencode( $s );
+
+ /**
+ * Returns a wikitext link to the DB's website, e.g.,
+ * return "[http://www.mysql.com/ MySQL]";
+ * Should at least contain plain text, if for some reason
+ * your database has no website.
+ *
+ * @return string Wikitext of a link to the server software's web site
+ */
+ abstract function getSoftwareLink();
+
+ /**
+ * A string describing the current software version, like from
+ * mysql_get_server_info().
+ *
+ * @return string Version information from the database server.
+ */
+ abstract function getServerVersion();
/**
* Constructor.
$this->reportQueryError( $this->lastError(), $this->lastErrno(), $sql, $fname, $tempIgnore );
}
- return $this->resultObject( $ret );
+ $res = $this->resultObject( $ret );
+
+ // Destroy profile sections in the opposite order to their creation
+ $queryProfSection = false;
+ $totalProfSection = false;
+
+ return $res;
}
/**
class MySQLMasterPos implements DBMasterPos {
/** @var string */
public $file;
-
- /** @var int Timestamp */
+ /** @var int Position */
public $pos;
+ /** @var float UNIX timestamp */
+ public $asOfTime = 0.0;
function __construct( $file, $pos ) {
$this->file = $file;
$this->pos = $pos;
+ $this->asOfTime = microtime( true );
}
function __toString() {
return ( $thisPos && $thatPos && $thisPos >= $thatPos );
}
+
+ function asOfTime() {
+ return $this->asOfTime;
+ }
}
}
$p['tablePrefix'] = strtoupper( $p['tablePrefix'] );
parent::__construct( $p );
- wfRunHooks( 'DatabaseOraclePostInit', array( $this ) );
+ Hooks::run( 'DatabaseOraclePostInit', array( $this ) );
}
function __destruct() {
* The implementation details of this opaque type are up to the database subclass.
*/
interface DBMasterPos {
+ /**
+ * @return float UNIX timestamp
+ */
+ public function asOfTime();
}
*
* @return LBFactory
*/
- public static function &singleton() {
+ public static function singleton() {
global $wgLBFactoryConf;
if ( is_null( self::$instance ) ) {
/**
* @param array $loads
* @param bool|string $wiki Wiki to get non-lagged for
+ * @param float $maxLag Restrict the maximum allowed lag to this many seconds
* @return bool|int|string
*/
- private function getRandomNonLagged( array $loads, $wiki = false ) {
- # Unset excessively lagged servers
+ private function getRandomNonLagged( array $loads, $wiki = false, $maxLag = INF ) {
$lags = $this->getLagTimes( $wiki );
+
+ # Unset excessively lagged servers
foreach ( $lags as $i => $lag ) {
if ( $i != 0 ) {
+ $maxServerLag = $maxLag;
+ if ( isset( $this->mServers[$i]['max lag'] ) ) {
+ $maxServerLag = min( $maxServerLag, $this->mServers[$i]['max lag'] );
+ }
if ( $lag === false ) {
wfDebugLog( 'replication', "Server #$i is not replicating" );
unset( $loads[$i] );
- } elseif ( isset( $this->mServers[$i]['max lag'] ) && $lag > $this->mServers[$i]['max lag'] ) {
+ } elseif ( $lag > $maxServerLag ) {
wfDebugLog( 'replication', "Server #$i is excessively lagged ($lag seconds)" );
unset( $loads[$i] );
}
if ( $wgReadOnly || $this->mAllowLagged || $laggedSlaveMode ) {
$i = ArrayUtils::pickRandom( $currentLoads );
} else {
- $i = $this->getRandomNonLagged( $currentLoads, $wiki );
+ $i = false;
+ if ( $this->mWaitForPos && $this->mWaitForPos->asOfTime() ) {
+ # ChronologyProtecter causes mWaitForPos to be set via sessions.
+ # This triggers doWait() after connect, so it's especially good to
+ # avoid lagged servers so as to avoid just blocking in that method.
+ $ago = microtime( true ) - $this->mWaitForPos->asOfTime();
+ # Aim for <= 1 second of waiting (being too picky can backfire)
+ $i = $this->getRandomNonLagged( $currentLoads, $wiki, $ago + 1 );
+ }
+ if ( $i === false ) {
+ # Any server with less lag than it's 'max lag' param is preferable
+ $i = $this->getRandomNonLagged( $currentLoads, $wiki );
+ }
if ( $i === false && count( $currentLoads ) != 0 ) {
# All slaves lagged. Switch to read-only mode
wfDebugLog( 'replication', "All slaves lagged. Switch to read-only mode" );
* @throws MWException
* @return DatabaseBase
*/
- public function &getConnection( $i, $groups = array(), $wiki = false ) {
+ public function getConnection( $i, $groups = array(), $wiki = false ) {
wfProfileIn( __METHOD__ );
if ( $i === null || $i === false ) {
$wiki = false;
}
- # Query groups
+ $groups = ( $groups === false || $groups === array() )
+ ? array( false ) // check one "group": the generic pool
+ : (array)$groups;
+
if ( $i == DB_MASTER ) {
$i = $this->getWriterIndex();
- } elseif ( !is_array( $groups ) ) {
- $groupIndex = $this->getReaderIndex( $groups, $wiki );
- if ( $groupIndex !== false ) {
- $serverName = $this->getServerName( $groupIndex );
- wfDebug( __METHOD__ . ": using server $serverName for group $groups\n" );
- $i = $groupIndex;
- }
} else {
+ # Try to find an available server in any the query groups (in order)
foreach ( $groups as $group ) {
$groupIndex = $this->getReaderIndex( $group, $wiki );
if ( $groupIndex !== false ) {
# Operation-based index
if ( $i == DB_SLAVE ) {
$this->mLastError = 'Unknown error'; // reset error string
- $i = $this->getReaderIndex( false, $wiki );
+ # Try the general server pool if $groups are unavailable.
+ $i = in_array( false, $groups, true )
+ ? false // don't bother with this if that is what was tried above
+ : $this->getReaderIndex( false, $wiki );
# Couldn't find a working server in getReaderIndex()?
if ( $i === false ) {
$this->mLastError = 'No working slave server: ' . $this->mLastError;
$this->mRecursive = $recursive;
- wfRunHooks( 'LinksUpdateConstructed', array( &$this ) );
+ Hooks::run( 'LinksUpdateConstructed', array( &$this ) );
}
/**
* Update link tables with outgoing links from an updated article
*/
public function doUpdate() {
- wfRunHooks( 'LinksUpdate', array( &$this ) );
+ Hooks::run( 'LinksUpdate', array( &$this ) );
$this->doIncrementalUpdate();
- wfRunHooks( 'LinksUpdateComplete', array( &$this ) );
+ Hooks::run( 'LinksUpdateComplete', array( &$this ) );
}
protected function doIncrementalUpdate() {
}
if ( count( $insertions ) ) {
$this->mDb->insert( $table, $insertions, __METHOD__, 'IGNORE' );
- wfRunHooks( 'LinksUpdateAfterInsert', array( $this, $table, $insertions ) );
+ Hooks::run( 'LinksUpdateAfterInsert', array( $this, $table, $insertions ) );
}
}
wfProfileIn( __METHOD__ );
- $page = WikiPage::newFromId( $this->id, WikiPage::READ_LATEST );
+ $page = WikiPage::newFromID( $this->id, WikiPage::READ_LATEST );
foreach ( SearchEngine::getSearchTypes() as $type ) {
$search = SearchEngine::create( $type );
$samePage = true;
$oldHeader = '';
} else {
- wfRunHooks( 'DiffViewHeader', array( $this, $this->mOldRev, $this->mNewRev ) );
+ Hooks::run( 'DiffViewHeader', array( $this, $this->mOldRev, $this->mNewRev ) );
if ( $this->mNewPage->equals( $this->mOldPage ) ) {
$out->setPageTitle( $this->msg( 'difference-title', $this->mNewPage->getPrefixedText() ) );
$rdel = $this->revisionDeleteLink( $this->mNewRev );
# Allow extensions to define their own revision tools
- wfRunHooks( 'DiffRevisionTools', array( $this->mNewRev, &$revisionTools, $this->mOldRev ) );
+ Hooks::run( 'DiffRevisionTools', array( $this->mNewRev, &$revisionTools, $this->mOldRev ) );
$formattedRevisionTools = array();
// Put each one in parentheses (poor man's button)
foreach ( $revisionTools as $key => $tool ) {
<h2 class='diff-currentversion-title'>{$revHeader}</h2>\n" );
# Page content may be handled by a hooked call instead...
# @codingStandardsIgnoreStart Ignoring long lines.
- if ( wfRunHooks( 'ArticleContentOnDiff', array( $this, $out ) ) ) {
+ if ( Hooks::run( 'ArticleContentOnDiff', array( $this, $out ) ) ) {
$this->loadNewText();
$out->setRevisionId( $this->mNewid );
$out->setRevisionTimestamp( $this->mNewRev->getTimestamp() );
$out->addParserOutputContent( $po );
}
}
- } elseif ( !wfRunHooks( 'ArticleContentViewCustom', array( $this->mNewContent, $this->mNewPage, $out ) ) ) {
+ } elseif ( !Hooks::run( 'ArticleContentViewCustom', array( $this->mNewContent, $this->mNewPage, $out ) ) ) {
// Handled by extension
} elseif ( !ContentHandler::runLegacyHooks( 'ArticleViewCustom', array( $this->mNewContent, $this->mNewPage, $out ) ) ) {
// NOTE: deprecated hook, B/C only
$difftext = $this->generateContentDiffBody( $this->mOldContent, $this->mNewContent );
// Save to cache for 7 days
- if ( !wfRunHooks( 'AbortDiffCache', array( &$this ) ) ) {
+ if ( !Hooks::run( 'AbortDiffCache', array( &$this ) ) ) {
wfIncrStats( 'diff_uncacheable' );
} elseif ( $key !== false && $difftext !== false ) {
wfIncrStats( 'diff_cache_miss' );
$this->mNewid = 0;
}
- wfRunHooks(
+ Hooks::run(
'NewDifferenceEngine',
array( $this->getTitle(), &$this->mOldid, &$this->mNewid, $old, $new )
);
*/
class MWExceptionHandler {
+ protected static $reservedMemory;
+ protected static $fatalErrorTypes = array(
+ E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR,
+ /* HHVM's FATAL_ERROR level */ 16777217,
+ );
+
/**
* Install handlers with PHP.
*/
public static function installHandler() {
set_exception_handler( array( 'MWExceptionHandler', 'handleException' ) );
set_error_handler( array( 'MWExceptionHandler', 'handleError' ) );
+
+ // Reserve 16k of memory so we can report OOM fatals
+ self::$reservedMemory = str_repeat( ' ', 16384 );
+ register_shutdown_function(
+ array( 'MWExceptionHandler', 'handleFatalError' )
+ );
}
/**
case E_USER_DEPRECATED:
$levelName = 'Deprecated';
break;
+ case /* HHVM's FATAL_ERROR */ 16777217:
+ $levelName = 'Fatal';
+ break;
default:
$levelName = 'Unknown error';
break;
return false;
}
+
+ /**
+ * Look for a fatal error as the cause of the request termination and log
+ * as an exception.
+ *
+ * Special handling is included for missing class errors as they may
+ * indicate that the user needs to install 3rd-party libraries via
+ * Composer or other means.
+ *
+ * @since 1.25
+ */
+ public static function handleFatalError() {
+ self::$reservedMemory = null;
+ $lastError = error_get_last();
+
+ if ( $lastError &&
+ isset( $lastError['type'] ) &&
+ in_array( $lastError['type'], self::$fatalErrorTypes )
+ ) {
+ $msg = "Fatal Error: {$lastError['message']}";
+ // HHVM: Class undefined: foo
+ // PHP5: Class 'foo' not found
+ if ( preg_match( "/Class (undefined: \w+|'\w+' not found)/",
+ $lastError['message']
+ ) ) {
+ $msg = <<<TXT
+{$msg}
+
+MediaWiki or an installed extension requires this class but it is not embedded directly in MediaWiki's git repository and must be installed separately by the end user.
+
+Please see <a href="https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries">mediawiki.org</a> for help on installing the required components.
+TXT;
+ }
+ $e = new ErrorException( $msg, 0, $lastError['type'] );
+ self::logError( $e );
+ }
+ }
+
/**
* Generate a string representation of an exception's stack trace
*
$thumb = $this->transformErrorOutput( $thumbPath, $thumbUrl, $transformParams, $flags );
}
// Give extensions a chance to do something with this thumbnail...
- wfRunHooks( 'FileTransformed', array( $this, $thumb, $tmpThumbPath, $thumbPath ) );
+ Hooks::run( 'FileTransformed', array( $this, $thumb, $tmpThumbPath, $thumbPath ) );
}
// Purge. Useful in the event of Core -> Squid connection failure or squid
$files = $this->getThumbnails( $archiveName );
// Purge any custom thumbnail caches
- wfRunHooks( 'LocalFilePurgeThumbnails', array( $this, $archiveName ) );
+ Hooks::run( 'LocalFilePurgeThumbnails', array( $this, $archiveName ) );
$dir = array_shift( $files );
$this->purgeThumbList( $dir, $files );
}
// Purge any custom thumbnail caches
- wfRunHooks( 'LocalFilePurgeThumbnails', array( $this, false ) );
+ Hooks::run( 'LocalFilePurgeThumbnails', array( $this, false ) );
$dir = array_shift( $files );
$this->purgeThumbList( $dir, $files );
$opts['ORDER BY'] = "oi_timestamp $order";
$opts['USE INDEX'] = array( 'oldimage' => 'oi_name_timestamp' );
- wfRunHooks( 'LocalFile::getHistory', array( &$this, &$tables, &$fields,
+ Hooks::run( 'LocalFile::getHistory', array( &$this, &$tables, &$fields,
&$conds, &$opts, &$join_conds ) );
$res = $dbr->select( $tables, $fields, $conds, __METHOD__, $opts, $join_conds );
if ( !is_null( $nullRevision ) ) {
$nullRevision->insertOn( $dbw );
- wfRunHooks( 'NewRevisionFromEditComplete', array( $wikiPage, $nullRevision, $latest, $user ) );
+ Hooks::run( 'NewRevisionFromEditComplete', array( $wikiPage, $nullRevision, $latest, $user ) );
$wikiPage->updateRevisionOn( $dbw, $nullRevision );
}
}
# Hooks, hooks, the magic of hooks...
wfProfileIn( __METHOD__ . '-hooks' );
- wfRunHooks( 'FileUpload', array( $this, $reupload, $descTitle->exists() ) );
+ Hooks::run( 'FileUpload', array( $this, $reupload, $descTitle->exists() ) );
wfProfileOut( __METHOD__ . '-hooks' );
# Invalidate cache for all pages using this file
'packed-overlay' => 'PackedOverlayImageGallery',
);
// Allow extensions to make a new gallery format.
- wfRunHooks( 'GalleryGetModes', self::$modeMapping );
+ Hooks::run( 'GalleryGetModes', self::$modeMapping );
}
}
if ( $this->mParser instanceof Parser ) {
# Give extensions a chance to select the file revision for us
$options = array();
- wfRunHooks( 'BeforeParserFetchFileAndTitle',
+ Hooks::run( 'BeforeParserFetchFileAndTitle',
array( $this->mParser, $nt, &$options, &$descQuery ) );
# Fetch and register the file (file title may be different via hooks)
list( $img, $nt ) = $this->mParser->fetchFileAndTitle( $nt, $options );
$this->maintenance->setDB( $db );
$this->initOldGlobals();
$this->loadExtensions();
- wfRunHooks( 'LoadExtensionSchemaUpdates', array( $this ) );
+ Hooks::run( 'LoadExtensionSchemaUpdates', array( $this ) );
}
/**
"config-env-good": "పర్యావరణాన్ని పరీక్షించాం.\nఇక మీరు MediaWiki ని స్థాపించుకోవచ్చు.",
"config-env-bad": "పర్యావరణాన్ని పరీక్షించాం.\nమీరు MediaWiki ని స్థాపించలేరు.",
"config-env-php": "PHP $1 స్థాపించబడింది.",
- "config-env-php-toolow": "PHP $1 స్థాపించబడింది.\nఅయితే, MediaWiki కి PHP $2 గానీ ఆ పైది గానీ కావాలి.",
"config-unicode-using-utf8": "యూనికోడు నార్మలైజేషన్ కోసం బ్రయాన్ విబర్ గారి utf8_normalize.so ను వాడుతున్నాం.",
"config-unicode-using-intl": "యూనికోడు నార్మలైజేషన్ కోసం [http://pecl.php.net/intl intl PECL పొడిగింత] ను వాడుతున్నాం.",
"config-outdated-sqlite": "<strong>హెచ్చరిక:</strong> మీ వద్ద SQLite $1 ఉంది. అదికావలసిన వెర్షను $2 కంటే దిగువది. SQLite అందుబాటులో ఉండదు.",
"config-memcache-badport": "Memcached పోర్టు సఖ్యలు $1, $2 ల మధ్య ఉండాలి.",
"config-extensions": "పొడిగింతలు",
"config-extensions-help": "పైన చూపిన పొడిగింతలు మీ <code>./extensions</code> డైరెక్టరీలో ఉన్నాయి.\n\nవాటికి అదనంగా కాన్ఫిగరేషన్ అవసరం కావచ్చు. అయితే మీరు వాటిని చేతనం చెయ్యవచ్చు.",
+ "config-skins": "అలంకారాలు",
"config-install-alreadydone": "<strong>హెచ్చరిక:</strong> మీరు ఈసరికే MediaWiki ని స్థాపించినట్లుగా అనిపిస్తోంది. మళ్ళీ స్థాపించే ప్రయత్నం చేస్తున్నట్లున్నారు.\nతరువాత పేజీకి వెళ్ళండి.",
"config-install-begin": "\"{{int:config-continue}}\" నొక్కి, MediaWiki స్థాపనను మొదలుపెట్టవచ్చు.\nఇంకా మార్పులు చెయ్యదలిస్తే, \"{{int:config-back}}\" నొక్కండి.",
"config-install-step-done": "పూర్తయింది",
"authors": [
"පසිඳු කාවින්ද",
"Minh Nguyen",
- "Withoutaname"
+ "Withoutaname",
+ "Dinhxuanduyet"
]
},
"config-desc": "Trình cài đặt MediaWiki",
"config-title": "Cài đặt MediaWiki $1",
"config-information": "Thông tin",
+ "config-localsettings-upgrade": "Một file <code>LocalSettings.php</code> đã được phát hiện.\nĐể nâng cấp cài đặt này, xin nhập giá trị của <code>$wgUpgradeKey</code> trong hộp thoại bên dưới đây.\nBạn sẽ tìm thấy nó trong<code>LocalSettings.php</code>.",
+ "config-localsettings-cli-upgrade": "Một file <code>LocalSettings.php</code> đã được phát hiện.\nĐể nâng cấp cài đặt này, hãy chạy <code>update.php</code>",
"config-localsettings-key": "Chìa khóa nâng cấp:",
"config-localsettings-badkey": "Bạn đã cung cấp một chìa khóa sai.",
+ "config-upgrade-key-missing": "Có một bản cài đặt của MediaWiki sẵn trước đó đã được phát hiện.\nĐể nâng cấp cài đặt này, hãy đặt dòng sau vào dưới của của <code>LocalSettings.php</code>:\n\n$1",
"config-session-error": "Lỗi khi bắt đầu phiên làm việc: $1",
"config-your-language": "Ngôn ngữ của bạn:",
"config-your-language-help": "Chọn một ngôn ngữ để sử dụng trong quá trình cài đặt.",
"config-license-gfdl": "GNU 自由文件授權條款 1.3 或更高版本",
"config-license-pd": "公共領域",
"config-license-cc-choose": "請選擇一個自訂的創作共用授權條款",
- "config-license-help": "許多開放式 Wiki 會以 [http://freedomdefined.org/Definition 自由授權條款] 的方式釋放出編者的所有貢獻,這有助於構建社群的所有權,並且能鼓勵長期貢獻。對於封閉式的 Wiki 或公司 Wiki 則是非必要的。\n\n如果您希望使用來自維基百科(Wikipedia)的內容,並希望維基百科能接受您的 Wiki 內容,請應選擇 <strong>{{int:config-license-cc-by-sa}}</strong> 授權條款。\n\n維基百科̽(Wikipedia)先前是使用 GNU 自由文件授權條款,\n但該授權條款的內容較難理解,因此較難再利用在該條款底下的內容。",
+ "config-license-help": "許多開放式 Wiki 會以 [http://freedomdefined.org/Definition 自由授權條款] 的方式釋放出編者的所有貢獻,這有助於構建社群的所有權,並且能鼓勵長期貢獻。對於封閉式的 Wiki 或公司 Wiki 則是非必要的。\n\n如果您希望使用來自維基百科(Wikipedia)的內容,並希望維基百科能接受您的 Wiki 內容,請應選擇 <strong>{{int:config-license-cc-by-sa}}</strong> 授權條款。\n\n維基百科(Wikipedia)先前是使用 GNU 自由文件授權條款,\n但該授權條款的內容較難理解,因此較難再利用在該條款底下的內容。",
"config-email-settings": "E-mail 設定",
"config-enable-email": "開啟外寄電子郵件",
"config-enable-email-help": "如果您要使用電子郵件功能,請正確設定 [http://www.php.net/manual/en/mail.configuration.php PHP 的郵件設定]。\n如果您不需要使用電子郵件功能,請在此處關閉。",
global $wgMemc, $wgInterwikiExpiry;
$iwData = array();
- if ( !wfRunHooks( 'InterwikiLoadPrefix', array( $prefix, &$iwData ) ) ) {
+ if ( !Hooks::run( 'InterwikiLoadPrefix', array( $prefix, &$iwData ) ) ) {
return Interwiki::loadFromArray( $iwData );
}
*
* @param mixed $value
*
- * @return boolean
+ * @return bool
*/
protected function hasValidType( $value ) {
$class = $this->getObjectType();
* @param integer|string $index
* @param mixed $value
*
- * @return boolean
+ * @return bool
*/
protected function preSetElement( $index, $value ) {
return true;
*
* @since 1.20
*
- * @return boolean
+ * @return bool
*/
public function isEmpty() {
return $this->count() === 0;
* Match an IP address against the set
*
* @param string $ip string IPv[46] address
- * @return boolean true is match success, false is match failure
+ * @return bool true is match success, false is match failure
*
* If $ip is unparseable, inet_pton may issue an E_WARNING to that effect
*/
class ScopedCallback {
/** @var callable */
protected $callback;
+ /** @var array */
+ protected $params;
/**
* @param callable $callback
+ * @param array $params Callback arguments (since 1.25)
* @throws Exception
*/
- public function __construct( $callback ) {
+ public function __construct( $callback, array $params = array() ) {
if ( !is_callable( $callback ) ) {
throw new InvalidArgumentException( "Provided callback is not valid." );
}
$this->callback = $callback;
+ $this->params = $params;
}
/**
*/
function __destruct() {
if ( $this->callback !== null ) {
- call_user_func( $this->callback );
+ call_user_func_array( $this->callback, $this->params );
}
}
}
* SAX element handler event. This gives you access to the element
* namespace, name, attributes, and text contents.
* Filter should return 'true' to toggle on $this->filterMatch
- * @param boolean $isFile (optional) indicates if the first parameter is a
+ * @param bool $isFile (optional) indicates if the first parameter is a
* filename (default, true) or if it is a string (false)
* @param array $options list of additional parsing options:
* processing_instruction_handler: Callback for xml_set_processing_instruction_handler
} else {
// Allow extensions to add their own extra inputs
$input = '';
- wfRunHooks( 'LogEventsListGetExtraInputs', array( $types[0], $this, &$input ) );
+ Hooks::run( 'LogEventsListGetExtraInputs', array( $types[0], $this, &$input ) );
return $input;
}
}
}
/* hook can return false, if we don't want the message to be emitted (Wikia BugId:7093) */
- if ( wfRunHooks( 'LogEventsListShowLogExtract', array( &$s, $types, $page, $user, $param ) ) ) {
+ if ( Hooks::run( 'LogEventsListShowLogExtract', array( &$s, $types, $page, $user, $param ) ) ) {
// $out can be either an OutputPage object or a String-by-reference
if ( $out instanceof OutputPage ) {
$out->addHTML( $s );
$params = $this->entry->getParameters();
- wfRunHooks( 'LogLine', array( $type, $subtype, $title, $params,
+ Hooks::run( 'LogLine', array( $type, $subtype, $title, $params,
&$this->comment, &$this->revert, $this->entry->getTimestamp() ) );
return $this->revert;
$formattedPageStatus = array( 'deleted', 'created', 'moved', 'restored', 'changed' );
- wfRunHooks( 'UpdateUserMailerFormattedPageStatus', array( &$formattedPageStatus ) );
+ Hooks::run( 'UpdateUserMailerFormattedPageStatus', array( &$formattedPageStatus ) );
if ( !in_array( $this->pageStatus, $formattedPageStatus ) ) {
wfProfileOut( __METHOD__ );
throw new MWException( 'Not a valid page status!' );
&& $watchingUser->isEmailConfirmed()
&& $watchingUser->getID() != $userTalkId
) {
- if ( wfRunHooks( 'SendWatchlistEmailNotification', array( $watchingUser, $title, $this ) ) ) {
+ if ( Hooks::run( 'SendWatchlistEmailNotification', array( $watchingUser, $title, $this ) ) ) {
$this->compose( $watchingUser );
}
}
) {
if ( !$targetUser->isEmailConfirmed() ) {
wfDebug( __METHOD__ . ": talk page owner doesn't have validated email\n" );
- } elseif ( !wfRunHooks( 'AbortTalkPageEmailNotification', array( $targetUser, $title ) ) ) {
+ } elseif ( !Hooks::run( 'AbortTalkPageEmailNotification', array( $targetUser, $title ) ) ) {
wfDebug( __METHOD__ . ": talk page update notification is aborted for this user\n" );
} else {
wfDebug( __METHOD__ . ": sending talk page update notification\n" );
$extraParams = $wgAdditionalMailParams;
// Hook to generate custom VERP address for 'Return-Path'
- wfRunHooks( 'UserMailerChangeReturnPath', array( $to, &$returnPath ) );
+ Hooks::run( 'UserMailerChangeReturnPath', array( $to, &$returnPath ) );
# Add the envelope sender address using the -f command line option when PHP mail() is used.
# Will default to the $from->address when the UserMailerChangeReturnPath hook fails and the
# generated VERP address when the hook runs effectively.
$headers['Content-transfer-encoding'] = '8bit';
}
- $ret = wfRunHooks( 'AlternateUserMailer', array( $headers, $to, $from, $subject, $body ) );
+ $ret = Hooks::run( 'AlternateUserMailer', array( $headers, $to, $from, $subject, $body ) );
if ( $ret === false ) {
// the hook implementation will return false to skip regular mail sending
return Status::newGood();
$cachedValue = $wgMemc->get( $cacheKey );
if (
$cachedValue
- && wfRunHooks( 'ValidateExtendedMetadataCache', array( $cachedValue['timestamp'], $file ) )
+ && Hooks::run( 'ValidateExtendedMetadataCache', array( $cachedValue['timestamp'], $file ) )
) {
$extendedMetadata = $cachedValue['data'];
} else {
) {
wfProfileIn( __METHOD__ );
- wfRunHooks( 'GetExtendedMetadata', array(
+ Hooks::run( 'GetExtendedMetadata', array(
&$extendedMetadata,
$file,
$this->getContext(),
*/
static function getMetadataVersion() {
$version = array( '2' ); // core metadata version
- wfRunHooks( 'GetMetadataVersion', array( &$version ) );
+ Hooks::run( 'GetMetadataVersion', array( &$version ) );
return implode( ';', $version );
}
$attribs['srcset'] = Html::srcSet( $this->responsiveUrls );
}
- wfRunHooks( 'ThumbnailBeforeProduceHTML', array( $this, &$attribs, &$linkAttribs ) );
+ Hooks::run( 'ThumbnailBeforeProduceHTML', array( $this, &$attribs, &$linkAttribs ) );
return $this->linkWrap( $linkAttribs, Xml::element( 'img', $attribs ) );
}
# Check if the file is smaller than the maximum image area for thumbnailing
# For historical reasons, hook starts with BitmapHandler
$checkImageAreaHookResult = null;
- wfRunHooks(
+ Hooks::run(
'BitmapHandlerCheckImageArea',
array( $image, &$params, &$checkImageAreaHookResult )
);
# Try a hook. Called "Bitmap" for historical reasons.
/** @var $mto MediaTransformOutput */
$mto = null;
- wfRunHooks( 'BitmapHandlerTransform', array( $this, $image, &$scalerParams, &$mto ) );
+ Hooks::run( 'BitmapHandlerTransform', array( $this, $image, &$scalerParams, &$mto ) );
if ( !is_null( $mto ) ) {
wfDebug( __METHOD__ . ": Hook to BitmapHandlerTransform created an mto\n" );
$scaler = 'hookaborted';
$data = $this->results;
- wfRunHooks( 'XMPGetResults', array( &$data ) );
+ Hooks::run( 'XMPGetResults', array( &$data ) );
if ( isset( $data['xmp-special']['AuthorsPosition'] )
&& is_string( $data['xmp-special']['AuthorsPosition'] )
if ( !self::$ranHooks ) {
// This is for if someone makes a custom metadata extension.
// For example, a medical wiki might want to decode DICOM xmp properties.
- wfRunHooks( 'XMPGetInfo', array( &self::$items ) );
+ Hooks::run( 'XMPGetInfo', array( &self::$items ) );
self::$ranHooks = true; // Only want to do this once.
}
}
$page = null;
- wfRunHooks( 'ArticleFromTitle', array( &$title, &$page, $context ) );
+ Hooks::run( 'ArticleFromTitle', array( &$title, &$page, $context ) );
if ( !$page ) {
switch ( $title->getNamespace() ) {
case NS_FILE:
);
$this->mRevIdFetched = $this->mRevision->getId();
- wfRunHooks( 'ArticleAfterFetchContentObject', array( &$this, &$this->mContentObject ) );
+ Hooks::run( 'ArticleAfterFetchContentObject', array( &$this, &$this->mContentObject ) );
wfProfileOut( __METHOD__ );
while ( !$outputDone && ++$pass ) {
switch ( $pass ) {
case 1:
- wfRunHooks( 'ArticleViewHeader', array( &$this, &$outputDone, &$useParserCache ) );
+ Hooks::run( 'ArticleViewHeader', array( &$this, &$outputDone, &$useParserCache ) );
break;
case 2:
# Early abort if the page doesn't exist
wfDebug( __METHOD__ . ": showing CSS/JS source\n" );
$this->showCssOrJsPage();
$outputDone = true;
- } elseif ( !wfRunHooks( 'ArticleContentViewCustom',
+ } elseif ( !Hooks::run( 'ArticleContentViewCustom',
array( $this->fetchContentObject(), $this->getTitle(), $outputPage ) ) ) {
# Allow extensions do their own custom view for certain pages
if ( isset( $this->mRedirectedFrom ) ) {
// This is an internally redirected page view.
// We'll need a backlink to the source page for navigation.
- if ( wfRunHooks( 'ArticleViewRedirect', array( &$this ) ) ) {
+ if ( Hooks::run( 'ArticleViewRedirect', array( &$this ) ) ) {
$redir = Linker::linkKnown(
$this->mRedirectedFrom,
null,
// Show a footer allowing the user to patrol the shown revision or page if possible
$patrolFooterShown = $this->showPatrolFooter();
- wfRunHooks( 'ArticleViewFooter', array( $this, $patrolFooterShown ) );
+ Hooks::run( 'ArticleViewFooter', array( $this, $patrolFooterShown ) );
}
/**
}
}
- wfRunHooks( 'ShowMissingArticle', array( $this ) );
+ Hooks::run( 'ShowMissingArticle', array( $this ) );
// Give extensions a chance to hide their (unrelated) log entries
$logTypes = array( 'delete', 'move' );
$conds = array( "log_action != 'revision'" );
- wfRunHooks( 'Article::MissingArticleConditions', array( &$conds, $logTypes ) );
+ Hooks::run( 'Article::MissingArticleConditions', array( &$conds, $logTypes ) );
# Show delete and move logs
LogEventsList::showLogExtract( $outputPage, $logTypes, $title, '',
$outputPage->setIndexPolicy( $policy['index'] );
$outputPage->setFollowPolicy( $policy['follow'] );
- $hookResult = wfRunHooks( 'BeforeDisplayNoArticleText', array( $this ) );
+ $hookResult = Hooks::run( 'BeforeDisplayNoArticleText', array( $this ) );
if ( !$hookResult ) {
return;
* @param int $oldid Revision ID of this article revision
*/
public function setOldSubtitle( $oldid = 0 ) {
- if ( !wfRunHooks( 'DisplayOldSubtitle', array( &$this, &$oldid ) ) ) {
+ if ( !Hooks::run( 'DisplayOldSubtitle', array( &$this, &$oldid ) ) ) {
return;
}
}
$outputPage->addWikiMsg( 'confirmdeletetext' );
- wfRunHooks( 'ArticleConfirmDelete', array( $this, $outputPage, &$reason ) );
+ Hooks::run( 'ArticleConfirmDelete', array( $this, $outputPage, &$reason ) );
$user = $this->getContext()->getUser();
$outputPage->addWikiMsg( 'deletedtext', wfEscapeWikiText( $deleted ), $loglink );
- wfRunHooks( 'ArticleDeleteAfterSuccess', array( $this->getTitle(), $outputPage ) );
+ Hooks::run( 'ArticleDeleteAfterSuccess', array( $this->getTitle(), $outputPage ) );
$outputPage->returnToMain( false );
} else {
&& !$this->mRedirectedFrom && !$this->getTitle()->isRedirect();
// Extension may have reason to disable file caching on some pages.
if ( $cacheable ) {
- $cacheable = wfRunHooks( 'IsFileCacheable', array( &$this ) );
+ $cacheable = Hooks::run( 'IsFileCacheable', array( &$this ) );
}
}
return;
}
- if ( !wfRunHooks( 'CategoryPageView', array( &$this ) ) ) {
+ if ( !Hooks::run( 'CategoryPageView', array( &$this ) ) ) {
return;
}
$this->fileLoaded = true;
$this->displayImg = $img = false;
- wfRunHooks( 'ImagePageFindFile', array( $this, &$img, &$this->displayImg ) );
+ Hooks::run( 'ImagePageFindFile', array( $this, &$img, &$this->displayImg ) );
if ( !$img ) { // not set by hook?
$img = wfFindFile( $this->getTitle() );
if ( !$img ) {
# Allow extensions to add something after the image links
$html = '';
- wfRunHooks( 'ImagePageAfterImageLinks', array( $this, &$html ) );
+ Hooks::run( 'ImagePageAfterImageLinks', array( $this, &$html ) );
if ( $html ) {
$out->addHTML( $html );
}
$r[] = '<li><a href="#metadata">' . wfMessage( 'metadata' )->escaped() . '</a></li>';
}
- wfRunHooks( 'ImagePageShowTOC', array( $this, &$r ) );
+ Hooks::run( 'ImagePageShowTOC', array( $this, &$r ) );
return '<ul id="filetoc">' . implode( "\n", $r ) . '</ul>';
}
$filename = wfEscapeWikiText( $this->displayImg->getName() );
$linktext = $filename;
- wfRunHooks( 'ImageOpenShowImageInlineBefore', array( &$this, &$out ) );
+ Hooks::run( 'ImageOpenShowImageInlineBefore', array( &$this, &$out ) );
if ( $this->displayImg->allowInlineDisplay() ) {
# image
}
$rowClass = null;
- wfRunHooks( 'ImagePageFileHistoryLine', array( $this, $file, &$row, &$rowClass ) );
+ Hooks::run( 'ImagePageFileHistoryLine', array( $this, $file, &$row, &$rowClass ) );
$classAttr = $rowClass ? " class='$rowClass'" : '';
return "<tr{$classAttr}>{$row}</tr>\n";
protected function pageData( $dbr, $conditions, $options = array() ) {
$fields = self::selectFields();
- wfRunHooks( 'ArticlePageDataBefore', array( &$this, &$fields ) );
+ Hooks::run( 'ArticlePageDataBefore', array( &$this, &$fields ) );
$row = $dbr->selectRow( 'page', $fields, $conditions, __METHOD__, $options );
- wfRunHooks( 'ArticlePageDataAfter', array( &$this, &$row ) );
+ Hooks::run( 'ArticlePageDataAfter', array( &$this, &$row ) );
return $row;
}
public function doPurge() {
global $wgUseSquid;
- if ( !wfRunHooks( 'ArticlePurge', array( &$this ) ) ) {
+ if ( !Hooks::run( 'ArticlePurge', array( &$this ) ) ) {
return false;
}
$hook_args = array( &$this, &$user, &$content, &$summary,
$flags & EDIT_MINOR, null, null, &$flags, &$status );
- if ( !wfRunHooks( 'PageContentSave', $hook_args )
+ if ( !Hooks::run( 'PageContentSave', $hook_args )
|| !ContentHandler::runLegacyHooks( 'ArticleSave', $hook_args ) ) {
wfDebug( __METHOD__ . ": ArticleSave or ArticleSaveContent hook aborted save!\n" );
$summary = $handler->getAutosummary( $old_content, $content, $flags );
}
- $editInfo = $this->prepareContentForEdit( $content, null, $user, $serialFormat, true );
+ $editInfo = $this->prepareContentForEdit( $content, null, $user, $serialFormat );
$serialized = $editInfo->pst;
/**
return $status;
}
- wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $revision, $baseRevId, $user ) );
+ Hooks::run( 'NewRevisionFromEditComplete', array( $this, $revision, $baseRevId, $user ) );
// Update recentchanges
if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
// Mark as patrolled if the user can do so
// Update the page record with revision data
$this->updateRevisionOn( $dbw, $revision, 0 );
- wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $revision, false, $user ) );
+ Hooks::run( 'NewRevisionFromEditComplete', array( $this, $revision, false, $user ) );
// Update recentchanges
if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
$flags & EDIT_MINOR, null, null, &$flags, $revision );
ContentHandler::runLegacyHooks( 'ArticleInsertComplete', $hook_args );
- wfRunHooks( 'PageContentInsertComplete', $hook_args );
+ Hooks::run( 'PageContentInsertComplete', $hook_args );
}
// Do updates right now unless deferral was requested
$flags & EDIT_MINOR, null, null, &$flags, $revision, &$status, $baseRevId );
ContentHandler::runLegacyHooks( 'ArticleSaveComplete', $hook_args );
- wfRunHooks( 'PageContentSaveComplete', $hook_args );
+ Hooks::run( 'PageContentSaveComplete', $hook_args );
// Promote user to any groups they meet the criteria for
$dbw->onTransactionIdle( function () use ( $user ) {
* @since 1.21
*/
public function prepareContentForEdit(
- Content $content, $revid = null, User $user = null, $serialFormat = null, $useCache = false
+ Content $content, $revid = null, User $user = null, $serialFormat = null, $useCache = true
) {
global $wgContLang, $wgUser;
: false;
$popts = ParserOptions::newFromUserAndLang( $user, $wgContLang );
- wfRunHooks( 'ArticlePrepareTextForEdit', array( $this, $popts ) );
+ Hooks::run( 'ArticlePrepareTextForEdit', array( $this, $popts ) );
$edit = (object)array();
if ( $cachedEdit ) {
DataUpdate::runUpdates( $updates );
}
- wfRunHooks( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) );
+ Hooks::run( 'ArticleEditUpdates', array( &$this, &$editInfo, $options['changed'] ) );
- if ( wfRunHooks( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) {
+ if ( Hooks::run( 'ArticleEditUpdatesDeleteFromRecentchanges', array( &$this ) ) ) {
if ( 0 == mt_rand( 0, 99 ) ) {
// Flush old entries from the `recentchanges` table; we do this on
// random requests so as to avoid an increase in writes for no good reason
wfDebug( __METHOD__ . ": invalid username\n" );
} else {
// Allow extensions to prevent user notification when a new message is added to their talk page
- if ( wfRunHooks( 'ArticleEditUpdateNewTalk', array( &$this, $recipient ) ) ) {
+ if ( Hooks::run( 'ArticleEditUpdateNewTalk', array( &$this, $recipient ) ) ) {
if ( User::isIP( $shortTitle ) ) {
// An anonymous user
$recipient->setNewtalk( true, $revision );
$revision->insertOn( $dbw );
$this->updateRevisionOn( $dbw, $revision );
- wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $revision, false, $user ) );
+ Hooks::run( 'NewRevisionFromEditComplete', array( $this, $revision, false, $user ) );
wfProfileOut( __METHOD__ );
}
$logRelationsField = null;
if ( $id ) { // Protection of existing page
- if ( !wfRunHooks( 'ArticleProtect', array( &$this, &$user, $limit, $reason ) ) ) {
+ if ( !Hooks::run( 'ArticleProtect', array( &$this, &$user, $limit, $reason ) ) ) {
return Status::newGood();
}
__METHOD__
);
- wfRunHooks( 'NewRevisionFromEditComplete', array( $this, $nullRevision, $latest, $user ) );
- wfRunHooks( 'ArticleProtectComplete', array( &$this, &$user, $limit, $reason ) );
+ Hooks::run( 'NewRevisionFromEditComplete', array( $this, $nullRevision, $latest, $user ) );
+ Hooks::run( 'ArticleProtectComplete', array( &$this, &$user, $limit, $reason ) );
} else { // Protection of non-existing page (also known as "title protection")
// Cascade protection is meaningless in this case
$cascade = false;
}
$user = is_null( $user ) ? $wgUser : $user;
- if ( !wfRunHooks( 'ArticleDelete', array( &$this, &$user, &$reason, &$error, &$status ) ) ) {
+ if ( !Hooks::run( 'ArticleDelete', array( &$this, &$user, &$reason, &$error, &$status ) ) ) {
if ( $status->isOK() ) {
// Hook aborted but didn't set a fatal status
$status->fatal( 'delete-hook-aborted' );
$this->doDeleteUpdates( $id, $content );
- wfRunHooks( 'ArticleDeleteComplete', array( &$this, &$user, $reason, $id, $content, $logEntry ) );
+ Hooks::run( 'ArticleDeleteComplete', array( &$this, &$user, $reason, $id, $content, $logEntry ) );
$status->value = $logid;
return $status;
}
$revId = $status->value['revision']->getId();
- wfRunHooks( 'ArticleRollbackComplete', array( $this, $guser, $target, $current ) );
+ Hooks::run( 'ArticleRollbackComplete', array( $this, $guser, $target, $current ) );
$resultDetails = array(
'summary' => $summary,
foreach ( $added as $catName ) {
$cat = Category::newFromName( $catName );
- wfRunHooks( 'CategoryAfterPageAdded', array( $cat, $that ) );
+ Hooks::run( 'CategoryAfterPageAdded', array( $cat, $that ) );
}
foreach ( $deleted as $catName ) {
$cat = Category::newFromName( $catName );
- wfRunHooks( 'CategoryAfterPageRemoved', array( $cat, $that ) );
+ Hooks::run( 'CategoryAfterPageRemoved', array( $cat, $that ) );
}
}
);
$updates = $content->getDeletionUpdates( $this );
}
- wfRunHooks( 'WikiPageDeletionUpdates', array( $this, $content, &$updates ) );
+ Hooks::run( 'WikiPageDeletionUpdates', array( $this, $content, &$updates ) );
return $updates;
}
}
}
if ( count( $linkcolour_ids ) ) {
//pass an array of page_ids to an extension
- wfRunHooks( 'GetLinkColours', array( $linkcolour_ids, &$colours ) );
+ Hooks::run( 'GetLinkColours', array( $linkcolour_ids, &$colours ) );
}
wfProfileOut( __METHOD__ . '-check' );
}
}
}
- wfRunHooks( 'GetLinkColours', array( $linkcolour_ids, &$colours ) );
+ Hooks::run( 'GetLinkColours', array( $linkcolour_ids, &$colours ) );
// rebuild the categories in original order (if there are replacements)
if ( count( $varCategories ) > 0 ) {
$wrappedtext = $wrapper->getWrapped( $text );
$retVal = null;
- $correctedtext = self::clean( $wrappedtext, false, $retVal );
+ list( $correctedtext, $errors ) = self::clean( $wrappedtext, $retVal );
if ( $retVal < 0 ) {
wfDebug( "Possible tidy configuration error!\n" );
return $text . "\n<!-- Tidy was unable to run -->\n";
- } elseif ( is_null( $correctedtext ) ) {
+ } elseif ( $correctedtext === '' && $text !== '' ) {
wfDebug( "Tidy error detected!\n" );
return $text . "\n<!-- Tidy found serious XHTML errors -->\n";
}
*/
public static function checkErrors( $text, &$errorStr = null ) {
$retval = 0;
- $errorStr = self::clean( $text, true, $retval );
+ list( $outputStr, $errorStr ) = self::clean( $text, $retval );
return ( $retval < 0 && $errorStr == '' ) || $retval == 0;
}
/**
* Perform a clean/repair operation
* @param string $text HTML to check
- * @param bool $stderr Whether to read result from STDERR rather than STDOUT
* @param int &$retval Exit code (-1 on internal error)
* @return string|null
*/
- private static function clean( $text, $stderr = false, &$retval = null ) {
+ private static function clean( $text, &$retval = null ) {
global $wgTidyInternal;
if ( $wgTidyInternal ) {
- if ( wfIsHHVM() ) {
- if ( $stderr ) {
- throw new MWException( __METHOD__ . ": error text return from HHVM tidy is not supported" );
- }
- return self::hhvmClean( $text, $retval );
- } else {
- return self::phpClean( $text, $stderr, $retval );
- }
+ return self::internalClean( $text, $retval );
} else {
- return self::externalClean( $text, $stderr, $retval );
+ return self::externalClean( $text, $retval );
}
}
* Also called in OutputHandler.php for full page validation
*
* @param string $text HTML to check
- * @param bool $stderr Whether to read result from STDERR rather than STDOUT
* @param int &$retval Exit code (-1 on internal error)
* @return string|null
*/
- private static function externalClean( $text, $stderr = false, &$retval = null ) {
+ private static function externalClean( $text, &$retval = null ) {
global $wgTidyConf, $wgTidyBin, $wgTidyOpts;
wfProfileIn( __METHOD__ );
- $cleansource = '';
$opts = ' -utf8';
- if ( $stderr ) {
- $descriptorspec = array(
- 0 => array( 'pipe', 'r' ),
- 1 => array( 'file', wfGetNull(), 'a' ),
- 2 => array( 'pipe', 'w' )
- );
- } else {
- $descriptorspec = array(
- 0 => array( 'pipe', 'r' ),
- 1 => array( 'pipe', 'w' ),
- 2 => array( 'file', wfGetNull(), 'a' )
- );
- }
+ $descriptorspec = array(
+ 0 => array( 'pipe', 'r' ),
+ 1 => array( 'pipe', 'w' ),
+ 2 => array( 'pipe', 'w' ),
+ );
- $readpipe = $stderr ? 2 : 1;
+ $outputBuffer = '';
+ $errorBuffer = '';
$pipes = array();
$process = proc_open(
// for tidyParseStdin and tidySaveStdout in console/tidy.c
fwrite( $pipes[0], $text );
fclose( $pipes[0] );
- while ( !feof( $pipes[$readpipe] ) ) {
- $cleansource .= fgets( $pipes[$readpipe], 1024 );
+
+ while ( !feof( $pipes[1] ) ) {
+ $outputBuffer .= fgets( $pipes[1], 1024 );
}
- fclose( $pipes[$readpipe] );
+ fclose( $pipes[1] );
+
+ while ( !feof( $pipes[2] ) ) {
+ $errorBuffer .= fgets( $pipes[2], 1024 );
+ }
+ fclose( $pipes[2] );
+
$retval = proc_close( $process );
} else {
wfWarn( "Unable to start external tidy process" );
$retval = -1;
}
- if ( !$stderr && $cleansource == '' && $text != '' ) {
- // Some kind of error happened, so we couldn't get the corrected text.
- // Just give up; we'll use the source text and append a warning.
- $cleansource = null;
- }
-
wfProfileOut( __METHOD__ );
- return $cleansource;
+ return array( $outputBuffer, $errorBuffer );
}
/**
* saving the overhead of spawning a new process.
*
* @param string $text HTML to check
- * @param bool $stderr Whether to read result from error status instead of output
* @param int &$retval Exit code (-1 on internal error)
* @return string|null
*/
- private static function phpClean( $text, $stderr = false, &$retval = null ) {
+ private static function internalClean( $text, &$retval = null ) {
global $wgTidyConf, $wgDebugTidy;
wfProfileIn( __METHOD__ );
- if ( !class_exists( 'tidy' ) ) {
+ if ( ( !wfIsHHVM() && !class_exists( 'tidy' ) ) ||
+ ( wfIsHHVM() && !function_exists( 'tidy_repair_string' ) )
+ ) {
wfWarn( "Unable to load internal tidy class." );
$retval = -1;
return null;
}
- $tidy = new tidy;
- $tidy->parseString( $text, $wgTidyConf, 'utf8' );
-
- if ( $stderr ) {
- $retval = $tidy->getStatus();
-
- wfProfileOut( __METHOD__ );
- return $tidy->errorBuffer;
- }
-
- $tidy->cleanRepair();
- $retval = $tidy->getStatus();
- if ( $retval == 2 ) {
- // 2 is magic number for fatal error
- // http://www.php.net/manual/en/function.tidy-get-status.php
- $cleansource = null;
+ $outputBuffer = '';
+ $errorBuffer = '';
+
+ if ( wfIsHHVM() ) {
+ // Use the tidy extension for HHVM from
+ // https://github.com/wikimedia/mediawiki-php-tidy
+ //
+ // This currently does not support the object-oriented interface, but
+ // tidy_repair_string() can be used for the most common tasks.
+ $result = tidy_repair_string( $text, $wgTidyConf, 'utf8' );
+ $outputBuffer .= $result;
+ $retval = $result === false ? -1 : 0;
} else {
- $cleansource = tidy_get_output( $tidy );
- if ( $wgDebugTidy && $retval > 0 ) {
- $cleansource .= "<!--\nTidy reports:\n" .
- str_replace( '-->', '-->', $tidy->errorBuffer ) .
- "\n-->";
+ $tidy = new tidy;
+ $tidy->parseString( $text, $wgTidyConf, 'utf8' );
+ $tidy->cleanRepair();
+ $retval = $tidy->getStatus();
+ $outputBuffer .= tidy_get_output( $tidy );
+ if ( $retval > 0 ) {
+ $errorBuffer .= $tidy->errorBuffer;
}
}
- wfProfileOut( __METHOD__ );
- return $cleansource;
- }
-
- /**
- * Use the tidy extension for HHVM from
- * https://github.com/wikimedia/mediawiki-php-tidy
- *
- * This currently does not support the object-oriented interface, but
- * tidy_repair_string() can be used for the most common tasks.
- *
- * @param string $text HTML to check
- * @param int &$retval Exit code (-1 on internal error)
- * @return string|null
- */
- private static function hhvmClean( $text, &$retval ) {
- global $wgTidyConf;
- wfProfileIn( __METHOD__ );
- $cleansource = tidy_repair_string( $text, $wgTidyConf, 'utf8' );
- if ( $cleansource === false ) {
- $cleansource = null;
- $retval = -1;
- } else {
- $retval = 0;
+ if ( $wgDebugTidy && $errorBuffer && $retval > 0 ) {
+ $outputBuffer .= "<!--\nTidy reports:\n" .
+ str_replace( '-->', '-->', $tidy->errorBuffer ) .
+ "\n-->";
}
+
wfProfileOut( __METHOD__ );
- return $cleansource;
+ return array( $outputBuffer, $errorBuffer );
}
}
unset( $tmp );
}
- wfRunHooks( 'ParserCloned', array( $this ) );
+ Hooks::run( 'ParserCloned', array( $this ) );
}
/**
CoreTagHooks::register( $this );
$this->initialiseVariables();
- wfRunHooks( 'ParserFirstCallInit', array( &$this ) );
+ Hooks::run( 'ParserFirstCallInit', array( &$this ) );
wfProfileOut( __METHOD__ );
}
$this->mProfiler = new SectionProfiler();
- wfRunHooks( 'ParserClearState', array( &$this ) );
+ Hooks::run( 'ParserClearState', array( &$this ) );
wfProfileOut( __METHOD__ );
}
$this->mRevisionSize = null;
}
- wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
+ Hooks::run( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
# No more strip!
- wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
+ Hooks::run( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
$text = $this->internalParse( $text );
- wfRunHooks( 'ParserAfterParse', array( &$this, &$text, &$this->mStripState ) );
+ Hooks::run( 'ParserAfterParse', array( &$this, &$text, &$this->mStripState ) );
$text = $this->internalParseHalfParsed( $text, true, $linestart );
$this->mOutput->setLimitReportData( 'limitreport-expensivefunctioncount',
array( $this->mExpensiveFunctionCount, $this->mOptions->getExpensiveParserFunctionLimit() )
);
- wfRunHooks( 'ParserLimitReportPrepare', array( $this, $this->mOutput ) );
+ Hooks::run( 'ParserLimitReportPrepare', array( $this, $this->mOutput ) );
$limitReport = "NewPP limit report\n";
if ( $wgShowHostnames ) {
$limitReport .= 'Parsed by ' . wfHostname() . "\n";
}
foreach ( $this->mOutput->getLimitReportData() as $key => $value ) {
- if ( wfRunHooks( 'ParserLimitReportFormat',
+ if ( Hooks::run( 'ParserLimitReportFormat',
array( $key, &$value, &$limitReport, false, false )
) ) {
$keyMsg = wfMessage( $key )->inLanguage( 'en' )->useDatabase( false );
// Since we're not really outputting HTML, decode the entities and
// then re-encode the things that need hiding inside HTML comments.
$limitReport = htmlspecialchars_decode( $limitReport );
- wfRunHooks( 'ParserLimitReport', array( $this, &$limitReport ) );
+ Hooks::run( 'ParserLimitReport', array( $this, &$limitReport ) );
// Sanitize for comment. Note '‐' in the replacement is U+2010,
// which looks much like the problematic '-'.
*/
public function recursiveTagParse( $text, $frame = false ) {
wfProfileIn( __METHOD__ );
- wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
- wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
+ Hooks::run( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
+ Hooks::run( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
$text = $this->internalParse( $text, false, $frame );
wfProfileOut( __METHOD__ );
return $text;
if ( $revid !== null ) {
$this->mRevisionId = $revid;
}
- wfRunHooks( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
- wfRunHooks( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
+ Hooks::run( 'ParserBeforeStrip', array( &$this, &$text, &$this->mStripState ) );
+ Hooks::run( 'ParserAfterStrip', array( &$this, &$text, &$this->mStripState ) );
$text = $this->replaceVariables( $text, $frame );
$text = $this->mStripState->unstripBoth( $text );
wfProfileOut( __METHOD__ );
$origText = $text;
# Hook to suspend the parser in this state
- if ( !wfRunHooks( 'ParserBeforeInternalParse', array( &$this, &$text, &$this->mStripState ) ) ) {
+ if ( !Hooks::run( 'ParserBeforeInternalParse', array( &$this, &$text, &$this->mStripState ) ) ) {
wfProfileOut( __METHOD__ );
return $text;
}
$text = $this->replaceVariables( $text );
}
- wfRunHooks( 'InternalParseBeforeSanitize', array( &$this, &$text, &$this->mStripState ) );
+ Hooks::run( 'InternalParseBeforeSanitize', array( &$this, &$text, &$this->mStripState ) );
$text = Sanitizer::removeHTMLtags(
$text,
array( &$this, 'attributeStripCallback' ),
false,
array_keys( $this->mTransparentTagHooks )
);
- wfRunHooks( 'InternalParseBeforeLinks', array( &$this, &$text, &$this->mStripState ) );
+ Hooks::run( 'InternalParseBeforeLinks', array( &$this, &$text, &$this->mStripState ) );
# Tables need to come after variable replacement for things to work
# properly; putting them before other transformations should keep
$text = $this->mStripState->unstripNoWiki( $text );
if ( $isMain ) {
- wfRunHooks( 'ParserBeforeTidy', array( &$this, &$text ) );
+ Hooks::run( 'ParserBeforeTidy', array( &$this, &$text ) );
}
$text = $this->replaceTransparentTags( $text );
}
if ( $isMain ) {
- wfRunHooks( 'ParserAfterTidy', array( &$this, &$text ) );
+ Hooks::run( 'ParserAfterTidy', array( &$this, &$text ) );
}
return $text;
'!(?: # Start cases
(<a[ \t\r\n>].*?</a>) | # m[1]: Skip link text
(<.*?>) | # m[2]: Skip stuff inside HTML elements' . "
- (\\b(?i:$prots)$urlChar+) | # m[3]: Free external links" . '
- (?:RFC|PMID)\s+([0-9]+) | # m[4]: RFC or PMID, capture number
- ISBN\s+(\b # m[5]: ISBN, capture number
+ (\b(?i:$prots)$urlChar+) | # m[3]: Free external links" . '
+ \b(?:RFC|PMID)\s+([0-9]+)\b |# m[4]: RFC or PMID, capture number
+ \bISBN\s+( # m[5]: ISBN, capture number
(?: 97[89] [\ \-]? )? # optional 13-digit ISBN prefix
(?: [0-9] [\ \-]? ){9} # 9 digits with opt. delimiters
[0-9Xx] # check digit
- \b)
+ )\b
)!xu', array( &$this, 'magicLinkCallback' ), $text );
wfProfileOut( __METHOD__ );
return $text;
# Give extensions a chance to select the file revision for us
$options = array();
$descQuery = false;
- wfRunHooks( 'BeforeParserFetchFileAndTitle',
+ Hooks::run( 'BeforeParserFetchFileAndTitle',
array( $this, $nt, &$options, &$descQuery ) );
# Fetch and register the file (file title may be different via hooks)
list( $file, $nt ) = $this->fetchFileAndTitle( $nt, $options );
* Some of these require message or data lookups and can be
* expensive to check many times.
*/
- if ( wfRunHooks( 'ParserGetVariableValueVarCache', array( &$this, &$this->mVarCache ) ) ) {
+ if ( Hooks::run( 'ParserGetVariableValueVarCache', array( &$this, &$this->mVarCache ) ) ) {
if ( isset( $this->mVarCache[$index] ) ) {
return $this->mVarCache[$index];
}
}
$ts = wfTimestamp( TS_UNIX, $this->mOptions->getTimestamp() );
- wfRunHooks( 'ParserGetVariableValueTs', array( &$this, &$ts ) );
+ Hooks::run( 'ParserGetVariableValueTs', array( &$this, &$ts ) );
$pageLang = $this->getFunctionLang();
break;
default:
$ret = null;
- wfRunHooks(
+ Hooks::run(
'ParserGetVariableValueSwitch',
array( &$this, &$this->mVarCache, &$index, &$ret, &$frame )
);
for ( $i = 0; $i < 2 && is_object( $title ); $i++ ) {
# Give extensions a chance to select the revision instead
$id = false; # Assume current
- wfRunHooks( 'BeforeParserFetchTemplateAndtitle',
+ Hooks::run( 'BeforeParserFetchTemplateAndtitle',
array( $parser, $title, &$skip, &$id ) );
if ( $skip ) {
* &$sectionContent : ref to the content of the section
* $showEditLinks : boolean describing whether this section has an edit link
*/
- wfRunHooks( 'ParserSectionCreate', array( $this, $i, &$sections[$i], $showEditLink ) );
+ Hooks::run( 'ParserSectionCreate', array( $this, $i, &$sections[$i], $showEditLink ) );
$i++;
}
}
$ig->setAdditionalOptions( $params );
- wfRunHooks( 'BeforeParserrenderImageGallery', array( &$this, &$ig ) );
+ Hooks::run( 'BeforeParserrenderImageGallery', array( &$this, &$ig ) );
$lines = StringUtils::explode( "\n", $text );
foreach ( $lines as $line ) {
# file (which potentially could be of a different type and have different handler).
$options = array();
$descQuery = false;
- wfRunHooks( 'BeforeParserFetchFileAndTitle',
+ Hooks::run( 'BeforeParserFetchFileAndTitle',
array( $this, $title, &$options, &$descQuery ) );
# Don't register it now, as ImageGallery does that later.
$file = $this->fetchFileNoRegister( $title, $options );
$ig->add( $title, $label, $alt, $link, $handlerOptions );
}
$html = $ig->toHTML();
- wfRunHooks( 'AfterParserFetchFileAndTitle', array( $this, $ig, &$html ) );
+ Hooks::run( 'AfterParserFetchFileAndTitle', array( $this, $ig, &$html ) );
wfProfileOut( __METHOD__ );
return $html;
}
# Give extensions a chance to select the file revision for us
$options = array();
$descQuery = false;
- wfRunHooks( 'BeforeParserFetchFileAndTitle',
+ Hooks::run( 'BeforeParserFetchFileAndTitle',
array( $this, $title, &$options, &$descQuery ) );
# Fetch and register the file (file title may be different via hooks)
list( $file, $title ) = $this->fetchFileAndTitle( $title, $options );
$params['frame']['title'] = $this->stripAltText( $caption, $holders );
}
- wfRunHooks( 'ParserMakeImageParams', array( $title, $file, &$params, $this ) );
+ Hooks::run( 'ParserMakeImageParams', array( $title, $file, &$params, $this ) );
# Linker does the rest
$time = isset( $options['time'] ) ? $options['time'] : false;
wfProfileIn( __METHOD__ );
+ // *UPDATE* ParserOptions::matches() if any of this changes as needed
$this->mInterwikiMagic = $wgInterwikiMagic;
$this->mAllowExternalImages = $wgAllowExternalImages;
$this->mAllowExternalImagesFrom = $wgAllowExternalImagesFrom;
wfProfileOut( __METHOD__ );
}
+ /**
+ * Check if these options match that of another options set
+ *
+ * This ignores report limit settings that only affect HTML comments
+ *
+ * @return bool
+ * @since 1.25
+ */
+ public function matches( ParserOptions $other ) {
+ $fields = array_keys( get_class_vars( __CLASS__ ) );
+ $fields = array_diff( $fields, array(
+ 'mEnableLimitReport', // only effects HTML comments
+ 'onAccessCallback', // only used for ParserOutput option tracking
+ ) );
+ foreach ( $fields as $field ) {
+ if ( !is_object( $this->$field ) && $this->$field !== $other->$field ) {
+ return false;
+ }
+ }
+ // Check the object and lazy-loaded options
+ return (
+ $this->mUserLang->getCode() === $other->mUserLang->getCode() &&
+ $this->getDateFormat() === $other->getDateFormat()
+ );
+ }
+
/**
* Registers a callback for tracking which ParserOptions which are used.
* This is a private API with the parser.
// Give a chance for extensions to modify the hash, if they have
// extra options or other effects on the parser cache.
- wfRunHooks( 'PageRenderingHash', array( &$confstr, $this->getUser(), &$forOptions ) );
+ Hooks::run( 'PageRenderingHash', array( &$confstr, $this->getUser(), &$forOptions ) );
// Make it a valid memcached key fragment
$confstr = str_replace( ' ', '_', $confstr );
$this->close(); // set "-total" entry
if ( $this->collateOnly ) {
- return; // already collated as methods exited
+ // already collated as methods exited
+ $this->sortCollated();
+ return;
}
$this->collated = array();
}
$this->collated['-overhead-total']['count'] = $profileCount;
- arsort( $this->collated, SORT_NUMERIC );
+ $this->sortCollated();
+ }
+
+ protected function sortCollated() {
+ uksort( $this->collated, function ( $a, $b ) {
+ $ca = $this->collated[$a]['real'];
+ $cb = $this->collated[$b]['real'];
+ if ( $ca > $cb ) {
+ return -1;
+ } elseif ( $cb > $ca ) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } );
}
/**
*/
protected $sprofiler;
- /**
- * Type of report to send when logData() is called.
- * @var string $logType
- */
- protected $logType;
-
- /**
- * Should profile report sent to in page content be visible?
- * @var bool $visible
- */
- protected $visible;
-
/**
* @param array $params
* @see Xhprof::__construct()
*/
public function __construct( array $params = array() ) {
- $params = array_merge(
- array(
- 'log' => 'text',
- 'visible' => false
- ),
- $params
- );
parent::__construct( $params );
- $this->logType = $params['log'];
- $this->visible = $params['visible'];
$this->xhprof = new Xhprof( $params );
$this->sprofiler = new SectionProfiler();
}
protected $collateOnly = true;
/** @var array Cache of a standard broken collation entry */
protected $errorEntry;
+ /** @var callable Cache of a profile out callback */
+ protected $profileOutCallback;
/**
* @param array $params
public function __construct( array $params = array() ) {
$this->errorEntry = $this->getErrorEntry();
$this->collateOnly = empty( $params['trace'] );
+ $this->profileOutCallback = function ( $profiler, $section ) {
+ $profiler->profileOutInternal( $section );
+ };
}
/**
$this->profileInInternal( $section );
$that = $this;
- return new ScopedCallback( function () use ( $that, $section ) {
- $that->profileOutInternal( $section );
- } );
+ return new ScopedCallback( $this->profileOutCallback, array( $that, $section ) );
}
/**
$query .= '&rcid=' . $attribs['rc_id'];
}
// HACK: We need this hook for WMF's secure server setup
- wfRunHooks( 'IRCLineURL', array( &$url, &$query, $rc ) );
+ Hooks::run( 'IRCLineURL', array( &$url, &$query, $rc ) );
$url .= $query;
}
*/
protected $sources = array();
- /** @var bool */
- protected $hasErrors = false;
+ /**
+ * Errors accumulated during current respond() call.
+ * @var array
+ */
+ protected $errors = array();
/**
* Load information stored in the database about modules.
} catch ( Exception $e ) {
MWExceptionHandler::logException( $e );
wfDebugLog( 'resourceloader', __METHOD__ . ": minification failed: $e" );
- $this->hasErrors = true;
- // Return exception as a comment
- $result = self::formatException( $e );
+ $this->errors[] = self::formatExceptionNoComment( $e );
}
wfProfileOut( __METHOD__ );
// Register core modules
$this->register( include "$IP/resources/Resources.php" );
// Register extension modules
- wfRunHooks( 'ResourceLoaderRegisterModules', array( &$this ) );
+ Hooks::run( 'ResourceLoaderRegisterModules', array( &$this ) );
$this->register( $config->get( 'ResourceModules' ) );
if ( $config->get( 'EnableJavaScriptTest' ) === true ) {
$testModules = array();
$testModules['qunit'] = array();
// Get other test suites (e.g. from extensions)
- wfRunHooks( 'ResourceLoaderTestModules', array( &$testModules, &$this ) );
+ Hooks::run( 'ResourceLoaderTestModules', array( &$testModules, &$this ) );
// Add the testrunner (which configures QUnit) to the dependencies.
// Since it must be ready before any of the test suites are executed.
ob_start();
wfProfileIn( __METHOD__ );
- $errors = '';
// Find out which modules are missing and instantiate the others
$modules = array();
// This is a security issue, see bug 34907.
if ( $module->getGroup() === 'private' ) {
wfDebugLog( 'resourceloader', __METHOD__ . ": request for private module '$name' denied" );
- $this->hasErrors = true;
- // Add exception to the output as a comment
- $errors .= self::makeComment( "Cannot show private module \"$name\"" );
-
+ $this->errors[] = "Cannot show private module \"$name\"";
continue;
}
$modules[$name] = $module;
} catch ( Exception $e ) {
MWExceptionHandler::logException( $e );
wfDebugLog( 'resourceloader', __METHOD__ . ": preloading module info failed: $e" );
- $this->hasErrors = true;
- // Add exception to the output as a comment
- $errors .= self::formatException( $e );
+ $this->errors[] = self::formatExceptionNoComment( $e );
}
wfProfileIn( __METHOD__ . '-getModifiedTime' );
} catch ( Exception $e ) {
MWExceptionHandler::logException( $e );
wfDebugLog( 'resourceloader', __METHOD__ . ": calculating maximum modified time failed: $e" );
- $this->hasErrors = true;
- // Add exception to the output as a comment
- $errors .= self::formatException( $e );
+ $this->errors[] = self::formatExceptionNoComment( $e );
}
}
// Generate a response
$response = $this->makeModuleResponse( $context, $modules, $missing );
- // Prepend comments indicating exceptions
- $response = $errors . $response;
-
// Capture any PHP warnings from the output buffer and append them to the
- // response in a comment if we're in debug mode.
+ // error list if we're in debug mode.
if ( $context->getDebug() && strlen( $warnings = ob_get_contents() ) ) {
- $response = self::makeComment( $warnings ) . $response;
- $this->hasErrors = true;
+ $this->errors[] = $warnings;
}
// Save response to file cache unless there are errors
- if ( isset( $fileCache ) && !$errors && !count( $missing ) ) {
- // Cache single modules...and other requests if there are enough hits
+ if ( isset( $fileCache ) && !$this->errors && !count( $missing ) ) {
+ // Cache single modules and images...and other requests if there are enough hits
if ( ResourceFileCache::useFileCache( $context ) ) {
if ( $fileCache->isCacheWorthy() ) {
$fileCache->saveText( $response );
}
// Send content type and cache related headers
- $this->sendResponseHeaders( $context, $mtime, $this->hasErrors );
+ $this->sendResponseHeaders( $context, $mtime, (bool)$this->errors );
// Remove the output buffer and output the response
ob_end_clean();
+
+ if ( $context->getImageObj() && $this->errors ) {
+ // We can't show both the error messages and the response when it's an image.
+ $errorText = '';
+ foreach ( $this->errors as $error ) {
+ $errorText .= $error . "\n";
+ }
+ $response = $errorText;
+ } elseif ( $this->errors ) {
+ // Prepend comments indicating errors
+ $errorText = '';
+ foreach ( $this->errors as $error ) {
+ $errorText .= self::makeComment( $error );
+ }
+ $response = $errorText . $response;
+ }
+
+ $this->errors = array();
echo $response;
wfProfileOut( __METHOD__ );
* Send content type and last modified headers to the client.
* @param ResourceLoaderContext $context
* @param string $mtime TS_MW timestamp to use for last-modified
- * @param bool $errors Whether there are commented-out errors in the response
+ * @param bool $errors Whether there are errors in the response
* @return void
*/
protected function sendResponseHeaders( ResourceLoaderContext $context, $mtime, $errors ) {
$maxage = $rlMaxage['versioned']['client'];
$smaxage = $rlMaxage['versioned']['server'];
}
- if ( $context->getOnly() === 'styles' ) {
+ if ( $context->getImageObj() ) {
+ // Output different headers if we're outputting textual errors.
+ if ( $errors ) {
+ header( 'Content-Type: text/plain; charset=utf-8' );
+ } else {
+ $context->getImageObj()->sendResponseHeaders( $context );
+ }
+ } elseif ( $context->getOnly() === 'styles' ) {
header( 'Content-Type: text/css; charset=utf-8' );
header( 'Access-Control-Allow-Origin: *' );
} else {
* Handle exception display.
*
* @param Exception $e Exception to be shown to the user
- * @return string Sanitized text that can be returned to the user
+ * @return string Sanitized text in a CSS/JS comment that can be returned to the user
*/
public static function formatException( $e ) {
+ return self::makeComment( self::formatExceptionNoComment( $e ) );
+ }
+
+ /**
+ * Handle exception display.
+ *
+ * @since 1.25
+ * @param Exception $e Exception to be shown to the user
+ * @return string Sanitized text that can be returned to the user
+ */
+ protected static function formatExceptionNoComment( $e ) {
global $wgShowExceptionDetails;
if ( $wgShowExceptionDetails ) {
- return self::makeComment( $e->__toString() );
+ return $e->__toString();
} else {
- return self::makeComment( wfMessage( 'internalerror' )->text() );
+ return wfMessage( 'internalerror' )->text();
}
}
array $modules, array $missing = array()
) {
$out = '';
- $exceptions = '';
$states = array();
if ( !count( $modules ) && !count( $missing ) ) {
wfProfileIn( __METHOD__ );
+ $image = $context->getImageObj();
+ if ( $image ) {
+ $data = $image->getImageData( $context );
+ if ( $data === false ) {
+ $data = '';
+ $this->errors[] = 'Image generation failed';
+ }
+ wfProfileOut( __METHOD__ );
+ return $data;
+ }
+
// Pre-fetch blobs
if ( $context->shouldIncludeMessages() ) {
try {
'resourceloader',
__METHOD__ . ": pre-fetching blobs from MessageBlobStore failed: $e"
);
- $this->hasErrors = true;
- // Add exception to the output as a comment
- $exceptions .= self::formatException( $e );
+ $this->errors[] = self::formatExceptionNoComment( $e );
}
} else {
$blobs = array();
} catch ( Exception $e ) {
MWExceptionHandler::logException( $e );
wfDebugLog( 'resourceloader', __METHOD__ . ": generating module package failed: $e" );
- $this->hasErrors = true;
- // Add exception to the output as a comment
- $exceptions .= self::formatException( $e );
+ $this->errors[] = self::formatExceptionNoComment( $e );
// Respond to client with error-state instead of module implementation
$states[$name] = 'error';
}
} else {
if ( count( $states ) ) {
- $exceptions .= self::makeComment(
- 'Problematic modules: ' . FormatJson::encode( $states, ResourceLoader::inDebugMode() )
- );
+ $this->errors[] = 'Problematic modules: ' .
+ FormatJson::encode( $states, ResourceLoader::inDebugMode() );
}
}
}
wfProfileOut( __METHOD__ );
- return $exceptions . $out;
+ return $out;
}
/* Static Methods */
protected $version;
protected $hash;
protected $raw;
+ protected $image;
+ protected $variant;
+ protected $format;
protected $userObj;
+ protected $imageObj;
/* Methods */
$this->only = $request->getVal( 'only' );
$this->version = $request->getVal( 'version' );
$this->raw = $request->getFuzzyBool( 'raw' );
+ // Image requests
+ $this->image = $request->getVal( 'image' );
+ $this->variant = $request->getVal( 'variant' );
+ $this->format = $request->getVal( 'format' );
$skinnames = Skin::getSkinNames();
// If no skin is specified, or we don't recognize the skin, use the default skin
return $this->raw;
}
+ /**
+ * @return string|null
+ */
+ public function getImage() {
+ return $this->image;
+ }
+
+ /**
+ * @return string|null
+ */
+ public function getVariant() {
+ return $this->variant;
+ }
+
+ /**
+ * @return string|null
+ */
+ public function getFormat() {
+ return $this->format;
+ }
+
+ /**
+ * If this is a request for an image, get the ResourceLoaderImage object.
+ *
+ * @since 1.25
+ * @return ResourceLoaderImage|bool false if a valid object cannot be created
+ */
+ public function getImageObj() {
+ if ( $this->imageObj === null ) {
+ $this->imageObj = false;
+
+ if ( !$this->image ) {
+ return $this->imageObj;
+ }
+
+ $modules = $this->getModules();
+ if ( count( $modules ) !== 1 ) {
+ return $this->imageObj;
+ }
+
+ $module = $this->getResourceLoader()->getModule( $modules[0] );
+ if ( !$module || !$module instanceof ResourceLoaderImageModule ) {
+ return $this->imageObj;
+ }
+
+ $image = $module->getImage( $this->image );
+ if ( !$image ) {
+ return $this->imageObj;
+ }
+
+ $this->imageObj = $image;
+ }
+
+ return $this->imageObj;
+ }
+
/**
* @return bool
*/
if ( !isset( $this->hash ) ) {
$this->hash = implode( '|', array(
$this->getLanguage(), $this->getDirection(), $this->getSkin(), $this->getUser(),
+ $this->getImage(), $this->getVariant(), $this->getFormat(),
$this->getDebug(), $this->getOnly(), $this->getVersion()
) );
}
--- /dev/null
+<?php
+/**
+ * Class encapsulating an image used in a ResourceLoaderImageModule.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Class encapsulating an image used in a ResourceLoaderImageModule.
+ *
+ * @since 1.25
+ */
+class ResourceLoaderImage {
+
+ /**
+ * Map of allowed file extensions to their MIME types.
+ * @var array
+ */
+ protected static $fileTypes = array(
+ 'svg' => 'image/svg+xml',
+ 'png' => 'image/png',
+ 'gif' => 'image/gif',
+ 'jpg' => 'image/jpg',
+ );
+
+ /**
+ * @param string $name Image name
+ * @param string $module Module name
+ * @param string|array $descriptor Path to image file, or array structure containing paths
+ * @param string $basePath Directory to which paths in descriptor refer
+ * @param array $variants
+ * @throws MWException
+ */
+ public function __construct( $name, $module, $descriptor, $basePath, $variants ) {
+ $this->name = $name;
+ $this->module = $module;
+ $this->descriptor = $descriptor;
+ $this->basePath = $basePath;
+ $this->variants = $variants;
+
+ // Ensure that all files have common extension.
+ $extensions = array();
+ $descriptor = (array)$descriptor;
+ array_walk_recursive( $descriptor, function ( $path ) use ( &$extensions ) {
+ $extensions[] = pathinfo( $path, PATHINFO_EXTENSION );
+ } );
+ $extensions = array_unique( $extensions );
+ if ( count( $extensions ) !== 1 ) {
+ throw new MWException( 'Image type for various images differs.' );
+ }
+ $ext = $extensions[0];
+ if ( !isset( self::$fileTypes[$ext] ) ) {
+ throw new MWException( 'Invalid image type; svg, png, gif or jpg required.' );
+ }
+ $this->extension = $ext;
+ }
+
+ /**
+ * Get name of this image.
+ *
+ * @return string
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ * Get name of the module this image belongs to.
+ *
+ * @return string
+ */
+ public function getModule() {
+ return $this->module;
+ }
+
+ /**
+ * Get the list of variants this image can be converted to.
+ *
+ * @return string[]
+ */
+ public function getVariants() {
+ return array_keys( $this->variants );
+ }
+
+ /**
+ * Get the path to image file for given context.
+ *
+ * @param ResourceLoaderContext $context Any context
+ * @return string
+ */
+ protected function getPath( ResourceLoaderContext $context ) {
+ $desc = $this->descriptor;
+ if ( is_string( $desc ) ) {
+ return $this->basePath . '/' . $desc;
+ } elseif ( isset( $desc['lang'][ $context->getLanguage() ] ) ) {
+ return $this->basePath . '/' . $desc['lang'][ $context->getLanguage() ];
+ } elseif ( isset( $desc[ $context->getDirection() ] ) ) {
+ return $this->basePath . '/' . $desc[ $context->getDirection() ];
+ } else {
+ return $this->basePath . '/' . $desc['default'];
+ }
+ }
+
+ /**
+ * Get the extension of the image.
+ *
+ * @param string $format Format to get the extension for, 'original' or 'rasterized'
+ * @return string Extension without leading dot, e.g. 'png'
+ */
+ public function getExtension( $format = 'original' ) {
+ if ( $format === 'rasterized' && $this->extension === 'svg' ) {
+ return 'png';
+ } else {
+ return $this->extension;
+ }
+ }
+
+ /**
+ * Get the MIME type of the image.
+ *
+ * @param string $format Format to get the MIME type for, 'original' or 'rasterized'
+ * @return string
+ */
+ public function getMimeType( $format = 'original' ) {
+ $ext = $this->getExtension( $format );
+ return self::$fileTypes[$ext];
+ }
+
+ /**
+ * Get the load.php URL that will produce this image.
+ *
+ * @param ResourceLoaderContext $context Any context
+ * @param string $script URL to load.php
+ * @param string|null $variant Variant to get the URL for
+ * @param string $format Format to get the URL for, 'original' or 'rasterized'
+ * @return string
+ */
+ public function getUrl( ResourceLoaderContext $context, $script, $variant, $format ) {
+ $query = array(
+ 'modules' => $this->getModule(),
+ 'image' => $this->getName(),
+ 'variant' => $variant,
+ 'format' => $format,
+ 'lang' => $context->getLanguage(),
+ 'version' => $context->getVersion(),
+ );
+
+ return wfExpandUrl( wfAppendQuery( $script, $query ), PROTO_RELATIVE );
+ }
+
+ /**
+ * Get the data: URI that will produce this image.
+ *
+ * @param ResourceLoaderContext $context Any context
+ * @param string|null $variant Variant to get the URI for
+ * @param string $format Format to get the URI for, 'original' or 'rasterized'
+ * @return string
+ */
+ public function getDataUri( ResourceLoaderContext $context, $variant, $format ) {
+ $type = $this->getMimeType( $format );
+ $contents = $this->getImageData( $context, $variant, $format );
+ return CSSMin::encodeStringAsDataURI( $contents, $type );
+ }
+
+ /**
+ * Get actual image data for this image. This can be saved to a file or sent to the browser to
+ * produce the converted image.
+ *
+ * Call getExtension() or getMimeType() with the same $format argument to learn what file type the
+ * returned data uses.
+ *
+ * @param ResourceLoaderContext $context Image context, or any context of $variant and $format
+ * given.
+ * @param string|null $variant Variant to get the data for. Optional, if given, overrides the data
+ * from $context.
+ * @param string $format Format to get the data for, 'original' or 'rasterized'. Optional, if
+ * given, overrides the data from $context.
+ * @return string|false Possibly binary image data, or false on failure
+ */
+ public function getImageData( ResourceLoaderContext $context, $variant = false, $format = false ) {
+ if ( $variant === false ) {
+ $variant = $context->getVariant();
+ }
+ if ( $format === false ) {
+ $format = $context->getFormat();
+ }
+
+ if ( $this->getExtension() !== 'svg' ) {
+ return file_get_contents( $this->getPath( $context ) );
+ }
+
+ if ( $variant && isset( $this->variants[$variant] ) ) {
+ $data = $this->variantize( $this->variants[$variant], $context );
+ } else {
+ $data = file_get_contents( $this->getPath( $context ) );
+ }
+
+ if ( $format === 'rasterized' ) {
+ $data = $this->rasterize( $data );
+ }
+
+ return $data;
+ }
+
+ /**
+ * Send response headers (using the header() function) that are necessary to correctly serve the
+ * image data for this image, as returned by getImageData().
+ *
+ * Note that the headers are independent of the language or image variant.
+ *
+ * @param ResourceLoaderContext $context Image context
+ */
+ public function sendResponseHeaders( ResourceLoaderContext $context ) {
+ $format = $context->getFormat();
+ $mime = $this->getMimeType( $format );
+ $filename = $this->getName() . '.' . $this->getExtension( $format );
+
+ header( 'Content-Type: ' . $mime );
+ header( 'Content-Disposition: ' .
+ FileBackend::makeContentDisposition( 'inline', $filename ) );
+ }
+
+ /**
+ * Convert this image, which is assumed to be SVG, to given variant.
+ *
+ * @param array $variantConf Array with a 'color' key, its value will be used as fill color
+ * @param ResourceLoaderContext $context Image context
+ * @return string New SVG file data
+ */
+ protected function variantize( $variantConf, ResourceLoaderContext $context ) {
+ $dom = new DomDocument;
+ $dom->load( $this->getPath( $context ) );
+ $root = $dom->documentElement;
+ $wrapper = $dom->createElement( 'g' );
+ while ( $root->firstChild ) {
+ $wrapper->appendChild( $root->firstChild );
+ }
+ $root->appendChild( $wrapper );
+ $wrapper->setAttribute( 'fill', $variantConf['color'] );
+ return $dom->saveXml();
+ }
+
+ /**
+ * Massage the SVG image data for converters which doesn't understand some path data syntax.
+ *
+ * This is necessary for rsvg and ImageMagick when compiled with rsvg support.
+ * Upstream bug is https://bugzilla.gnome.org/show_bug.cgi?id=620923, fixed 2014-11-10, so
+ * this will be needed for a while. (T76852)
+ *
+ * @param string $svg SVG image data
+ * @return string Massaged SVG image data
+ */
+ protected function massageSvgPathdata( $svg ) {
+ $dom = new DomDocument;
+ $dom->loadXml( $svg );
+ foreach ( $dom->getElementsByTagName( 'path' ) as $node ) {
+ $pathData = $node->getAttribute( 'd' );
+ // Make sure there is at least one space between numbers, and that leading zero is not omitted.
+ // rsvg has issues with syntax like "M-1-2" and "M.445.483" and especially "M-.445-.483".
+ $pathData = preg_replace( '/(-?)(\d*\.\d+|\d+)/', ' ${1}0$2 ', $pathData );
+ // Strip unnecessary leading zeroes for prettiness, not strictly necessary
+ $pathData = preg_replace( '/([ -])0(\d)/', '$1$2', $pathData );
+ $node->setAttribute( 'd', $pathData );
+ }
+ return $dom->saveXml();
+ }
+
+ /**
+ * Convert passed image data, which is assumed to be SVG, to PNG.
+ *
+ * @param string $svg SVG image data
+ * @return string|bool PNG image data, or false on failure
+ */
+ protected function rasterize( $svg ) {
+ // This code should be factored out to a separate method on SvgHandler, or perhaps a separate
+ // class, with a separate set of configuration settings.
+ //
+ // This is a distinct use case from regular SVG rasterization:
+ // * we can skip many sanity and security checks (as the images come from a trusted source,
+ // rather than from the user)
+ // * we need to provide extra options to some converters to achieve acceptable quality for very
+ // small images, which might cause performance issues in the general case
+ // * we need to directly pass image data to the converter instead of a file path
+ //
+ // See https://phabricator.wikimedia.org/T76473#801446 for examples of what happens with the
+ // default settings.
+ //
+ // For now, we special-case rsvg (used in WMF production) and do a messy workaround for other
+ // converters.
+
+ global $wgSVGConverter, $wgSVGConverterPath;
+
+ $svg = $this->massageSvgPathdata( $svg );
+
+ if ( $wgSVGConverter === 'rsvg' ) {
+ $command = 'rsvg-convert'; // Should be just 'rsvg'? T76476
+ if ( $wgSVGConverterPath ) {
+ $command = wfEscapeShellArg( "$wgSVGConverterPath/" ) . $command;
+ }
+
+ $process = proc_open(
+ $command,
+ array( 0 => array( 'pipe', 'r' ), 1 => array( 'pipe', 'w' ) ),
+ $pipes
+ );
+
+ if ( is_resource( $process ) ) {
+ fwrite( $pipes[0], $svg );
+ fclose( $pipes[0] );
+ $png = stream_get_contents( $pipes[1] );
+ fclose( $pipes[1] );
+ proc_close( $process );
+
+ return $png ?: false;
+ }
+ return false;
+
+ } else {
+ // Write input to and read output from a temporary file
+ $tempFilenameSvg = tempnam( wfTempDir(), 'ResourceLoaderImage' );
+ $tempFilenamePng = tempnam( wfTempDir(), 'ResourceLoaderImage' );
+
+ file_put_contents( $tempFilenameSvg, $svg );
+
+ $metadata = SVGMetadataExtractor::getMetadata( $tempFilenameSvg );
+ if ( !isset( $metadata['width'] ) || !isset( $metadata['height'] ) ) {
+ return false;
+ }
+
+ $handler = new SvgHandler;
+ $handler->rasterize( $tempFilenameSvg, $tempFilenamePng, $metadata['width'], $metadata['height'] );
+
+ $png = file_get_contents( $tempFilenamePng );
+
+ unlink( $tempFilenameSvg );
+ unlink( $tempFilenamePng );
+
+ return $png ?: false;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Resource loader module for generated and embedded images.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @author Trevor Parscal
+ */
+
+/**
+ * Resource loader module for generated and embedded images.
+ *
+ * @since 1.25
+ */
+class ResourceLoaderImageModule extends ResourceLoaderModule {
+
+ /**
+ * Local base path, see __construct()
+ * @var string
+ */
+ protected $localBasePath = '';
+
+ protected $origin = self::ORIGIN_CORE_SITEWIDE;
+
+ protected $images = array();
+ protected $variants = array();
+ protected $prefix = array();
+ protected $targets = array( 'desktop', 'mobile' );
+
+ /**
+ * Constructs a new module from an options array.
+ *
+ * @param array $options List of options; if not given or empty, an empty module will be
+ * constructed
+ * @param string $localBasePath Base path to prepend to all local paths in $options. Defaults
+ * to $IP
+ *
+ * Below is a description for the $options array:
+ * @par Construction options:
+ * @code
+ * array(
+ * // Base path to prepend to all local paths in $options. Defaults to $IP
+ * 'localBasePath' => [base path],
+ * // CSS class prefix to use in all style rules
+ * 'prefix' => [CSS class prefix],
+ * // List of variants that may be used for the image files
+ * 'variants' => array(
+ * // ([image type] is a string, used in generated CSS class names and to match variants to images)
+ * [image type] => array(
+ * [variant name] => array(
+ * 'color' => [color string, e.g. '#ffff00'],
+ * 'global' => [boolean, if true, this variant is available for all images of this type],
+ * ),
+ * )
+ * ),
+ * // List of image files and their options
+ * 'images' => array(
+ * [image type] => array(
+ * [file path string],
+ * [file path string] => array(
+ * 'name' => [image name string, defaults to file name],
+ * 'variants' => [array of variant name strings, variants available for this image],
+ * ),
+ * )
+ * ),
+ * )
+ * @endcode
+ * @throws MWException
+ */
+ public function __construct( $options = array(), $localBasePath = null ) {
+ $this->localBasePath = self::extractLocalBasePath( $options, $localBasePath );
+
+ if ( !isset( $options['prefix'] ) || !$options['prefix'] ) {
+ throw new MWException(
+ "Required 'prefix' option not given or empty."
+ );
+ }
+
+ foreach ( $options as $member => $option ) {
+ switch ( $member ) {
+ case 'images':
+ if ( !is_array( $option ) ) {
+ throw new MWException(
+ "Invalid collated file path list error. '$option' given, array expected."
+ );
+ }
+ foreach ( $option as $key => $value ) {
+ if ( !is_string( $key ) ) {
+ throw new MWException(
+ "Invalid collated file path list key error. '$key' given, string expected."
+ );
+ }
+ $this->{$member}[$key] = (array)$value;
+ }
+ break;
+
+ case 'variants':
+ if ( !is_array( $option ) ) {
+ throw new MWException(
+ "Invalid variant list error. '$option' given, array expected."
+ );
+ }
+ $this->{$member} = $option;
+ break;
+
+ case 'prefix':
+ $this->{$member} = (string)$option;
+ break;
+ }
+ }
+ }
+
+ /**
+ * Get CSS class prefix used by this module.
+ * @return string
+ */
+ public function getPrefix() {
+ return $this->prefix;
+ }
+
+ /**
+ * Get a ResourceLoaderImage object for given image.
+ * @param string $name Image name
+ * @return ResourceLoaderImage|null
+ */
+ public function getImage( $name ) {
+ $images = $this->getImages();
+ return isset( $images[$name] ) ? $images[$name] : null;
+ }
+
+ /**
+ * Get ResourceLoaderImage objects for all images.
+ * @return ResourceLoaderImage[] Array keyed by image name
+ */
+ public function getImages() {
+ if ( !isset( $this->imageObjects ) ) {
+ $this->imageObjects = array();
+
+ foreach ( $this->images as $type => $list ) {
+ foreach ( $list as $name => $options ) {
+ $imageDesc = is_string( $options ) ? $options : $options['image'];
+
+ $allowedVariants = array_merge(
+ isset( $options['variants'] ) ? $options['variants'] : array(),
+ $this->getGlobalVariants( $type )
+ );
+ $variantConfig = array_intersect_key(
+ $this->variants[$type],
+ array_fill_keys( $allowedVariants, true )
+ );
+
+ $image = new ResourceLoaderImage( $name, $this->getName(), $imageDesc, $this->localBasePath, $variantConfig );
+ $this->imageObjects[ $image->getName() ] = $image;
+ }
+ }
+ }
+
+ return $this->imageObjects;
+ }
+
+ /**
+ * Get list of variants in this module that are 'global' for given type of images, i.e., available
+ * for every image of given type regardless of image options.
+ * @param string $type Image type
+ * @return string[]
+ */
+ public function getGlobalVariants( $type ) {
+ if ( !isset( $this->globalVariants[$type] ) ) {
+ $this->globalVariants[$type] = array();
+
+ foreach ( $this->variants[$type] as $name => $config ) {
+ if ( isset( $config['global'] ) && $config['global'] ) {
+ $this->globalVariants[$type][] = $name;
+ }
+ }
+ }
+
+ return $this->globalVariants[$type];
+ }
+
+ /**
+ * Get the type of given image.
+ * @param string $imageName Image name
+ * @return string
+ */
+ public function getImageType( $imageName ) {
+ foreach ( $this->images as $type => $list ) {
+ foreach ( $list as $key => $value ) {
+ $file = is_int( $key ) ? $value : $key;
+ $options = is_array( $value ) ? $value : array();
+ $name = isset( $options['name'] ) ? $options['name'] : pathinfo( $file, PATHINFO_FILENAME );
+ if ( $name === $imageName ) {
+ return $type;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param ResourceLoaderContext $context
+ * @return array
+ */
+ public function getStyles( ResourceLoaderContext $context ) {
+ // Build CSS rules
+ $rules = array();
+ $script = $context->getResourceLoader()->getLoadScript( $this->getSource() );
+ $prefix = $this->getPrefix();
+
+ foreach ( $this->getImages() as $name => $image ) {
+ $type = $this->getImageType( $name );
+
+ $declarations = $this->getCssDeclarations(
+ $image->getDataUri( $context, null, 'original' ),
+ $image->getUrl( $context, $script, null, 'rasterized' )
+ );
+ $declarations = implode( "\n\t", $declarations );
+ $rules[] = ".$prefix-$type-$name {\n\t$declarations\n}";
+
+ // TODO: Get variant configurations from $context->getSkin()
+ foreach ( $image->getVariants() as $variant ) {
+ $declarations = $this->getCssDeclarations(
+ $image->getDataUri( $context, $variant, 'original' ),
+ $image->getUrl( $context, $script, $variant, 'rasterized' )
+ );
+ $declarations = implode( "\n\t", $declarations );
+ $rules[] = ".$prefix-$type-$name-$variant {\n\t$declarations\n}";
+ }
+ }
+
+ $style = implode( "\n", $rules );
+ if ( $this->getFlip( $context ) ) {
+ $style = CSSJanus::transform( $style, true, false );
+ }
+ return array( 'all' => $style );
+ }
+
+ /**
+ * @param string $primary Primary URI
+ * @param string $fallback Fallback URI
+ * @return string[] CSS declarations to use given URIs as background-image
+ */
+ protected function getCssDeclarations( $primary, $fallback ) {
+ // SVG support using a transparent gradient to guarantee cross-browser
+ // compatibility (browsers able to understand gradient syntax support also SVG).
+ // http://pauginer.tumblr.com/post/36614680636/invisible-gradient-technique
+ return array(
+ "background-image: url($fallback);",
+ "background-image: -webkit-linear-gradient(transparent, transparent), url($primary);",
+ "background-image: linear-gradient(transparent, transparent), url($primary);",
+ );
+ }
+
+ /**
+ * @return bool
+ */
+ public function supportsURLLoading() {
+ return false;
+ }
+
+ /**
+ * Extract a local base path from module definition information.
+ *
+ * @param array $options Module definition
+ * @param string $localBasePath Path to use if not provided in module definition. Defaults
+ * to $IP
+ * @return string Local base path
+ */
+ public static function extractLocalBasePath( $options, $localBasePath = null ) {
+ global $IP;
+
+ if ( $localBasePath === null ) {
+ $localBasePath = $IP;
+ }
+
+ if ( array_key_exists( 'localBasePath', $options ) ) {
+ $localBasePath = (string)$options['localBasePath'];
+ }
+
+ return $localBasePath;
+ }
+}
/**
* @param $context ResourceLoaderContext
- * @return boolean
+ * @return bool
*/
public function isKnownEmpty( ResourceLoaderContext $context ) {
// Regardless of whether the files are specified, we always
'wgResourceLoaderStorageEnabled' => $conf->get( 'ResourceLoaderStorageEnabled' ),
);
- wfRunHooks( 'ResourceLoaderGetConfigVars', array( &$vars ) );
+ Hooks::run( 'ResourceLoaderGetConfigVars', array( &$vars ) );
$this->configVars[$hash] = $vars;
return $this->configVars[$hash];
}
/**
- * @param DatabaseBase $db
+ * @param IDatabase $db
* @return mixed
*/
public function doQuery( $db ) {
}
/**
- * @param DatabaseBase $db
+ * @param IDatabase $db
* @return mixed
*/
public function doQuery( $db ) {
}
/**
- * @param DatabaseBase $db
+ * @param IDatabase $db
* @return mixed
*/
public function doQuery( $db ) {
}
/**
- * @param DatabaseBase $db
+ * @param IDatabase $db
* @return mixed
*/
public function doQuery( $db ) {
}
/**
- * @param DatabaseBase $db
+ * @param IDatabase $db
* @return mixed
*/
public function doQuery( $db ) {
public function doPostCommitUpdates() {
$this->title->purgeSquid();
// Extensions that require referencing previous revisions may need this
- wfRunHooks( 'ArticleRevisionVisibilitySet', array( &$this->title ) );
+ Hooks::run( 'ArticleRevisionVisibilitySet', array( &$this->title ) );
return Status::newGood();
}
}
* @param string $name Username
* @param int $userId User id
* @param string $op Operator '|' or '&'
- * @param null|DatabaseBase $dbw If you happen to have one lying around
+ * @param null|IDatabase $dbw If you happen to have one lying around
* @return bool
*/
private static function setUsernameBitfields( $name, $userId, $op, $dbw ) {
if ( !$userId || ( $op !== '|' && $op !== '&' ) ) {
return false; // sanity check
}
- if ( !$dbw instanceof DatabaseBase ) {
+ if ( !$dbw instanceof IDatabase ) {
$dbw = wfGetDB( DB_MASTER );
}
public static function getNearMatch( $searchterm ) {
$title = self::getNearMatchInternal( $searchterm );
- wfRunHooks( 'SearchGetNearMatchComplete', array( $searchterm, &$title ) );
+ Hooks::run( 'SearchGetNearMatchComplete', array( $searchterm, &$title ) );
return $title;
}
}
$titleResult = null;
- if ( !wfRunHooks( 'SearchGetNearMatchBefore', array( $allSearchTerms, &$titleResult ) ) ) {
+ if ( !Hooks::run( 'SearchGetNearMatchBefore', array( $allSearchTerms, &$titleResult ) ) ) {
return $titleResult;
}
return $title;
}
- if ( !wfRunHooks( 'SearchAfterNoDirectMatch', array( $term, &$title ) ) ) {
+ if ( !Hooks::run( 'SearchAfterNoDirectMatch', array( $term, &$title ) ) ) {
return $title;
}
// Give hooks a chance at better match variants
$title = null;
- if ( !wfRunHooks( 'SearchGetNearMatch', array( $term, &$title ) ) ) {
+ if ( !Hooks::run( 'SearchGetNearMatch', array( $term, &$title ) ) ) {
return $title;
}
}
}
}
- wfRunHooks( 'SearchableNamespaces', array( &$arr ) );
+ Hooks::run( 'SearchableNamespaces', array( &$arr ) );
return $arr;
}
$this->mTitle = $title;
if ( !is_null( $this->mTitle ) ) {
$id = false;
- wfRunHooks( 'SearchResultInitFromTitle', array( $title, &$id ) );
+ Hooks::run( 'SearchResultInitFromTitle', array( $title, &$id ) );
$this->mRevision = Revision::newFromTitle(
$this->mTitle, $id, Revision::READ_NORMAL );
if ( $this->mTitle->getNamespace() === NS_FILE ) {
$toolbox['info']['id'] = 't-info';
}
- wfRunHooks( 'BaseTemplateToolbox', array( &$this, &$toolbox ) );
+ Hooks::run( 'BaseTemplateToolbox', array( &$this, &$toolbox ) );
wfProfileOut( __METHOD__ );
return $toolbox;
}
ob_start();
// We pass an extra 'true' at the end so extensions using BaseTemplateToolbox
// can abort and avoid outputting double toolbox links
- wfRunHooks( 'SkinTemplateToolboxEnd', array( &$this, true ) );
+ Hooks::run( 'SkinTemplateToolboxEnd', array( &$this, true ) );
$hookContents = ob_get_contents();
ob_end_clean();
if ( !trim( $hookContents ) ) {
*/
protected function renderAfterPortlet( $name ) {
$content = '';
- wfRunHooks( 'BaseTemplateAfterPortlet', array( $this, $name, &$content ) );
+ Hooks::run( 'BaseTemplateAfterPortlet', array( $this, $name, &$content ) );
if ( $content !== '' ) {
echo "<div class='after-portlet after-portlet-$name'>$content</div>";
$titles[] = $title->getTalkPage();
}
- wfRunHooks( 'SkinPreloadExistence', array( &$titles, $this ) );
+ Hooks::run( 'SkinPreloadExistence', array( &$titles, $this ) );
if ( count( $titles ) ) {
$lb = new LinkBatch( $titles );
protected function afterContentHook() {
$data = '';
- if ( wfRunHooks( 'SkinAfterContent', array( &$data, $this ) ) ) {
+ if ( Hooks::run( 'SkinAfterContent', array( &$data, $this ) ) ) {
// adding just some spaces shouldn't toggle the output
// of the whole <div/>, so we use trim() here
if ( trim( $data ) != '' ) {
// OutputPage::getBottomScripts() which takes a Skin param. This should be cleaned
// up at some point
$bottomScriptText = $this->getOutput()->getBottomScripts();
- wfRunHooks( 'SkinAfterBottomScripts', array( $this, &$bottomScriptText ) );
+ Hooks::run( 'SkinAfterBottomScripts', array( $this, &$bottomScriptText ) );
return $bottomScriptText;
}
$out = $this->getOutput();
$subpages = '';
- if ( !wfRunHooks( 'SkinSubPageSubtitle', array( &$subpages, $this, $out ) ) ) {
+ if ( !Hooks::run( 'SkinSubPageSubtitle', array( &$subpages, $this, $out ) ) ) {
return $subpages;
}
// @todo Remove deprecated $forContent param from hook handlers and then remove here.
$forContent = true;
- wfRunHooks(
+ Hooks::run(
'SkinCopyrightFooter',
array( $this->getTitle(), $type, &$msg, &$link, &$forContent )
);
$url = htmlspecialchars( "$wgResourceBasePath/resources/assets/poweredby_mediawiki_88x31.png" );
$text = '<a href="//www.mediawiki.org/"><img src="' . $url
. '" height="31" width="88" alt="Powered by MediaWiki" /></a>';
- wfRunHooks( 'SkinGetPoweredBy', array( &$text, $this ) );
+ Hooks::run( 'SkinGetPoweredBy', array( &$text, $this ) );
return $text;
}
if ( $wgEnableSidebarCache ) {
$cachedsidebar = $wgMemc->get( $key );
if ( $cachedsidebar ) {
- wfRunHooks( 'SidebarBeforeOutput', array( $this, &$cachedsidebar ) );
+ Hooks::run( 'SidebarBeforeOutput', array( $this, &$cachedsidebar ) );
wfProfileOut( __METHOD__ );
return $cachedsidebar;
$bar = array();
$this->addToSidebar( $bar, 'sidebar' );
- wfRunHooks( 'SkinBuildSidebar', array( $this, &$bar ) );
+ Hooks::run( 'SkinBuildSidebar', array( $this, &$bar ) );
if ( $wgEnableSidebarCache ) {
$wgMemc->set( $key, $bar, $wgSidebarCacheExpiry );
}
- wfRunHooks( 'SidebarBeforeOutput', array( $this, &$bar ) );
+ Hooks::run( 'SidebarBeforeOutput', array( $this, &$bar ) );
wfProfileOut( __METHOD__ );
return $bar;
$out = $this->getOutput();
// Allow extensions to disable or modify the new messages alert
- if ( !wfRunHooks( 'GetNewMessagesAlert', array( &$newMessagesAlert, $newtalks, $user, $out ) ) ) {
+ if ( !Hooks::run( 'GetNewMessagesAlert', array( &$newMessagesAlert, $newtalks, $user, $out ) ) ) {
return '';
}
if ( $newMessagesAlert ) {
wfProfileIn( __METHOD__ );
$siteNotice = '';
- if ( wfRunHooks( 'SiteNoticeBefore', array( &$siteNotice, $this ) ) ) {
+ if ( Hooks::run( 'SiteNoticeBefore', array( &$siteNotice, $this ) ) ) {
if ( is_object( $this->getUser() ) && $this->getUser()->isLoggedIn() ) {
$siteNotice = $this->getCachedNotice( 'sitenotice' );
} else {
}
}
- wfRunHooks( 'SiteNoticeAfter', array( &$siteNotice, $this ) );
+ Hooks::run( 'SiteNoticeAfter', array( &$siteNotice, $this ) );
wfProfileOut( __METHOD__ );
return $siteNotice;
}
. '<span class="mw-editsection-bracket">]</span>'
. '</span>';
- wfRunHooks( 'DoEditSectionLink', array( $this, $nt, $section, $tooltip, &$result, $lang ) );
+ Hooks::run( 'DoEditSectionLink', array( $this, $nt, $section, $tooltip, &$result, $lang ) );
return $result;
}
'lang' => $ilInterwikiCodeBCP47,
'hreflang' => $ilInterwikiCodeBCP47,
);
- wfRunHooks(
+ Hooks::run(
'SkinTemplateGetLanguageLink',
array( &$languageLink, $languageLinkTitle, $this->getTitle(), $this->getOutput() )
);
$tpl->set( 'reporttime', wfReportTime() );
// original version by hansm
- if ( !wfRunHooks( 'SkinTemplateOutputPageBeforeExec', array( &$this, &$tpl ) ) ) {
+ if ( !Hooks::run( 'SkinTemplateOutputPageBeforeExec', array( &$this, &$tpl ) ) ) {
wfDebug( __METHOD__ . ": Hook SkinTemplateOutputPageBeforeExec broke outputPage execution!\n" );
}
$personal_urls['login'] = $login_url;
}
- wfRunHooks( 'PersonalUrls', array( &$personal_urls, &$title, $this ) );
+ Hooks::run( 'PersonalUrls', array( &$personal_urls, &$title, $this ) );
wfProfileOut( __METHOD__ );
return $personal_urls;
}
}
$result = array();
- if ( !wfRunHooks( 'SkinTemplateTabAction', array( &$this,
+ if ( !Hooks::run( 'SkinTemplateTabAction', array( &$this,
$title, $message, $selected, $checkEdit,
&$classes, &$query, &$text, &$result ) ) ) {
return $result;
$userCanRead = $title->quickUserCan( 'read', $user );
$preventActiveTabs = false;
- wfRunHooks( 'SkinTemplatePreventOtherActiveTabs', array( &$this, &$preventActiveTabs ) );
+ Hooks::run( 'SkinTemplatePreventOtherActiveTabs', array( &$this, &$preventActiveTabs ) );
// Checks if page is some kind of content
if ( $title->canExist() ) {
}
}
- wfRunHooks( 'SkinTemplateNavigation', array( &$this, &$content_navigation ) );
+ Hooks::run( 'SkinTemplateNavigation', array( &$this, &$content_navigation ) );
if ( $userCanRead && !$wgDisableLangConversion ) {
$pageLang = $title->getPageLanguage();
'context' => 'subject'
);
- wfRunHooks( 'SkinTemplateNavigation::SpecialPage',
+ Hooks::run( 'SkinTemplateNavigation::SpecialPage',
array( &$this, &$content_navigation ) );
}
// Equiv to SkinTemplateContentActions
- wfRunHooks( 'SkinTemplateNavigation::Universal', array( &$this, &$content_navigation ) );
+ Hooks::run( 'SkinTemplateNavigation::Universal', array( &$this, &$content_navigation ) );
// Setup xml ids and tooltip info
foreach ( $content_navigation as $section => &$links ) {
}
// Use the copy of revision ID in case this undocumented, shady hook tries to mess with internals
- wfRunHooks( 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink',
+ Hooks::run( 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink',
array( &$this, &$nav_urls, &$revid, &$revid ) );
}
protected function getCustomFilters() {
if ( $this->customFilters === null ) {
$this->customFilters = array();
- wfRunHooks( 'ChangesListSpecialPageFilters', array( $this, &$this->customFilters ) );
+ Hooks::run( 'ChangesListSpecialPageFilters', array( $this, &$this->customFilters ) );
}
return $this->customFilters;
}
protected function runMainQueryHook( &$tables, &$fields, &$conds, &$query_options, &$join_conds, $opts ) {
- return wfRunHooks(
+ return Hooks::run(
'ChangesListSpecialPageQuery',
array( $this->getName(), &$tables, &$fields, &$conds, &$query_options, &$join_conds, $opts )
);
}
/**
- * Return a DatabaseBase object for reading
+ * Return a IDatabase object for reading
*
- * @return DatabaseBase
+ * @return IDatabase
*/
protected function getDB() {
return wfGetDB( DB_SLAVE );
$this->alterForm( $form );
// Give hooks a chance to alter the form, adding extra fields or text etc
- wfRunHooks( 'SpecialPageBeforeFormDisplay', array( $this->getName(), &$form ) );
+ Hooks::run( 'SpecialPageBeforeFormDisplay', array( $this->getName(), &$form ) );
return $form;
}
*
* @param OutputPage $out OutputPage to print to
* @param Skin $skin User skin to use [unused]
- * @param DatabaseBase $dbr (read) connection to use
+ * @param IDatabase $dbr (read) connection to use
* @param ResultWrapper $res Result pointer
* @param int $num Number of available result rows
* @param int $offset Paging offset
* like page existence and information for stub color and redirect hints.
* This should be done for live data and cached data.
*
- * @param DatabaseBase $db
+ * @param IDatabase $db
* @param ResultWrapper $res
*/
public function preprocessResults( $db, $res ) {
array( 'UnusedtemplatesPage', 'Unusedtemplates' ),
array( 'WithoutInterwikiPage', 'Withoutinterwiki' ),
);
- wfRunHooks( 'wgQueryPages', array( &$qp ) );
+ Hooks::run( 'wgQueryPages', array( &$qp ) );
}
return $qp;
/**
* Get a DB connection to be used for slow recache queries
- * @return DatabaseBase
+ * @return IDatabase
*/
function getRecacheDB() {
return wfGetDB( DB_SLAVE, array( $this->getName(), 'QueryPage::recache', 'vslow' ) );
*
* @param OutputPage $out OutputPage to print to
* @param Skin $skin User skin to use
- * @param DatabaseBase $dbr Database (read) connection to use
+ * @param IDatabase $dbr Database (read) connection to use
* @param ResultWrapper $res Result pointer
* @param int $num Number of available result rows
* @param int $offset Paging offset
/**
* Do any necessary preprocessing of the result object.
- * @param DatabaseBase $db
+ * @param IDatabase $db
* @param ResultWrapper $res
*/
function preprocessResults( $db, $res ) {
'ctype', 'maxage', 'smaxage',
);
- wfRunHooks( "RedirectSpecialArticleRedirectParams", array( &$redirectParams ) );
+ Hooks::run( "RedirectSpecialArticleRedirectParams", array( &$redirectParams ) );
$this->mAllowedRedirectParams = $redirectParams;
}
}
* @param SpecialPage $this
* @param string|null $subPage
*/
- wfRunHooks( 'SpecialPageBeforeExecute', array( $this, $subPage ) );
+ Hooks::run( 'SpecialPageBeforeExecute', array( $this, $subPage ) );
$this->beforeExecute( $subPage );
$this->execute( $subPage );
* @param SpecialPage $this
* @param string|null $subPage
*/
- wfRunHooks( 'SpecialPageAfterExecute', array( $this, $subPage ) );
+ Hooks::run( 'SpecialPageAfterExecute', array( $this, $subPage ) );
}
/**
// Run hooks
// This hook can be used to remove undesired built-in special pages
- wfRunHooks( 'SpecialPage_initList', array( &self::$list ) );
+ Hooks::run( 'SpecialPage_initList', array( &self::$list ) );
wfProfileOut( __METHOD__ );
}
/**
* Cache page existence for performance
- * @param DatabaseBase $db
+ * @param IDatabase $db
* @param ResultWrapper $res
*/
function preprocessResults( $db, $res ) {
* @note This will only be run if the page is cached (ie $wgMiserMode = true)
* unless forceExistenceCheck() is true.
* @since 1.24
- * @return boolean
+ * @return bool
*/
protected function existenceCheck( Title $title ) {
return $title->isKnown();
$this->maybeAlterFormDefaults( $a );
// Allow extensions to add more fields
- wfRunHooks( 'SpecialBlockModifyFormFields', array( $this, &$a ) );
+ Hooks::run( 'SpecialBlockModifyFormFields', array( $this, &$a ) );
return $a;
}
$otherBlockMessages = array();
if ( $this->target !== null ) {
# Get other blocks, i.e. from GlobalBlocking or TorBlock extension
- wfRunHooks( 'OtherBlockLogLink', array( &$otherBlockMessages, $this->target ) );
+ Hooks::run( 'OtherBlockLogLink', array( &$otherBlockMessages, $this->target ) );
if ( count( $otherBlockMessages ) ) {
$s = Html::rawElement(
$block->mHideName = $data['HideUser'];
$reason = array( 'hookaborted' );
- if ( !wfRunHooks( 'BlockIp', array( &$block, &$performer, &$reason ) ) ) {
+ if ( !Hooks::run( 'BlockIp', array( &$block, &$performer, &$reason ) ) ) {
return $reason;
}
$logaction = 'block';
}
- wfRunHooks( 'BlockIpComplete', array( $block, $performer ) );
+ Hooks::run( 'BlockIpComplete', array( $block, $performer ) );
# Set *_deleted fields if requested
if ( $data['HideUser'] ) {
# Check for other blocks, i.e. global/tor blocks
$otherBlockLink = array();
- wfRunHooks( 'OtherBlockLogLink', array( &$otherBlockLink, $this->target ) );
+ Hooks::run( 'OtherBlockLogLink', array( &$otherBlockLink, $this->target ) );
$out = $this->getOutput();
# Hook to allow extensions to insert additional HTML,
# e.g. for API-interacting plugins and so on
- wfRunHooks( 'BookInformation', array( $this->isbn, $this->getOutput() ) );
+ Hooks::run( 'BookInformation', array( $this->isbn, $this->getOutput() ) );
# Check for a local page such as Project:Book_sources and use that if available
$page = $this->msg( 'booksources' )->inContentLanguage()->text();
return $status;
}
- wfRunHooks( 'PrefsEmailAudit', array( $user, $oldaddr, $newaddr ) );
+ Hooks::run( 'PrefsEmailAudit', array( $user, $oldaddr, $newaddr ) );
$user->saveSettings();
}
$extraFields = array();
- wfRunHooks( 'ChangePasswordForm', array( &$extraFields ) );
+ Hooks::run( 'ChangePasswordForm', array( &$extraFields ) );
foreach ( $extraFields as $extra ) {
list( $name, $label, $type, $default ) = $extra;
$fields[$name] = array(
}
if ( $newpass !== $retype ) {
- wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) );
+ Hooks::run( 'PrefsPasswordAudit', array( $user, $newpass, 'badretype' ) );
throw new PasswordError( $this->msg( 'badretype' )->text() );
}
// @todo Make these separate messages, since the message is written for both cases
if ( !$user->checkTemporaryPassword( $oldpass ) && !$user->checkPassword( $oldpass ) ) {
- wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
+ Hooks::run( 'PrefsPasswordAudit', array( $user, $newpass, 'wrongpassword' ) );
throw new PasswordError( $this->msg( 'resetpass-wrong-oldpass' )->text() );
}
// Do AbortChangePassword after checking mOldpass, so we don't leak information
// by possibly aborting a new password before verifying the old password.
$abortMsg = 'resetpass-abort-generic';
- if ( !wfRunHooks( 'AbortChangePassword', array( $user, $oldpass, $newpass, &$abortMsg ) ) ) {
- wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'abortreset' ) );
+ if ( !Hooks::run( 'AbortChangePassword', array( $user, $oldpass, $newpass, &$abortMsg ) ) ) {
+ Hooks::run( 'PrefsPasswordAudit', array( $user, $newpass, 'abortreset' ) );
throw new PasswordError( $this->msg( $abortMsg )->text() );
}
try {
$user->setPassword( $newpass );
- wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
+ Hooks::run( 'PrefsPasswordAudit', array( $user, $newpass, 'success' ) );
} catch ( PasswordError $e ) {
- wfRunHooks( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
+ Hooks::run( 'PrefsPasswordAudit', array( $user, $newpass, 'error' ) );
throw new PasswordError( $e->getMessage() );
}
// Add RSS/atom links
$this->addFeedLinks( $feedParams );
- if ( wfRunHooks( 'SpecialContributionsBeforeMainOutput', array( $id, $userObj, $this ) ) ) {
+ if ( Hooks::run( 'SpecialContributionsBeforeMainOutput', array( $id, $userObj, $this ) ) ) {
if ( !$this->including() ) {
$out->addHTML( $this->getForm() );
}
);
}
- wfRunHooks( 'ContributionsToolLinks', array( $id, $userpage, &$tools ) );
+ Hooks::run( 'ContributionsToolLinks', array( $id, $userpage, &$tools ) );
return $tools;
}
$msgs = array(
'diff',
'hist',
- 'newarticle',
'pipe-separator',
- 'rev-delundel',
- 'rollbacklink',
'uctop'
);
$data = array( $this->mDb->select(
$tables, $fields, $conds, $fname, $options, $join_conds
) );
- wfRunHooks(
+ Hooks::run(
'ContribsPager::reallyDoQuery',
array( &$data, $pager, $offset, $limit, $descending )
);
$this->tagFilter
);
- wfRunHooks( 'ContribsPager::getQueryInfo', array( &$this, &$queryInfo ) );
+ Hooks::run( 'ContribsPager::getQueryInfo', array( &$this, &$queryInfo ) );
return $queryInfo;
}
}
// Let extensions add data
- wfRunHooks( 'ContributionsLineEnding', array( $this, &$ret, $row, &$classes ) );
+ Hooks::run( 'ContributionsLineEnding', array( $this, &$ret, $row, &$classes ) );
if ( $classes === array() && $ret === '' ) {
wfDebug( "Dropping Special:Contribution row that could not be formatted\n" );
);
}
- wfRunHooks( 'ContributionsToolLinks', array( $id, $nt, &$tools ) );
+ Hooks::run( 'ContributionsToolLinks', array( $id, $nt, &$tools ) );
$links = $this->getLanguage()->pipeList( $tools );
);
$page = WikiPage::factory( $title );
- wfRunHooks( 'UnwatchArticleComplete', array( $this->getUser(), &$page ) );
+ Hooks::run( 'UnwatchArticleComplete', array( $this->getUser(), &$page ) );
}
}
}
// Allow subscribers to manipulate the list of watched pages (or use it
// to preload lots of details at once)
$watchlistInfo = $this->getWatchlistInfo();
- wfRunHooks(
+ Hooks::run(
'WatchlistEditorBeforeFormRender',
array( &$watchlistInfo )
);
);
}
- wfRunHooks(
+ Hooks::run(
'WatchlistEditorBuildRemoveLine',
array( &$tools, $title, $title->isRedirect(), $this->getSkin(), &$link )
);
$form->setWrapperLegendMsg( 'email-legend' );
$form->loadData();
- if ( !wfRunHooks( 'EmailUserForm', array( &$form ) ) ) {
+ if ( !Hooks::run( 'EmailUserForm', array( &$form ) ) ) {
return;
}
$hookErr = false;
- wfRunHooks( 'UserCanSendEmail', array( &$user, &$hookErr ) );
- wfRunHooks( 'EmailUserPermissionsErrors', array( $user, $editToken, &$hookErr ) );
+ Hooks::run( 'UserCanSendEmail', array( &$user, &$hookErr ) );
+ Hooks::run( 'EmailUserPermissionsErrors', array( $user, $editToken, &$hookErr ) );
if ( $hookErr ) {
return $hookErr;
$from->name, $to->name )->inContentLanguage()->text();
$error = '';
- if ( !wfRunHooks( 'EmailUser', array( &$to, &$from, &$subject, &$text, &$error ) ) ) {
+ if ( !Hooks::run( 'EmailUser', array( &$to, &$from, &$subject, &$text, &$error ) ) ) {
return $error;
}
if ( $data['CCMe'] && $to != $from ) {
$cc_subject = $context->msg( 'emailccsubject' )->rawParams(
$target->getName(), $subject )->text();
- wfRunHooks( 'EmailUserCC', array( &$from, &$from, &$cc_subject, &$text ) );
+ Hooks::run( 'EmailUserCC', array( &$from, &$from, &$cc_subject, &$text ) );
$ccStatus = UserMailer::send( $from, $from, $cc_subject, $text );
$status->merge( $ccStatus );
}
- wfRunHooks( 'EmailUserComplete', array( $to, $from, $subject, $text ) );
+ Hooks::run( 'EmailUserComplete', array( $to, $from, $subject, $text ) );
return $status;
}
$page = WikiPage::factory( $title );
# Update page record
$page->updateRevisionOn( $dbw, $nullRevision );
- wfRunHooks(
+ Hooks::run(
'NewRevisionFromEditComplete',
array( $page, $nullRevision, $latest, $this->getUser() )
);
'conds' => $conds
);
- wfRunHooks( 'SpecialListusersQueryInfo', array( $this, &$query ) );
+ Hooks::run( 'SpecialListusersQueryInfo', array( $this, &$query ) );
return $query;
}
' ' . $this->msg( 'listusers-blocked', $userName )->escaped() :
'';
- wfRunHooks( 'SpecialListusersFormatRow', array( &$item, $row ) );
+ Hooks::run( 'SpecialListusersFormatRow', array( &$item, $row ) );
return Html::rawElement( 'li', array(), "{$item}{$edits}{$created}{$blocked}" );
}
);
$out .= '<br />';
- wfRunHooks( 'SpecialListusersHeaderForm', array( $this, &$out ) );
+ Hooks::run( 'SpecialListusersHeaderForm', array( $this, &$out ) );
# Submit button and form bottom
$out .= Html::hidden( 'limit', $this->mLimit );
$out .= Xml::submitButton( $this->msg( 'allpagessubmit' )->text() );
- wfRunHooks( 'SpecialListusersHeader', array( $this, &$out ) );
+ Hooks::run( 'SpecialListusersHeader', array( $this, &$out ) );
$out .= Xml::closeElement( 'fieldset' ) .
Xml::closeElement( 'form' );
if ( $this->requestedUser != '' ) {
$query['username'] = $this->requestedUser;
}
- wfRunHooks( 'SpecialListusersDefaultQuery', array( $this, &$query ) );
+ Hooks::run( 'SpecialListusersDefaultQuery', array( $this, &$query ) );
return $query;
}
}
} else {
// Allow extensions to add relations to their search types
- wfRunHooks( 'SpecialLogAddLogSearchRelations', array( $opts->getValue( 'type' ), $this->getRequest(), &$qc ) );
+ Hooks::run( 'SpecialLogAddLogSearchRelations', array( $opts->getValue( 'type' ), $this->getRequest(), &$qc ) );
}
# Some log types are only for a 'User:' title but we might have been given
# only the username instead of the full title 'User:username'. This part try
# to lookup for a user by that name and eventually fix user input. See bug 1697.
- wfRunHooks( 'GetLogTypesOnUser', array( &$this->typeOnUser ) );
+ Hooks::run( 'GetLogTypesOnUser', array( &$this->typeOnUser ) );
if ( in_array( $opts->getValue( 'type' ), $this->typeOnUser ) ) {
# ok we have a type of log which expect a user title.
$target = Title::newFromText( $opts->getValue( 'page' ) );
);
// Allow extensions to modify the query
- wfRunHooks( 'LonelyPagesQuery', array( &$tables, &$conds, &$joinConds ) );
+ Hooks::run( 'LonelyPagesQuery', array( &$tables, &$conds, &$joinConds ) );
return array(
'tables' => $tables,
$targetTitle->getPrefixedText(), $destTitle->getPrefixedText() )->numParams(
$count )->text() );
- wfRunHooks( 'ArticleMergeComplete', array( $targetTitle, $destTitle ) );
+ Hooks::run( 'ArticleMergeComplete', array( $targetTitle, $destTitle ) );
return true;
}
$newLink )->params( $oldText, $newText )->parseAsBlock() );
$out->addWikiMsg( $msgName );
- wfRunHooks( 'SpecialMovepageAfterMove', array( &$this, &$ot, &$nt ) );
+ Hooks::run( 'SpecialMovepageAfterMove', array( &$this, &$ot, &$nt ) );
# Now we move extra pages we've been asked to move: subpages and talk
# pages. First, if the old page or the new page is a talk page, we
$opts->add( 'invert', false );
$this->customFilters = array();
- wfRunHooks( 'SpecialNewPagesFilters', array( $this, &$this->customFilters ) );
+ Hooks::run( 'SpecialNewPagesFilters', array( $this, &$this->customFilters ) );
foreach ( $this->customFilters as $key => $params ) {
$opts->add( $key, $params['default'] );
}
);
$join_conds = array( 'page' => array( 'INNER JOIN', 'page_id=rc_cur_id' ) );
- wfRunHooks( 'SpecialNewpagesConditions',
+ Hooks::run( 'SpecialNewpagesConditions',
array( &$this, $this->opts, &$conds, &$tables, &$fields, &$join_conds ) );
$options = array();
public function alterForm( HTMLForm $form ) {
$form->setDisplayFormat( 'vform' );
$form->setWrapperLegend( false );
- wfRunHooks( 'LanguageSelector', array( $this->getOutput(), 'mw-languageselector' ) );
+ Hooks::run( 'LanguageSelector', array( $this->getOutput(), 'mw-languageselector' ) );
}
/**
// Check for hooks (captcha etc), and allow them to modify the users list
$error = array();
- if ( !wfRunHooks( 'SpecialPasswordResetOnSubmit', array( &$users, $data, &$error ) ) ) {
+ if ( !Hooks::run( 'SpecialPasswordResetOnSubmit', array( &$users, $data, &$error ) ) ) {
return array( $error );
}
return array( 'badipaddress' );
}
$caller = $this->getUser();
- wfRunHooks( 'User::mailPasswordInternal', array( &$caller, &$ip, &$firstUser ) );
+ Hooks::run( 'User::mailPasswordInternal', array( &$caller, &$ip, &$firstUser ) );
$username = $caller->getName();
$msg = IP::isValid( $username )
? 'passwordreset-emailtext-ip'
$randstr = wfRandom();
$title = null;
- if ( !wfRunHooks(
+ if ( !Hooks::run(
'SpecialRandomGetRandomTitle',
array( &$randstr, &$this->isRedir, &$this->namespaces, &$this->extra, &$title )
) ) {
protected function getCustomFilters() {
if ( $this->customFilters === null ) {
$this->customFilters = parent::getCustomFilters();
- wfRunHooks( 'SpecialRecentChangesFilters', array( $this, &$this->customFilters ), '1.23' );
+ Hooks::run( 'SpecialRecentChangesFilters', array( $this, &$this->customFilters ), '1.23' );
}
return $this->customFilters;
protected function runMainQueryHook( &$tables, &$fields, &$conds, &$query_options, &$join_conds, $opts ) {
return parent::runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds, $opts )
- && wfRunHooks(
+ && Hooks::run(
'SpecialRecentChangesQuery',
array( &$conds, &$tables, &$join_conds, $opts, &$query_options, &$fields ),
'1.23'
// Don't fire the hook for subclasses. (Or should we?)
if ( $this->getName() === 'Recentchanges' ) {
- wfRunHooks( 'SpecialRecentChangesPanel', array( &$extraOpts, $opts ) );
+ Hooks::run( 'SpecialRecentChangesPanel', array( &$extraOpts, $opts ) );
}
return $extraOpts;
$tokens = array(
array( 'preference' => 'watchlisttoken', 'label-message' => 'resettokens-watchlist-token' ),
);
- wfRunHooks( 'SpecialResetTokensTokens', array( &$tokens ) );
+ Hooks::run( 'SpecialResetTokensTokens', array( &$tokens ) );
$hiddenPrefs = $this->getConfig()->get( 'HiddenPrefs' );
$tokens = array_filter( $tokens, function ( $tok ) use ( $hiddenPrefs ) {
# No match, generate an edit URL
$title = Title::newFromText( $term );
if ( !is_null( $title ) ) {
- wfRunHooks( 'SpecialSearchNogomatch', array( &$title ) );
+ Hooks::run( 'SpecialSearchNogomatch', array( &$title ) );
}
$this->showResults( $term );
}
$search->prefix = $this->mPrefix;
$term = $search->transformSearchTerm( $term );
- wfRunHooks( 'SpecialSearchSetupEngine', array( $this, $this->profile, $search ) );
+ Hooks::run( 'SpecialSearchSetupEngine', array( $this, $this->profile, $search ) );
$this->setupPage( $term );
. $this->msg( 'search-suggest' )->rawParams( $suggestLink )->text() . '</div>';
}
- if ( !wfRunHooks( 'SpecialSearchResultsPrepend', array( $this, $out, $term ) ) ) {
+ if ( !Hooks::run( 'SpecialSearchResultsPrepend', array( $this, $out, $term ) ) ) {
# Hook requested termination
return;
}
);
}
}
- wfRunHooks( 'SpecialSearchResults', array( $term, &$titleMatches, &$textMatches ) );
+ Hooks::run( 'SpecialSearchResults', array( $term, &$titleMatches, &$textMatches ) );
$out->parserOptions()->setEditSection( false );
if ( $titleMatches ) {
wfEscapeWikiText( $title->getPrefixedText() ),
Message::numParam( $num )
);
- wfRunHooks( 'SpecialSearchCreateLink', array( $title, &$params ) );
+ Hooks::run( 'SpecialSearchCreateLink', array( $title, &$params ) );
// Extensions using the hook might still return an empty $messageName
if ( $messageName ) {
$link_t = clone $title;
- wfRunHooks( 'ShowSearchHitTitle',
+ Hooks::run( 'ShowSearchHitTitle',
array( &$link_t, &$titleSnippet, $result, $terms, $this ) );
$link = Linker::linkKnown(
$html = null;
$score = '';
- if ( wfRunHooks( 'ShowSearchHit', array(
+ if ( Hooks::run( 'ShowSearchHit', array(
$this, $result, $terms,
&$link, &$redirect, &$section, &$extract,
&$score, &$size, &$date, &$related,
$showSections = array( 'namespaceTables' => $namespaceTables );
- wfRunHooks( 'SpecialSearchPowerBox', array( &$showSections, $term, $opts ) );
+ Hooks::run( 'SpecialSearchPowerBox', array( &$showSections, $term, $opts ) );
$hidden = '';
foreach ( $opts as $key => $value ) {
)
);
- wfRunHooks( 'SpecialSearchProfiles', array( &$profiles ) );
+ Hooks::run( 'SpecialSearchProfiles', array( &$profiles ) );
foreach ( $profiles as &$data ) {
if ( !is_array( $data['namespaces'] ) ) {
$out .= $this->powerSearchBox( $term, $opts );
} else {
$form = '';
- wfRunHooks( 'SpecialSearchProfileForm', array( $this, &$form, $this->profile, $term, $opts ) );
+ Hooks::run( 'SpecialSearchProfileForm', array( $this, &$form, $this->profile, $term, $opts ) );
$out .= $form;
}
# Statistic - other
$extraStats = array();
- if ( wfRunHooks( 'SpecialStatsAddExtra', array( &$extraStats ) ) ) {
+ if ( Hooks::run( 'SpecialStatsAddExtra', array( &$extraStats ) ) ) {
$text .= $this->getOtherStats( $extraStats );
}
$logEntry->setTarget( $this->title );
$logEntry->setComment( $reason );
- wfRunHooks( 'ArticleUndeleteLogEntry', array( $this, &$logEntry, $user ) );
+ Hooks::run( 'ArticleUndeleteLogEntry', array( $this, &$logEntry, $user ) );
$logid = $logEntry->insert();
$logEntry->publish( $logid );
$revision->insertOn( $dbw );
$restored++;
- wfRunHooks( 'ArticleRevisionUndeleted', array( &$this->title, $revision, $row->ar_page_id ) );
+ Hooks::run( 'ArticleRevisionUndeleted', array( &$this->title, $revision, $row->ar_page_id ) );
}
# Now that it's safely stored, take it out of the archive
$dbw->delete( 'archive',
);
}
- wfRunHooks( 'ArticleUndelete', array( &$this->title, $created, $comment, $oldPageId ) );
+ Hooks::run( 'ArticleUndelete', array( &$this->title, $created, $comment, $oldPageId ) );
if ( $this->title->getNamespace() == NS_FILE ) {
$update = new HTMLCacheUpdate( $this->title, 'imagelinks' );
}
$archive = new PageArchive( $this->mTargetObj, $this->getConfig() );
- if ( !wfRunHooks( 'UndeleteForm::showRevision', array( &$archive, $this->mTargetObj ) ) ) {
+ if ( !Hooks::run( 'UndeleteForm::showRevision', array( &$archive, $this->mTargetObj ) ) ) {
return;
}
$rev = $archive->getRevision( $timestamp );
$out->addHTML( $this->msg( 'undelete-revision' )->rawParams( $link )->params(
$time )->rawParams( $userLink )->params( $d, $t )->parse() . '</div>' );
- if ( !wfRunHooks( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) ) ) {
+ if ( !Hooks::run( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) ) ) {
return;
}
);
$archive = new PageArchive( $this->mTargetObj, $this->getConfig() );
- wfRunHooks( 'UndeleteForm::showHistory', array( &$archive, $this->mTargetObj ) );
+ Hooks::run( 'UndeleteForm::showHistory', array( &$archive, $this->mTargetObj ) );
/*
$text = $archive->getLastRevisionText();
if( is_null( $text ) ) {
$out = $this->getOutput();
$archive = new PageArchive( $this->mTargetObj, $this->getConfig() );
- wfRunHooks( 'UndeleteForm::undelete', array( &$archive, $this->mTargetObj ) );
+ Hooks::run( 'UndeleteForm::undelete', array( &$archive, $this->mTargetObj ) );
$ok = $archive->undelete(
$this->mTargetTimestamp,
$this->mComment,
if ( is_array( $ok ) ) {
if ( $ok[1] ) { // Undeleted file count
- wfRunHooks( 'FileUndeleteComplete', array(
+ Hooks::run( 'FileUndeleteComplete', array(
$this->mTargetObj, $this->mFileVersions,
$this->getUser(), $this->mComment ) );
}
$this->processUpload();
} else {
# Backwards compatibility hook
- if ( !wfRunHooks( 'UploadForm:initial', array( &$this ) ) ) {
+ if ( !Hooks::run( 'UploadForm:initial', array( &$this ) ) ) {
wfDebug( "Hook 'UploadForm:initial' broke output of the upload form\n" );
return;
return;
}
- if ( !wfRunHooks( 'UploadForm:BeforeProcessing', array( &$this ) ) ) {
+ if ( !Hooks::run( 'UploadForm:BeforeProcessing', array( &$this ) ) ) {
wfDebug( "Hook 'UploadForm:BeforeProcessing' broke processing the file.\n" );
// This code path is deprecated. If you want to break upload processing
// do so by hooking into the appropriate hooks in UploadBase::verifyUpload
// Success, redirect to description page
$this->mUploadSuccessful = true;
- wfRunHooks( 'SpecialUploadComplete', array( &$this ) );
+ Hooks::run( 'SpecialUploadComplete', array( &$this ) );
$this->getOutput()->redirect( $this->mLocalFile->getTitle()->getFullURL() );
}
+ $this->getDescriptionSection()
+ $this->getOptionsSection();
- wfRunHooks( 'UploadFormInitDescriptor', array( &$descriptor ) );
+ Hooks::run( 'UploadFormInitDescriptor', array( &$descriptor ) );
parent::__construct( $descriptor, $context, 'upload' );
# Add a link to edit MediaWik:Licenses
'checked' => $selectedSourceType == 'url',
);
}
- wfRunHooks( 'UploadFormSourceDescriptors', array( &$descriptor, &$radio, $selectedSourceType ) );
+ Hooks::run( 'UploadFormSourceDescriptors', array( &$descriptor, &$radio, $selectedSourceType ) );
$descriptor['Extensions'] = array(
'type' => 'info',
static $messages = null;
if ( !$messages ) {
$messages = self::$validErrorMessages;
- wfRunHooks( 'LoginFormValidErrorMessages', array( &$messages ) );
+ Hooks::run( 'LoginFormValidErrorMessages', array( &$messages ) );
}
return $messages;
$u->saveSettings();
$result = $this->mailPasswordInternal( $u, false, 'createaccount-title', 'createaccount-text' );
- wfRunHooks( 'AddNewAccount', array( $u, true ) );
+ Hooks::run( 'AddNewAccount', array( $u, true ) );
$u->addNewUserLogEntry( 'byemail', $this->mReason );
$out = $this->getOutput();
// which is needed or the personal links will be
// wrong.
$this->getContext()->setUser( $u );
- wfRunHooks( 'AddNewAccount', array( $u, false ) );
+ Hooks::run( 'AddNewAccount', array( $u, false ) );
$u->addNewUserLogEntry( 'create' );
if ( $this->hasSessionCookie() ) {
$this->successfulCreation();
$out->setPageTitle( $this->msg( 'accountcreated' ) );
$out->addWikiMsg( 'accountcreatedtext', $u->getName() );
$out->addReturnTo( $this->getPageTitle() );
- wfRunHooks( 'AddNewAccount', array( $u, false ) );
+ Hooks::run( 'AddNewAccount', array( $u, false ) );
$u->addNewUserLogEntry( 'create2', $this->mReason );
}
$abortError = '';
$abortStatus = null;
- if ( !wfRunHooks( 'AbortNewAccount', array( $u, &$abortError, &$abortStatus ) ) ) {
+ if ( !Hooks::run( 'AbortNewAccount', array( $u, &$abortError, &$abortStatus ) ) ) {
// Hook point to add extra creation throttles and blocks
wfDebug( "LoginForm::addNewAccountInternal: a hook blocked creation\n" );
if ( $abortStatus === null ) {
}
// Hook point to check for exempt from account creation throttle
- if ( !wfRunHooks( 'ExemptFromAccountCreationThrottle', array( $ip ) ) ) {
+ if ( !Hooks::run( 'ExemptFromAccountCreationThrottle', array( $ip ) ) ) {
wfDebug( "LoginForm::exemptFromAccountCreationThrottle: a hook " .
"allowed account creation w/o throttle\n" );
} else {
// Give extensions a way to indicate the username has been updated,
// rather than telling the user the account doesn't exist.
- if ( !wfRunHooks( 'LoginUserMigrated', array( $u, &$msg ) ) ) {
+ if ( !Hooks::run( 'LoginUserMigrated', array( $u, &$msg ) ) ) {
$this->mAbortLoginErrorMsg = $msg;
return self::USER_MIGRATED;
}
// Give general extensions, such as a captcha, a chance to abort logins
$abort = self::ABORTED;
$msg = null;
- if ( !wfRunHooks( 'AbortLogin', array( $u, $this->mPassword, &$abort, &$msg ) ) ) {
+ if ( !Hooks::run( 'AbortLogin', array( $u, $this->mPassword, &$abort, &$msg ) ) ) {
$this->mAbortLoginErrorMsg = $msg;
return $abort;
if ( $isAutoCreated ) {
// Must be run after $wgUser is set, for correct new user log
- wfRunHooks( 'AuthPluginAutoCreate', array( $u ) );
+ Hooks::run( 'AuthPluginAutoCreate', array( $u ) );
}
$retval = self::SUCCESS;
}
- wfRunHooks( 'LoginAuthenticateAudit', array( $u, $this->mPassword, $retval ) );
+ Hooks::run( 'LoginAuthenticateAudit', array( $u, $this->mPassword, $retval ) );
return $retval;
}
}
$abortError = '';
- if ( !wfRunHooks( 'AbortAutoAccount', array( $user, &$abortError ) ) ) {
+ if ( !Hooks::run( 'AbortAutoAccount', array( $user, &$abortError ) ) ) {
// Hook point to add extra creation throttles and blocks
wfDebug( "LoginForm::attemptAutoCreate: a hook blocked creation: $abortError\n" );
$this->mAbortLoginErrorMsg = $abortError;
*/
protected function resetLoginForm( Message $msg ) {
// Allow hooks to explain this password reset in more detail
- wfRunHooks( 'LoginPasswordResetMessage', array( &$msg, $this->mUsername ) );
+ Hooks::run( 'LoginPasswordResetMessage', array( &$msg, $this->mUsername ) );
$reset = new SpecialChangePassword();
$derivative = new DerivativeContext( $this->getContext() );
$derivative->setTitle( $reset->getPageTitle() );
}
$currentUser = $this->getUser();
- wfRunHooks( 'User::mailPasswordInternal', array( &$currentUser, &$ip, &$u ) );
+ Hooks::run( 'User::mailPasswordInternal', array( &$currentUser, &$ip, &$u ) );
$np = $u->randomPassword();
$u->setNewpassword( $np, $throttle );
# Run any hooks; display injected HTML if any, else redirect
$currentUser = $this->getUser();
$injected_html = '';
- wfRunHooks( 'UserLoginComplete', array( &$currentUser, &$injected_html ) );
+ Hooks::run( 'UserLoginComplete', array( &$currentUser, &$injected_html ) );
if ( $injected_html !== '' ) {
$this->displaySuccessfulAction( 'success', $this->msg( 'loginsuccesstitle' ),
$injected_html = '';
$welcome_creation_msg = 'welcomecreation-msg';
- wfRunHooks( 'UserLoginComplete', array( &$currentUser, &$injected_html ) );
+ Hooks::run( 'UserLoginComplete', array( &$currentUser, &$injected_html ) );
/**
* Let any extensions change what message is shown.
* @see https://www.mediawiki.org/wiki/Manual:Hooks/BeforeWelcomeCreation
* @since 1.18
*/
- wfRunHooks( 'BeforeWelcomeCreation', array( &$welcome_creation_msg, &$injected_html ) );
+ Hooks::run( 'BeforeWelcomeCreation', array( &$welcome_creation_msg, &$injected_html ) );
$this->displaySuccessfulAction(
'signup',
}
// Allow modification of redirect behavior
- wfRunHooks( 'PostLoginRedirect', array( &$returnTo, &$returnToQuery, &$type ) );
+ Hooks::run( 'PostLoginRedirect', array( &$returnTo, &$returnToQuery, &$type ) );
$returnToTitle = Title::newFromText( $returnTo );
if ( !$returnToTitle ) {
// Give authentication and captcha plugins a chance to modify the form
$wgAuth->modifyUITemplate( $template, $this->mType );
if ( $this->mType == 'signup' ) {
- wfRunHooks( 'UserCreateForm', array( &$template ) );
+ Hooks::run( 'UserCreateForm', array( &$template ) );
} else {
- wfRunHooks( 'UserLoginForm', array( &$template ) );
+ Hooks::run( 'UserLoginForm', array( &$template ) );
}
$out->disallowUserJs(); // just in case...
// Hook.
$injected_html = '';
- wfRunHooks( 'UserLogoutComplete', array( &$user, &$injected_html, $oldName ) );
+ Hooks::run( 'UserLogoutComplete', array( &$user, &$injected_html, $oldName ) );
$out->addHTML( $injected_html );
$out->returnToMain();
wfDebug( 'oldGroups: ' . print_r( $oldGroups, true ) . "\n" );
wfDebug( 'newGroups: ' . print_r( $newGroups, true ) . "\n" );
- wfRunHooks( 'UserRights', array( &$user, $add, $remove ) );
+ Hooks::run( 'UserRights', array( &$user, $add, $remove ) );
if ( $newGroups != $oldGroups ) {
$this->addLogEntry( $user, $oldGroups, $newGroups, $reason );
$software[$dbr->getSoftwareLink()] = $dbr->getServerInfo();
// Allow a hook to add/remove items.
- wfRunHooks( 'SoftwareInfo', array( &$software ) );
+ Hooks::run( 'SoftwareInfo', array( &$software ) );
$out = Xml::element(
'h2',
private static function getwgVersionLinked() {
global $wgVersion;
$versionUrl = "";
- if ( wfRunHooks( 'SpecialVersionVersionUrl', array( $wgVersion, &$versionUrl ) ) ) {
+ if ( Hooks::run( 'SpecialVersionVersionUrl', array( $wgVersion, &$versionUrl ) ) ) {
$versionParts = array();
preg_match( "/^(\d+\.\d+)/", $wgVersion, $versionParts );
$versionUrl = "https://www.mediawiki.org/wiki/MediaWiki_{$versionParts[1]}";
'other' => wfMessage( 'version-other' )->text(),
);
- wfRunHooks( 'ExtensionTypes', array( &self::$extensionTypes ) );
+ Hooks::run( 'ExtensionTypes', array( &self::$extensionTypes ) );
}
return self::$extensionTypes;
* Use wfFindFile so we still think file namespace pages without
* files are missing, but valid file redirects and foreign files are ok.
*
- * @return boolean
+ * @return bool
*/
protected function existenceCheck( Title $title ) {
return (bool)wfFindFile( $title );
)
);
// Replacement for the WantedPages::getSQL hook
- wfRunHooks( 'WantedPages::getQueryInfo', array( &$this, &$query ) );
+ Hooks::run( 'WantedPages::getQueryInfo', array( &$this, &$query ) );
return $query;
}
protected function getCustomFilters() {
if ( $this->customFilters === null ) {
$this->customFilters = parent::getCustomFilters();
- wfRunHooks( 'SpecialWatchlistFilters', array( $this, &$this->customFilters ), '1.23' );
+ Hooks::run( 'SpecialWatchlistFilters', array( $this, &$this->customFilters ), '1.23' );
}
return $this->customFilters;
} else {
# Top log Ids for a page are not stored
$nonRevisionTypes = array( RC_LOG );
- wfRunHooks( 'SpecialWatchlistGetNonRevisionTypes', array( &$nonRevisionTypes ) );
+ Hooks::run( 'SpecialWatchlistGetNonRevisionTypes', array( &$nonRevisionTypes ) );
if ( $nonRevisionTypes ) {
$conds[] = $dbr->makeList(
array(
&$join_conds, $opts
) {
return parent::runMainQueryHook( $tables, $fields, $conds, $query_options, $join_conds, $opts )
- && wfRunHooks(
+ && Hooks::run(
'SpecialWatchlistQuery',
array( &$conds, &$tables, &$join_conds, &$fields, $opts ),
'1.23'
$props[] = $msgcache['isimage'];
}
- wfRunHooks( 'WhatLinksHereProps', array( $row, $nt, $target, &$props ) );
+ Hooks::run( 'WhatLinksHereProps', array( $row, $nt, $target, &$props ) );
if ( count( $props ) ) {
$propsText = $this->msg( 'parentheses' )
// Give hooks the chance to handle this request
$className = null;
- wfRunHooks( 'UploadCreateFromRequest', array( $type, &$className ) );
+ Hooks::run( 'UploadCreateFromRequest', array( $type, &$className ) );
if ( is_null( $className ) ) {
$className = 'UploadFrom' . $type;
wfDebug( __METHOD__ . ": class name: $className\n" );
}
$error = '';
- if ( !wfRunHooks( 'UploadVerification',
+ if ( !Hooks::run( 'UploadVerification',
array( $this->mDestName, $this->mTempPath, &$error ) )
) {
wfProfileOut( __METHOD__ );
}
}
- wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &$status ) );
+ Hooks::run( 'UploadVerifyFile', array( $this, $mime, &$status ) );
if ( $status !== true ) {
wfProfileOut( __METHOD__ );
WatchedItem::IGNORE_USER_RIGHTS
);
}
- wfRunHooks( 'UploadComplete', array( &$this ) );
+ Hooks::run( 'UploadComplete', array( &$this ) );
$this->postProcessUpload();
}
public static function isAllowedUrl( $url ) {
if ( !isset( self::$allowedUrls[$url] ) ) {
$allowed = true;
- wfRunHooks( 'IsUploadAllowedFromUrl', array( $url, &$allowed ) );
+ Hooks::run( 'IsUploadAllowedFromUrl', array( $url, &$allowed ) );
self::$allowedUrls[$url] = $allowed;
}
*/
public static function isTrustedProxy( $ip ) {
$trusted = self::isConfiguredProxy( $ip );
- wfRunHooks( 'IsTrustedProxy', array( &$ip, &$trusted ) );
+ Hooks::run( 'IsTrustedProxy', array( &$ip, &$trusted ) );
return $trusted;
}
# Re-order by namespace ID number...
ksort( $this->namespaceNames );
- wfRunHooks( 'LanguageGetNamespaces', array( &$this->namespaceNames ) );
+ Hooks::run( 'LanguageGetNamespaces', array( &$this->namespaceNames ) );
}
return $this->namespaceNames;
if ( $inLanguage ) {
# TODO: also include when $inLanguage is null, when this code is more efficient
- wfRunHooks( 'LanguageGetTranslatedLanguageNames', array( &$names, $inLanguage ) );
+ Hooks::run( 'LanguageGetTranslatedLanguageNames', array( &$names, $inLanguage ) );
}
$mwNames = $wgExtraLanguageNames + $coreLanguageNames;
}
$this->mMagicHookDone = true;
wfProfileIn( 'LanguageGetMagic' );
- wfRunHooks( 'LanguageGetMagic', array( &$this->mMagicExtensions, $this->getCode() ) );
+ Hooks::run( 'LanguageGetMagic', array( &$this->mMagicExtensions, $this->getCode() ) );
wfProfileOut( 'LanguageGetMagic' );
}
// Initialise array
$this->mExtendedSpecialPageAliases =
self::$dataCache->getItem( $this->mCode, 'specialPageAliases' );
- wfRunHooks( 'LanguageGetSpecialPageAliases',
+ Hooks::run( 'LanguageGetSpecialPageAliases',
array( &$this->mExtendedSpecialPageAliases, $this->getCode() ) );
}
public static function getMessagesFileName( $code ) {
global $IP;
$file = self::getFileName( "$IP/languages/messages/Messages", $code, '.php' );
- wfRunHooks( 'Language::getMessagesFileName', array( $code, &$file ) );
+ Hooks::run( 'Language::getMessagesFileName', array( $code, &$file ) );
return $file;
}
"anoneditwarning": "<strong>Папярэджаньне</strong>: вы не ўвайшлі ў сыстэму. Ваш IP-адрас будзе бачны ўсім, калі вы адрэдагуеце старонку. Калі вы <strong>[$1 ўвойдзеце]</strong> або <strong>[$2 створыце рахунак]</strong>, вашыя рэдагаваньні будуць зьвязаныя з вашым імем карыстальніка, а таксама вам будуць даступныя дадатковыя перавагі.",
"anonpreviewwarning": "''Вы не ўвайшлі ў сыстэму. Падчас захаваньня Ваш IP-адрас будзе дададзены ў гісторыю рэдагаваньняў старонкі.''",
"missingsummary": "'''Напамін:''' Вы не пазначылі кароткае апісаньне зьменаў.\nКалі Вы націсьніце кнопку «Запісаць» яшчэ раз, Вашае рэдагаваньне будзе запісанае без апісаньня.",
+ "selfredirect": "<strong>Папярэджаньне:</strong> вы ствараеце перанакіраваньне на гэты самы артыкул.\nКалі вы націсьніце «{{int:savearticle}}» яшчэ раз, перанакіраваньне будзе створанае.",
"missingcommenttext": "Калі ласка, увядзіце камэнтар ніжэй.",
"missingcommentheader": "'''Напамін:''' Вы не пазначылі загаловак камэнтара.\nКалі Вы націсьніце кнопку «{{int:savearticle}}» яшчэ раз, Ваш камэнтар захаваецца бяз тэмы.",
"summary-preview": "Папярэдні прагляд апісаньня:",
"tog-shownumberswatching": "নজরদারী করছে, এমন ব্যবহারকারীর সংখ্যা দেখানো হোক",
"tog-oldsig": "বর্তমান স্বাক্ষর:",
"tog-fancysig": "স্বাক্ষরকে উইকিটেক্সট হিসেবে মনে করুন (কোন সয়ংক্রিয় লিঙ্ক ছাড়া)",
- "tog-uselivepreview": "তাৎক্ষণিক প্রাকদর্শনের ক্ষমতা চালু করা হোক (পরীক্ষামূলক)",
+ "tog-uselivepreview": "তাৎক্ষণিক প্রাকদর্শন ব্যবহার করো",
"tog-forceeditsummary": "খালি সম্পাদনা সারাংশ প্রবেশ করানোর সময় আমাকে জানানো হোক",
"tog-watchlisthideown": "আমার সম্পাদনাগুলি আমার নজরতালিকায় না দেখানো হোক",
"tog-watchlisthidebots": "বটের করা সম্পাদনাগুলি নজরতালিকায় না দেখানো হোক",
"showhideselectedversions": "নির্বাচিত সংশোধনগুলো দেখাও/লুকাও",
"editundo": "পূর্বাবস্থায় আনো",
"diff-empty": "(কোন পার্থক্য নেই)",
+ "diff-multi-sameuser": "(একই ব্যবহারকারী দ্বারা সম্পাদিত {{PLURAL:$1|একটি মধ্যবর্তী সংশোধন|$1টি মধ্যবর্তী সংশোধন}} দেখানো হচ্ছে না)",
+ "diff-multi-otherusers": "({{PLURAL:$2|একজন|$2 জন}} ব্যবহারকারী দ্বারা সম্পাদিত {{PLURAL:$1|একটি|$1টি}} মধ্যবর্তী সংশোধন দেখানো হচ্ছে না)",
"diff-multi-manyusers": "($2 জন {{PLURAL:$2|ব্যবহারাকারীর}} সম্পাদিত {{PLURAL:$1|একটি সাম্প্রতিক সংস্করণ|$1 টি সাম্প্রতিক সংস্করণ}} প্রদর্শিত হচ্ছে না)",
"difference-missing-revision": "$1 পার্থক্যের {{PLURAL:$2|একটি সংস্করণ|$2টি সংস্করণসমূহ}} খুজে পাওয়া যাচ্ছে না।\n\nসাধারণত মুছে ফেলা হয়েছে এমন পাতার মেয়াদ উত্তীর্ণ ইতিহাস পাতার লিংক ওপেন করার কারণে এটি হতে পারে। \n[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} অপসারণ লগে] বিস্তারিত তথ্য জানা যাবে।",
"searchresults": "অনুসন্ধানের ফলাফল",
"tog-shownumberswatching": "Prikaži broj korisnika koji prate",
"tog-oldsig": "Postojeći potpis:",
"tog-fancysig": "Smatraj potpis kao wikitekst (bez automatskog linka)",
- "tog-uselivepreview": "Koristite pregled uživo (eksperimentalno)",
+ "tog-uselivepreview": "Koristite pregled uživo",
"tog-forceeditsummary": "Opomeni me pri unosu praznog sažetka",
"tog-watchlisthideown": "Sakrij moje izmjene sa spiska praćenih članaka",
"tog-watchlisthidebots": "Sakrij izmjene botova sa spiska praćenih članaka",
"december-date": "$1. decembar",
"pagecategories": "{{PLURAL:$1|Kategorija|Kategorije}}",
"category_header": "Članci u kategoriji \"$1\"",
- "subcategories": "Potkategorije",
+ "subcategories": "Podkategorije",
"category-media-header": "Datoteke u kategoriji \"$1\"",
"category-empty": "''Ova kategorija trenutno ne sadrži članke ni medije.''",
"hidden-categories": "{{PLURAL:$1|Sakrivena kategorija|Sakrivene kategorije}}",
- "hidden-category-category": "Sakrivene kategorije",
+ "hidden-category-category": "Skrivene kategorije",
"category-subcat-count": "{{PLURAL:$2|Ova kategorija ima sljedeću podkategoriju.|Ova kategorija ima {{PLURAL:$1|sljedeću podkategoriju|sljedeće $1 podkategorije|sljedećih $1 podkategorija}}, od $2 ukupno.}}",
"category-subcat-count-limited": "Ova kategorija sadrži {{PLURAL:$1|slijedeću $1 podkategoriju|slijedeće $1 podkategorije|slijedećih $1 podkategorija}}.",
"category-article-count": "{{PLURAL:$2|U ovoj kategoriji nalazi se $1 članak.|{{PLURAL:$1|Prikazan je $1 članak|Prikazana su $1 članka|Prikazano je $1 članaka}} od ukupno $2 u ovoj kategoriji.}}",
"otherlanguages": "Na drugim jezicima",
"redirectedfrom": "(Preusmjereno sa $1)",
"redirectpagesub": "Preusmjeri stranicu",
+ "redirectto": "Preusmjerenje na:",
"lastmodifiedat": "Ova stranica je posljednji put izmijenjena $2, $1",
"viewcount": "Ovoj stranici je pristupljeno {{PLURAL:$1|$1 put|$1 puta}}.",
"protectedpage": "Zaštićena stranica",
"filerenameerror": "Ne može se promjeniti ime datoteke \"$1\" u \"$2\".",
"filedeleteerror": "Ne može se izbrisati datoteka \"$1\".",
"directorycreateerror": "Nije moguće napraviti direktorijum \"$1\".",
+ "directorynotreadableerror": "Direktorij \"$1\" nije čitljiv.",
"filenotfound": "Ne može se naći datoteka \"$1\".",
"unexpected": "Neočekivana vrijednost: \"$1\"=\"$2\".",
"formerror": "Greška: ne može se poslati upitnik",
"createacct-imgcaptcha-ph": "Unesite tekst koji vidite iznad",
"createacct-submit": "Napravite svoj korisnički račun",
"createacct-another-submit": "Napravi još jedan korisnički račun",
- "createacct-benefit-heading": "{{SITENAME}} je napravljen od strane ljudi kao što ste Vi.",
+ "createacct-benefit-heading": "{{SITENAME}} je napravljena od strane ljudi kao što ste Vi.",
"createacct-benefit-body1": "{{PLURAL:$1|izmjena|izmjene}}",
"createacct-benefit-body2": "{{PLURAL:$1|stranica|stranice|stranica}}",
- "createacct-benefit-body3": "nedavni {{PLURAL:$1|doprinosa}}",
+ "createacct-benefit-body3": "nedavnih {{PLURAL:$1|doprinosa}}",
"badretype": "Šifre koje ste unijeli se ne poklapaju.",
"userexists": "Korisničko ime koje ste unijeli je već u upotrebi.\nMolimo Vas da izaberete drugo ime.",
"loginerror": "Greška pri prijavljivanju",
"accountcreated": "Korisnički račun je napravljen",
"accountcreatedtext": "Korisnički račun za [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|razgovor]]) je napravljen.",
"createaccount-title": "Pravljenje korisničkog računa za {{SITENAME}}",
- "createaccount-text": "Neko je napravio korisnički račun za vašu e-mail adresu na {{SITENAME}} ($4) sa imenom \"$2\", i sa šifrom \"$3\".\nTrebali biste se prijaviti i promjeniti šifru.\n\nMožete ignorisati ovu poruku, ako je korisnički račun napravljen greškom.",
+ "createaccount-text": "Neko je napravio korisnički račun za vašu e-mail adresu na {{SITENAME}} ($4) sa imenom \"$2\", i sa šifrom \"$3\".\nTrebali biste se prijaviti i promijeniti šifru.\n\nMožete ignorisati ovu poruku, ako je korisnički račun napravljen greškom.",
"login-throttled": "Previše puta ste se pokušali prijaviti.\nMolimo Vas da sačekate $1 prije nego što pokušate ponovo.",
"login-abort-generic": "Vaša prijava nije bila uspješna – Prekinuto",
"loginlanguagelabel": "Jezik: $1",
"revdelete-hide-text": "Tekst revizije",
"revdelete-hide-image": "Sakrij sadržaj datoteke",
"revdelete-hide-name": "Sakrij akciju i cilj",
- "revdelete-hide-comment": "Sakrij izmjene komentara",
+ "revdelete-hide-comment": "Uredi sažetak",
"revdelete-hide-user": "Korisničko ime urednika/IP",
"revdelete-hide-restricted": "Ograniči podatke za administratore kao i za druge korisnike",
"revdelete-radio-same": "(ne mijenjaj)",
"search-result-category-size": "{{PLURAL:$1|1 član|$1 člana|$1 članova}} ({{PLURAL:$2|1 podkategorija|$2 podkategorije|$2 podkategorija}}, {{PLURAL:$3|1 datoteka|$3 datoteke|$3 datoteka}})",
"search-redirect": "(preusmjeravanje $1)",
"search-section": "(sekcija $1)",
+ "search-category": "(kategorija $1)",
"search-suggest": "Da li ste mislili: $1",
"search-interwiki-caption": "Srodni projekti",
"search-interwiki-default": "$1 rezultati:",
"invalid-chunk-offset": "Neispravna polazna tačka",
"img-auth-accessdenied": "Pristup onemogućen",
"img-auth-nopathinfo": "Nedostaje PATH_INFO.\nVaš server nije postavljen da daje ovu informaciju.\nMožda je zasnovan na CGI koji ne podržava img_auth.\nPogledajte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
- "img-auth-notindir": "Zahtjevana putanje nije u direktorijumu podešenom za postavljanje.",
+ "img-auth-notindir": "Zahtjevana putanja nije u direktoriju podešenom za postavljanje.",
"img-auth-badtitle": "Ne mogu napraviti valjani naslov iz \"$1\".",
"img-auth-nologinnWL": "Niste prijavljeni i \"$1\" nije na spisku dozvoljenih.",
"img-auth-nofile": "Datoteka \"$1\" ne postoji.",
- "img-auth-isdir": "Pokušavate pristupiti direktorijumu \"$1\".\nDozvoljen je samo pristup datotekama.",
+ "img-auth-isdir": "Pokušavate pristupiti direktoriju \"$1\".\nDozvoljen je samo pristup datotekama.",
"img-auth-streaming": "Tok \"$1\".",
"img-auth-public": "Funkcija img_auth.php služi za izlaz datoteka sa privatnih wikija.\nOva wiki je postavljena kao javna wiki.\nZa optimalnu sigurnost, img_auth.php je onemogućena.",
"img-auth-noread": "Korisnik nema pristup za čitanje \"$1\".",
"querypage-disabled": "Ova posebna stranica je onemogućena jer smanjuje performanse.",
"booksources": "Štampani izvori",
"booksources-search-legend": "Traži književne izvore",
+ "booksources-search": "Traži",
"booksources-text": "Ispod se nalazi spisak vanjskih linkova na ostale stranice koje prodaju nove ili korištene knjige kao i stranice koje mogu da imaju važnije podatke o knjigama koje tražite:",
"booksources-invalid-isbn": "Navedeni ISBN broj nije validan; molimo da provjerite da li je došlo do greške pri kopiranju iz prvobitnog izvora.",
"specialloguserlabel": "Izvršilac:",
"listgrouprights-addgroup-self-all": "Može dodati sve grupe na svoj račun",
"listgrouprights-removegroup-self-all": "Može ukloniti sve grupe sa svog računa",
"listgrouprights-namespaceprotection-namespace": "Imenski prostor",
+ "trackingcategories-name": "Ime poruke",
"trackingcategories-nodesc": "Opis nije dostupan.",
"mailnologin": "Nema adrese za slanje",
"mailnologintext": "Morate biti [[Special:UserLogin|prijavljeni]]\ni imati ispravnu adresu e-pošte u vašim [[Special:Preferences|podešavanjima]]\nda biste slali e-poštu drugim korisnicima.",
"tooltip-feed-atom": "Atom za ovu stranicu",
"tooltip-t-contributions": "Pogledajte spisak doprinosa ovog korisnika",
"tooltip-t-emailuser": "Pošaljite pismo ovom korisniku",
+ "tooltip-t-info": "Više informacija o ovoj stranici",
"tooltip-t-upload": "Postavi slike i druge medije",
"tooltip-t-specialpages": "Spisak svih posebnih stranica",
"tooltip-t-print": "Verzija ove stranice za štampanje",
"confirm-watch-top": "Dodajte ovu stranu na Vaš spisak praćenih članaka",
"confirm-unwatch-button": "U redu",
"confirm-unwatch-top": "Izbrišite ovu stranu sa Vašeg spiska praćenih članaka",
+ "quotation-marks": "\"$1\"",
"imgmultipageprev": "← prethodna stranica",
"imgmultipagenext": "slijedeća stranica →",
"imgmultigo": "Idi!",
"imgmultigoto": "Idi na stranicu $1",
+ "img-lang-default": "(podrazumijevani jezik)",
+ "img-lang-info": "Prikaži ovu sliku u $1. $2",
"img-lang-go": "Idi",
"ascending_abbrev": "rast",
"descending_abbrev": "opad",
"autosumm-replace": "Zamjena stranice sa '$1'",
"autoredircomment": "Preusmjereno na [[$1]]",
"autosumm-new": "Napravljena stranica sa '$1'",
+ "autosumm-newblank": "Napravljena prazna stranica",
"size-bytes": "$1 B",
"size-kilobytes": "$1 KB",
"size-megabytes": "$1 MB",
"watchlistedit-raw-done": "Vaš spisak praćenja je ažuriran.",
"watchlistedit-raw-added": "{{PLURAL:$1|1 naslov je dodan|$1 naslova su dodana|$1 naslova je dodano}}:",
"watchlistedit-raw-removed": "{{PLURAL:$1|1 naslov je uklonjen|$1 naslova je uklonjeno}}:",
+ "watchlisttools-clear": "Očisti spisak nadgledanja",
"watchlisttools-view": "Pregled promjena praćenih stranica",
"watchlisttools-edit": "Pogledaj i uredi listu praćenih članaka.",
"watchlisttools-raw": "Uređivanje praćenih stranica u okviru praćenja.",
"version-version": "(Verzija $1)",
"version-license": "Licenca",
"version-ext-license": "Licenca",
+ "version-ext-colheader-name": "Proširenje",
+ "version-skin-colheader-name": "Izgled",
"version-ext-colheader-version": "Verzija",
"version-ext-colheader-license": "Licenca",
"version-ext-colheader-description": "Opis",
"specialpages-group-wiki": "Podaci i alati",
"specialpages-group-redirects": "Preusmjeravanje posebnih stranica",
"specialpages-group-spam": "Alati za spam",
+ "specialpages-group-developer": "Razvojni alati",
"blankpage": "Prazna stranica",
"intentionallyblankpage": "Ova stranica je namjerno ostavljena prazna",
"external_image_whitelist": " #Ostavite ovu liniju onakva kakva je<pre>\n#Stavite obične fragmente opisa (samo dio koji ide između //) ispod\n#Ovi će biti spojeni sa URLovima sa vanjskih (eksternih) slika\n#One koji se spoje biće prikazane kao slike, u suprotnom će se prikazati samo link\n#Linije koje počinju sa # se tretiraju kao komentari\n#Ovo ne razlikuje velika i mala slova\n\n#Stavite sve regex fragmente iznad ove linije. Ostavite ovu liniju onakvu kakva je</pre>",
"duration-centuries": "$1 {{PLURAL:$1|vijek|vijeka|vijekova}}",
"duration-millennia": "$1 {{PLURAL:$1|milenij|milenija}}",
"rotate-comment": "Slika rotirana za $1 {{PLURAL:$1|stepen|stepeni}} u smjeru kazaljke na satu",
+ "limitreport-walltime": "Korištenje u realnom vremenu",
"limitreport-walltime-value": "$1 {{PLURAL:$1|sekunda|sekunde|sekundi}}",
"expandtemplates": "Proširi šablone",
"expand_templates_intro": "Ova posebna stranica uzima neki tekst i proširuje sve šablone u njemu rekurzivno.\nOna također proširuje parserske funkcije poput\n<nowiki>{{</nowiki>#language:…}} i varijable poput\n<nowiki>{{</nowiki>CURRENTDAY}}—u principu gotovo sve između dvostrukih zagrada.\nOvo se uradi putem poziva relevantnog parserskog nivoa iz same MediaWiki.",
"expand_templates_preview": "Pregled",
"pagelang-name": "Stranica",
"pagelang-language": "Jezik",
- "pagelang-select-lang": "Izaberi jezik"
+ "pagelang-select-lang": "Izaberi jezik",
+ "mediastatistics-header-unknown": "Nepoznato",
+ "json-error-syntax": "Sintaksna greška"
}
"tog-enotifrevealaddr": "Гайта сан зlе оцу хаамаш барехь",
"tog-shownumberswatching": "Гайта декъашхойн терахь, агӀо латийна болу шай тергаме могӀанан юкъа",
"tog-oldsig": "Карара куьгтаӀорна:",
- "tog-fancysig": "Шен вики-кÑ\8aаÑ\81Ñ\82аман кÑ\83Ñ\8cгÑ\82аÓ\80даÑ\80 (Ñ\88а Ñ\88еÑ\85 Ñ\85Ñ\8cажоÑ\80аг йоÑ\86Ñ\83Ñ\88)",
+ "tog-fancysig": "Шен вики-къастаман куьгтаӀдар (ша шех хьажорг йоцуш)",
"tog-uselivepreview": "Лелайа чехка хьалха хьажа (JavaScript, муха ю хьажарна)",
"tog-forceeditsummary": "Дага даийта, нагахь нисйарх лаьцна чохь язйина яцахь",
"tog-watchlisthideown": "Къайлаяха ас нисйинарш тергаме могӀам чура",
"history_short": "Истори",
"updatedmarker": "Керла яккхина сона гинчултӀаьхьа",
"printableversion": "Зорба туху верси",
- "permalink": "Ð\94аиман йолÑ\83 Ñ\85Ñ\8cажоÑ\80аг",
+ "permalink": "Даиман йолу хьажорг",
"print": "Зорба тоха",
"view": "Хьажа",
"view-foreign": "Сайтехь $1 хьажа",
"readonly": "Блоктоьхна дӀайаздар хаамийн бухе",
"enterlockreason": "Билгалде блоктохаран бахьна а и чекх йолу хан а.",
"readonlytext": "АгӀонаш тӀетохар а кхин хийцамаш барна а блоктоьхна:\nБлокоьхначо биттина хаам: $1.",
- "missing-article": "Ð¥Ó\80окÑ\85Ñ\83 Ñ\87оÑ\85Ñ\8c каÑ\80оезаÑ\88 йолÑ\83 Ñ\85Ñ\8cан деÑ\85аÑ\80Ñ\86а йозан агÓ\80онаÑ\88 Ñ\86акаÑ\80ийна «$1» $2.\n\nÐ\98Ñ\88Ñ\82наÑ\80г наггаÑ\85Ñ\8c Ñ\85Ñ\83Ñ\8cлÑ\83 Ñ\85Ñ\8cажоÑ\80аг дÓ\80аÑ\8fÑ\8cккÑ\85ина елаÑ\85Ñ\8c Ñ\8f Ñ\85ийÑ\86ам бина Ñ\82иÑ\88а Ñ\85Ñ\8cажоÑ\80агца дехьа гӀо гӀоьртича.\n\nНагахьсан гӀулкх цуьнах доьзна дацахь, хьуна карийна гӀирс латточехь гӀалат.\nДехар до, хаам бе оцуьнах [[Special:ListUsers/sysop|куьйгалхога]], гойтуш URL.",
+ "missing-article": "Ð¥Ó\80окÑ\85Ñ\83 Ñ\87оÑ\85Ñ\8c каÑ\80оезаÑ\88 йолÑ\83 Ñ\85Ñ\8cан деÑ\85аÑ\80Ñ\86а йозан агÓ\80онаÑ\88 Ñ\86акаÑ\80ийна «$1» $2.\n\nÐ\98Ñ\88Ñ\82наÑ\80г наггаÑ\85Ñ\8c Ñ\85Ñ\83Ñ\8cлÑ\83 Ñ\85Ñ\8cажоÑ\80г дÓ\80аÑ\8fÑ\8cккÑ\85ина елаÑ\85Ñ\8c Ñ\8f Ñ\85ийÑ\86ам бина Ñ\82иÑ\88а Ñ\85Ñ\8cажоÑ\80гца дехьа гӀо гӀоьртича.\n\nНагахьсан гӀулкх цуьнах доьзна дацахь, хьуна карийна гӀирс латточехь гӀалат.\nДехар до, хаам бе оцуьнах [[Special:ListUsers/sysop|куьйгалхога]], гойтуш URL.",
"missingarticle-rev": "(верси № $1)",
"missingarticle-diff": "(башхалла: $1, $2)",
"readonly_lag": "Хаамашан базина цхьана хан блоктоьхна, хаамашан базан сервераш нисялца.",
"italic_sample": "Сеттан до йоза",
"italic_tip": "Сеттан до йоза",
"link_sample": "Хьажориган коьрта могlа",
- "link_tip": "ЧоÑ\8cÑ\85Ñ\8cа Ñ\85Ñ\8cажоÑ\80аг",
- "extlink_sample": "http://www.example.com Ñ\85Ñ\8cажоÑ\80аг коÑ\80Ñ\82а",
- "extlink_tip": "Ð\90Ñ\80аÑ\85Ñ\8cаÑ\80а Ñ\85Ñ\8cажоÑ\80аг (йиÑ\86 ма йе Ñ\85Ó\80оÑ\82Ñ\82алÑ\83Ñ\88еÑ\80г http://)",
+ "link_tip": "Чоьхьа хьажорг",
+ "extlink_sample": "http://www.example.com хьажорг корта",
+ "extlink_tip": "Арахьара хьажорг (йиц ма йе хӀотталушерг http://)",
"headline_sample": "Йозан корта",
"headline_tip": "Корта 2-гlа локхаллийца",
"nowiki_sample": "Чудиллийша кхузе барамхlоттонза йоза.",
"image_sample": "Example.jpg",
"image_tip": "Чохь йолу файл",
"media_sample": "Example.ogg",
- "media_tip": "Ð¥Ñ\8cажоÑ\80аг медиа-Ñ\84айлан Ñ\82Ó\80е",
+ "media_tip": "Хьажорг медиа-файлан тӀе",
"sig_tip": "Хьан куьгтаlор аъ хlоттина хан",
"hr_tip": "Ана сиз (сих сиха ма леладайша)",
"summary": "Хийцамех лаьцна:",
"note": "'''Билгалдаккхар:'''",
"previewnote": "'''ХӀара хьлха хьажар ду, йоза хӀинца язданза ду!'''",
"continue-editing": "Кхин дӀа тадар",
- "session_fail_preview": "СеÑ\80веÑ\80 лаÑ\80а Ñ\86а йиÑ\80а аÑ\85Ñ\8cа бина Ñ\85ийÑ\86амаÑ\88 дÓ\80аÑ\8fзба. Ð\9aÑ\85иÑ\8a Ñ\86кÑ\8aа а гÓ\80оÑ\80Ñ\82аÑ\85Ñ\8c.\nÐ\9dагаÑ\85Ñ\8c Ñ\81анна Ñ\85Ó\80аÑ\80а гÓ\80алаÑ\82 Ñ\8eÑ\85а а далаÑ\85Ñ\8c, [[Special:UserLogout|Ñ\81еанÑ\81 дÓ\80а а кÑ\8aоÑ\8cвлин]], Ñ\8eÑ\85а а Ñ\81иÑ\81Ñ\82емин Ñ\87Ñ\83вала/Ñ\8fла Ñ\85Ñ\8cажа.",
+ "session_fail_preview": "СеÑ\80веÑ\80 лаÑ\80а Ñ\86а йиÑ\80а аÑ\85Ñ\8cа бина Ñ\85ийÑ\86амаÑ\88 дÓ\80аÑ\8fзба. Ð\9aÑ\85иÑ\8a Ñ\86кÑ\8aа а гÓ\80оÑ\80Ñ\82аÑ\85Ñ\8c.\nÐ\9dагаÑ\85Ñ\8c Ñ\81анна Ñ\85Ó\80аÑ\80а гÓ\80алаÑ\82 Ñ\8eÑ\85а а далаÑ\85Ñ\8c, [[Special:UserLogout|Ñ\81еанÑ\81 дÓ\80а а кÑ\8aоÑ\8cвлин]], Ñ\8eÑ\85а а Ñ\81иÑ\81Ñ\82емин Ñ\87Ñ\83гÓ\80о.",
"edit_form_incomplete": "'''Цхьайолу тадаран формаш серверан тӀекхаьчча яц. Тидаме хьажа хьай нисдарш доьхна дуй, ТӀакха южу гӀорта.'''",
"editing": "Тадар: $1",
"creating": "АгӀо кхоллар «$1»",
"searchall": "массо",
"showingresults": "Лахахьа {{PLURAL:$1|гойту}} <strong>$1</strong> {{PLURAL:$1|хилам}}, дӀаболало кху № <strong>$2</strong>.",
"showingresultsinrange": "Лахахь гайтина {{PLURAL:$1|<strong>1</strong> хилам}} диапазонехь <strong>$2</strong> тӀера <strong>$3</strong> кхаччалц.",
- "search-showingresults": "{{PLURAL:$4|Карийнарш <strong>$1</strong> чура <strong>$3</strong>|Карийнарш <strong>$1 — $2</strong> чура <strong>$3</strong>}}",
+ "search-showingresults": "{{PLURAL:$4|Карийна <strong>$1</strong> — цхьаъ агӀо|Карийна <strong>$3</strong> агӀо, царах агӀонгахь гойту $2 агӀо}}",
"search-nonefound": "Дехаре терра цхьа хӀума ца карийна.",
"powersearch-legend": "Шуьйра лахар",
"powersearch-ns": "ЦӀерийн меттигашкахь лахар:",
"recentchangeslinked-title": "Кхуьнца долу нисдарш $1",
"recentchangeslinked-summary": "ХӀара хийцам биначу агӀонийн могӀам бу, тӀетовжар долуш хьагучу агӀон (я хьагойтуш йолучу категорена).\nАгӀонаш юькъа йогӀуш йолу хьан [[Special:Watchlist|тергаме могӀам чохь]] '''къастийна ю'''.",
"recentchangeslinked-page": "АгӀон цӀе:",
- "recentchangeslinked-to": "Ð\9aÑ\85еÑ\87Ñ\83 агÓ\80оÑ\80, гайÑ\82а Ñ\85ийÑ\86амаÑ\88 агÓ\80онаÑ\88Ñ\86а, Ñ\85Ó\80оÑ\82Ñ\82ийнаÑ\87Ñ\83 агÓ\80онÑ\82Ó\80е Ñ\85Ñ\8cажоÑ\80аг йолÑ\83Ñ\88",
+ "recentchangeslinked-to": "Кхечу агӀор, гайта хийцамаш агӀонашца, хӀоттийначу агӀонтӀе хьажорг йолуш",
"upload": "Файл чуяккхар",
"uploadbtn": "Файл чуяккхар",
"reuploaddesc": "Юху гӀо файл чуйоккху агӀоне",
"uploadnologintext": "Серверан чу файлаш яха хьо $1.",
"uploaderror": "Файл чуяккхаран гӀалат",
"upload-recreate-warning": "'''Тегам бе: иштта цӀе йолу файл дӀаяьккхина я цӀе хийцина.'''\n\nЛахахьа гойтуш ю хӀокху агӀона тептар:",
- "uploadtext": "Ð\9bелайе Ñ\85Ó\80аÑ\80а агÓ\80о Ñ\81еÑ\80веÑ\80 Ñ\87Ñ\83 Ñ\84айлаÑ\88 йоÑ\85Ñ\83Ñ\88.\nÐ¥Ñ\8cалÑ\85о Ñ\87Ñ\83Ñ\8fÑ\8cÑ\85на Ñ\84айлаÑ\88 Ñ\85Ñ\8cажа, [[Special:FileList|кÑ\85Ñ\83заÑ\85Ñ\8c]]. Ð\9aÑ\85ин Ñ\87Ñ\83Ñ\8fÑ\8cÑ\85на Ñ\84айлаÑ\88 дÓ\80аÑ\8fзло [[Special:Log/upload|Ñ\87Ñ\83Ñ\8fÑ\85аÑ\80ан Ñ\82епÑ\82аÑ\80 Ñ\87оÑ\85Ñ\8c]], дÓ\80аÑ\8fÑ\8cÑ\85на Ñ\84айлаÑ\88 каÑ\80о йиÑ\88 Ñ\8e [[Special:Log/delete|кÑ\85Ñ\83заÑ\85Ñ\8c]].\n\nФайл агÓ\80она Ñ\87Ñ\83йилла лелабе лаÑ\85аÑ\80а могÓ\80анаÑ\88:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code>''' Ñ\84айла Файлан Ñ\8eÑ\8cззина веÑ\80Ñ\81и Ñ\87Ñ\83йиллÑ\83Ñ\88;\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|Ñ\86Ñ\83наÑ\85Ñ\8c лаÑ\8cÑ\86на Ñ\85аам]]</nowiki></code>''' 200 пикÑ\81елÑ\8c баÑ\80амеÑ\85Ñ\8c Ñ\84айл Ñ\87Ñ\83йилаÑ\80 бÑ\83Ñ\85аÑ\85Ñ\8c Ñ\86Ñ\83наÑ\85Ñ\8c лаÑ\8cÑ\86на могÓ\80а а болÑ\83Ñ\88;\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code>''' Ñ\84айлан Ñ\82Ó\80е Ñ\85Ñ\8cажоÑ\80аг Ñ\85Ó\80оÑ\82айо Ñ\84айл агÓ\80онгаÑ\85Ñ\8c Ñ\86а гÑ\83Ñ\88.",
+ "uploadtext": "Лелайе хӀара агӀо сервер чу файлаш йохуш.\nХьалхо чуяьхна файлаш хьажа, [[Special:FileList|кхузахь]]. Кхин чуяьхна файлаш дӀаязло [[Special:Log/upload|чуяхаран тептар чохь]], дӀаяьхна файлаш каро йиш ю [[Special:Log/delete|кхузахь]].\n\nФайл агӀона чуйилла лелабе лахара могӀанаш:\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.jpg]]</nowiki></code>''' файла Файлан юьззина верси чуйиллуш;\n* '''<code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:File.png|200px|thumb|left|цунахь лаьцна хаам]]</nowiki></code>''' 200 пиксель барамехь файл чуйилар бухахь цунахь лаьцна могӀа а болуш;\n* '''<code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:File.ogg]]</nowiki></code>''' файлан тӀе хьажорг хӀотайо файл агӀонгахь ца гуш.",
"upload-permitted": "Магийна файлийн тайпанаш: $1.",
"upload-preferred": "Магийна файлийн тайпанаш: $1.",
"upload-prohibited": "Магийна доцу файлийн тайпанаш: $1.",
"fewestrevisions": "ЧӀогӀа кӀезиг версеш йолу агӀонаш",
"nbytes": "$1 {{PLURAL:$1|байт}}",
"ncategories": "$1 {{PLURAL:$1|категори|категореш}}",
- "ninterwikis": "$1 {{PLURAL:$1|1=Ñ\8eкÑ\8aаÑ\80вики-Ñ\85Ñ\8cажоÑ\80аг|Ñ\8eкÑ\8aаÑ\80вики-Ñ\85Ñ\8cажоÑ\80гаÑ\88}}",
+ "ninterwikis": "$1 {{PLURAL:$1|1=юкъарвики-хьажорг|юкъарвики-хьажоргаш}}",
"nlinks": "$1 {{PLURAL:$1|хьажорг}}",
"nmembers": "$1 {{PLURAL:$1|хӀума|хӀумнаш}}",
"nmemberschanged": "$1 → $2 {{PLURAL:$2|хӀума|хӀумнаш}}",
"ancientpages": "ТӀехьара терахьца тадар дина яззамаш",
"move": "ЦӀе хийца",
"movethispage": "ХӀокху агӀон цӀе хийца",
- "unusedimagestext": "Ð\94еÑ\85аÑ\80 до, Ñ\82идаме Ñ\8dÑ\86а, кÑ\85ин йолÑ\83 дÑ\83Ñ\8cнана маÑ\88ан-меÑ\82Ñ\82игаÑ\88 а лелоÑ\88 Ñ\85ила мега нийÑ\81Ñ\81а йогÓ\80Ñ\83 Ñ\85Ñ\8cажоÑ\80аг (URL) Ñ\85Ó\80окÑ\85Ñ\83 Ñ\85Ó\80Ñ\83ман, Ñ\85Ó\80окÑ\85Ñ\83 могÓ\80аме йогÓ\80Ñ\83Ñ\88 Ñ\8fлаÑ\85Ñ\8c Ñ\8fÑ\86аÑ\85Ñ\8c а иза Ñ\85ила мега жигаÑ\80а лелоÑ\88.",
+ "unusedimagestext": "Дехар до, тидаме эца, кхин йолу дуьнана машан-меттигаш а лелош хила мега нийсса йогӀу хьажорг (URL) хӀокху хӀуман, хӀокху могӀаме йогӀуш ялахь яцахь а иза хила мега жигара лелош.",
"unusedcategoriestext": "ХӀокху категорешан чохь агӀонаш я кхин категореш яц.",
"notargettitle": "Ӏалашо билгал йина яц",
"notargettext": "И кхочушдан ахьа билгал йина яц Ӏалашонан агӀо я декъашхо.",
"deletedcontributions": "Декъашхочун дӀабяккхина къинхьегам",
"deletedcontributions-title": "ДӀабаьккхина къинхьегам",
"sp-deletedcontributions-contribs": "къинхьегам",
- "linksearch": "Ð\90Ñ\80аÑ\85Ñ\8cаÑ\80а Ñ\85Ñ\8cажоÑ\80аг",
+ "linksearch": "Арахьара хьажорг",
"linksearch-pat": "Лехарна кеп:",
"linksearch-ns": "ЦӀерийн ана:",
"linksearch-ok": "Лаха",
"linksearch-text": "Лело мега хӀоттош йолу символаш, масала, <code>*.wikipedia.org</code>.\nЛакхара даржан домен мукъа хила еза , масала<code>*.org</code><br />\nЛовш йолу {{PLURAL:$2|1=протокол|протоколаш}}: <code>$1</code> (Iад йитарца http://, протокол бакъалла язъен яцахь).",
- "linksearch-line": "$2 â\80\94 Ñ\85Ñ\8cажоÑ\80аг кÑ\85Ñ\83 $1",
+ "linksearch-line": "$2 — хьажорг кху $1",
"listusersfrom": "Гучé баха декъашхой, болалуш болу тӀера:",
"listusers-submit": "Гайта",
"listusers-noresult": "Декъашхой цакарий.",
"nolinkshere-ns": "Хаьржинчу анахь яц '''[[:$1]]''' цӀе йолу агӀонаш",
"isredirect": "агӀо-дӀасахьажорг",
"istemplate": "юкъаялийнарш",
- "isimage": "Файлан Ñ\85Ñ\8cажоÑ\80аг",
+ "isimage": "Файлан хьажорг",
"whatlinkshere-prev": "{{PLURAL:$1|1=хьалхайодарг|хьалхайодарш}} $1",
"whatlinkshere-next": "{{PLURAL:$1|тӀаьхьайогӀург|тӀаьхьайогӀурш}} $1",
"whatlinkshere-links": "← хьажоргаш",
"lockedbyandtime": "($1 $2 $3)",
"move-page": "$1 — цӀе хийцар",
"move-page-legend": "ЦӀe хийца яр",
- "movepagetext": "Ð\91Ñ\83Ñ\85аÑ\85Ñ\8c йолÑ\83 Ñ\84оÑ\80манÑ\86а агÓ\80он Ñ\86Ó\80е Ñ\85ийÑ\86ало. ЦÑ\83л Ñ\81овнаÑ\85 Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аман Ñ\82епÑ\82аÑ\80 кÑ\85оÑ\8cÑ\87Ñ\83 меÑ\82Ñ\82е доккÑ\85а. Ð¥Ñ\8cалÑ\85алеÑ\80а Ñ\86Ó\80аÑ\80аÑ\85Ñ\8c Ñ\85иÑ\80Ñ\8aÑ\8e кеÑ\80ла кÑ\85оÑ\8cллина агÓ\80онан Ñ\85Ñ\8cажоÑ\80аг.\n\nÐ¥Ñ\8cовÑ\81алаÑ\88 [[Special:DoubleRedirects|Ñ\88алÑ\85а]] а [[Special:BrokenRedirects|йоÑ\85на Ñ\85Ñ\8cажоÑ\80гаÑ\88]] Ñ\8eй Ñ\82еÑ\85Ñ\8c аÑ\8cлла.\n\nШÑ\83 жоÑ\8cпеÑ\85Ñ\8c дÑ\83 Ñ\85Ñ\8cажоÑ\80гаÑ\88 нийÑ\81а некÑ\8a гойÑ\82Ñ\83Ñ\88 Ñ\85илаÑ\80ан.\n\nТидам бе Ñ\85Ñ\8cалÑ\85алеÑ\80а агÓ\80он Ñ\86Ó\80е â\80\98â\80\99â\80\99Ñ\85ийÑ\86алÑ\83Ñ\80 Ñ\8fÑ\86â\80\99â\80\99â\80\99 иÑ\88Ñ\82Ñ\82а Ñ\86Ó\80е йолÑ\83 агÓ\80о йолÑ\83Ñ\88 елаÑ\85Ñ\8c. ЮкÑ\8aаÑ\80даккÑ\85аÑ\80: йолÑ\83Ñ\88 йолÑ\83 агÓ\80о кÑ\85оÑ\8cÑ\87Ñ\83Ñ\85Ñ\8cа Ñ\85Ñ\8cажоÑ\80аг елаÑ\85Ñ\8c, Ñ\8f еÑ\81а елаÑ\85Ñ\8c а, Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аме иÑ\81Ñ\82оÑ\80и Ñ\8fÑ\86аÑ\85Ñ\8c а.\n\nÐ\98 боÑ\85Ñ\83Ñ\80г дÑ\83 Ñ\88Ñ\83н агÓ\80онан Ñ\86Ó\80е Ñ\8eÑ\85а а Ñ\85Ñ\8cалÑ\85а Ñ\85иллаÑ\80гÑ\87Ñ\83нтӀе хийца йиш ю, амма йолуш йолу агӀо дӀаяккха йиш яц.\n\n'''ДӀАХЬЕДАР!'''\n\nЦӀе хийцар бахьнехь гӀаръяьлла агӀонашна дукха дагахь боцу хийцамаш хила тарло. Цундела цӀе хийцале шеш хила тарлучу тӀехьонашах кхета аьлла тешна хила.",
- "movepagetext-noredirectfixer": "Ð\91Ñ\83Ñ\85аÑ\85Ñ\8c йолÑ\83 Ñ\84оÑ\80манÑ\86а агÓ\80он Ñ\86Ó\80е Ñ\85ийÑ\86ало. ЦÑ\83л Ñ\81овнаÑ\85 Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аман Ñ\82епÑ\82аÑ\80 кÑ\85оÑ\8cÑ\87Ñ\83 меÑ\82Ñ\82е доккÑ\85а. Ð¥Ñ\8cалÑ\85алеÑ\80а Ñ\86Ó\80аÑ\80аÑ\85Ñ\8c Ñ\85иÑ\80Ñ\8aÑ\8e кеÑ\80ла кÑ\85оÑ\8cллина агÓ\80онан Ñ\85Ñ\8cажоÑ\80аг.\n\nÐ¥Ñ\8cовÑ\81алаÑ\88 [[Special:DoubleRedirects|Ñ\88алÑ\85а]] а [[Special:BrokenRedirects|йоÑ\85на Ñ\85Ñ\8cажоÑ\80гаÑ\88]] Ñ\8eй Ñ\82еÑ\85Ñ\8c аÑ\8cлла.\n\nШÑ\83 жоÑ\8cпеÑ\85Ñ\8c дÑ\83 Ñ\85Ñ\8cажоÑ\80гаÑ\88 нийÑ\81а некÑ\8a гойÑ\82Ñ\83Ñ\88 Ñ\85илаÑ\80ан.\n\nТидам бе Ñ\85Ñ\8cалÑ\85алеÑ\80а агÓ\80он Ñ\86Ó\80е â\80\98â\80\99â\80\99Ñ\85ийÑ\86алÑ\83Ñ\80 Ñ\8fÑ\86â\80\99â\80\99â\80\99 иÑ\88Ñ\82Ñ\82а Ñ\86Ó\80е йолÑ\83 агÓ\80о йолÑ\83Ñ\88 елаÑ\85Ñ\8c. ЮкÑ\8aаÑ\80даккÑ\85аÑ\80: йолÑ\83Ñ\88 йолÑ\83 агÓ\80о кÑ\85оÑ\8cÑ\87Ñ\83Ñ\85Ñ\8cа Ñ\85Ñ\8cажоÑ\80аг елаÑ\85Ñ\8c, Ñ\8f еÑ\81а елаÑ\85Ñ\8c а, Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аме иÑ\81Ñ\82оÑ\80и Ñ\8fÑ\86аÑ\85Ñ\8c а.\n\nÐ\98 боÑ\85Ñ\83Ñ\80г дÑ\83 Ñ\88Ñ\83н агÓ\80онан Ñ\86Ó\80е Ñ\8eÑ\85а а Ñ\85Ñ\8cалÑ\85а Ñ\85иллаÑ\80гÑ\87Ñ\83нтӀе хийца йиш ю, амма йолуш йолу агӀо дӀаяккха йиш яц.\n\n'''ДӀАХЬЕДАР!'''\n\nЦӀе хийцар бахьнехь гӀаръяьлла агӀонашна дукха дагахь боцу хийцамаш хила тарло. Цундела цӀе хийцале шеш хила тарлучу тӀехьонашах кхета аьлла тешна хила.",
+ "movepagetext": "Ð\91Ñ\83Ñ\85аÑ\85Ñ\8c йолÑ\83 Ñ\84оÑ\80манÑ\86а агÓ\80он Ñ\86Ó\80е Ñ\85ийÑ\86ало. ЦÑ\83л Ñ\81овнаÑ\85 Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аман Ñ\82епÑ\82аÑ\80 кÑ\85оÑ\8cÑ\87Ñ\83 меÑ\82Ñ\82е доккÑ\85а. Ð¥Ñ\8cалÑ\85алеÑ\80а Ñ\86Ó\80аÑ\80аÑ\85Ñ\8c Ñ\85иÑ\80Ñ\8aÑ\8e кеÑ\80ла кÑ\85оÑ\8cллина агÓ\80онан Ñ\85Ñ\8cажоÑ\80г.\n\nÐ¥Ñ\8cовÑ\81алаÑ\88 [[Special:DoubleRedirects|Ñ\88алÑ\85а]] а [[Special:BrokenRedirects|йоÑ\85на Ñ\85Ñ\8cажоÑ\80гаÑ\88]] Ñ\8eй Ñ\82еÑ\85Ñ\8c аÑ\8cлла.\n\nШÑ\83 жоÑ\8cпеÑ\85Ñ\8c дÑ\83 Ñ\85Ñ\8cажоÑ\80гаÑ\88 нийÑ\81а некÑ\8a гойÑ\82Ñ\83Ñ\88 Ñ\85илаÑ\80ан.\n\nТидам бе Ñ\85Ñ\8cалÑ\85алеÑ\80а агÓ\80он Ñ\86Ó\80е â\80\98â\80\99â\80\99Ñ\85ийÑ\86алÑ\83Ñ\80 Ñ\8fÑ\86â\80\99â\80\99â\80\99 иÑ\88Ñ\82Ñ\82а Ñ\86Ó\80е йолÑ\83 агÓ\80о йолÑ\83Ñ\88 елаÑ\85Ñ\8c. ЮкÑ\8aаÑ\80даккÑ\85аÑ\80: йолÑ\83Ñ\88 йолÑ\83 агÓ\80о кÑ\85оÑ\8cÑ\87Ñ\83Ñ\85Ñ\8cа Ñ\85Ñ\8cажоÑ\80г елаÑ\85Ñ\8c, Ñ\8f еÑ\81а елаÑ\85Ñ\8c а, Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аме иÑ\81Ñ\82оÑ\80и Ñ\8fÑ\86аÑ\85Ñ\8c а.\n\nÐ\98 боÑ\85Ñ\83Ñ\80г дÑ\83 Ñ\88Ñ\83н агÓ\80онан Ñ\86Ó\80е Ñ\8eÑ\85а а Ñ\85Ñ\8cалÑ\85а Ñ\85иллаÑ\87Ñ\83н тӀе хийца йиш ю, амма йолуш йолу агӀо дӀаяккха йиш яц.\n\n'''ДӀАХЬЕДАР!'''\n\nЦӀе хийцар бахьнехь гӀаръяьлла агӀонашна дукха дагахь боцу хийцамаш хила тарло. Цундела цӀе хийцале шеш хила тарлучу тӀехьонашах кхета аьлла тешна хила.",
+ "movepagetext-noredirectfixer": "Ð\91Ñ\83Ñ\85аÑ\85Ñ\8c йолÑ\83 Ñ\84оÑ\80манÑ\86а агÓ\80он Ñ\86Ó\80е Ñ\85ийÑ\86ало. ЦÑ\83л Ñ\81овнаÑ\85 Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аман Ñ\82епÑ\82аÑ\80 кÑ\85оÑ\8cÑ\87Ñ\83 меÑ\82Ñ\82е доккÑ\85а. Ð¥Ñ\8cалÑ\85алеÑ\80а Ñ\86Ó\80аÑ\80аÑ\85Ñ\8c Ñ\85иÑ\80Ñ\8aÑ\8e кеÑ\80ла кÑ\85оÑ\8cллина агÓ\80онан Ñ\85Ñ\8cажоÑ\80г.\n\nÐ¥Ñ\8cовÑ\81алаÑ\88 [[Special:DoubleRedirects|Ñ\88алÑ\85а]] а [[Special:BrokenRedirects|йоÑ\85на Ñ\85Ñ\8cажоÑ\80гаÑ\88]] Ñ\8eй Ñ\82еÑ\85Ñ\8c аÑ\8cлла.\n\nШÑ\83 жоÑ\8cпеÑ\85Ñ\8c дÑ\83 Ñ\85Ñ\8cажоÑ\80гаÑ\88 нийÑ\81а некÑ\8a гойÑ\82Ñ\83Ñ\88 Ñ\85илаÑ\80ан.\n\nТидам бе Ñ\85Ñ\8cалÑ\85алеÑ\80а агÓ\80он Ñ\86Ó\80е â\80\98â\80\99â\80\99Ñ\85ийÑ\86алÑ\83Ñ\80 Ñ\8fÑ\86â\80\99â\80\99â\80\99 иÑ\88Ñ\82Ñ\82а Ñ\86Ó\80е йолÑ\83 агÓ\80о йолÑ\83Ñ\88 елаÑ\85Ñ\8c. ЮкÑ\8aаÑ\80даккÑ\85аÑ\80: йолÑ\83Ñ\88 йолÑ\83 агÓ\80о кÑ\85оÑ\8cÑ\87Ñ\83Ñ\85Ñ\8cа Ñ\85Ñ\8cажоÑ\80г елаÑ\85Ñ\8c, Ñ\8f еÑ\81а елаÑ\85Ñ\8c а, Ñ\86Ñ\83Ñ\8cна Ñ\85ийÑ\86аме иÑ\81Ñ\82оÑ\80и Ñ\8fÑ\86аÑ\85Ñ\8c а.\n\nÐ\98 боÑ\85Ñ\83Ñ\80г дÑ\83 Ñ\88Ñ\83н агÓ\80онан Ñ\86Ó\80е Ñ\8eÑ\85а а Ñ\85Ñ\8cалÑ\85а Ñ\85иллаÑ\87Ñ\83н тӀе хийца йиш ю, амма йолуш йолу агӀо дӀаяккха йиш яц.\n\n'''ДӀАХЬЕДАР!'''\n\nЦӀе хийцар бахьнехь гӀаръяьлла агӀонашна дукха дагахь боцу хийцамаш хила тарло. Цундела цӀе хийцале шеш хила тарлучу тӀехьонашах кхета аьлла тешна хила.",
"movepagetalktext": "ТӀе хӀоьттина йолу дийцаре агӀо ишта цӀе хийцина хира ю, '''цхьа йолу ханчохь, маца:'''\n\n*Йаьсса йоцу дийцаре агӀо йолуш ю оцу цӀарца йа\n*Ахьа къастаман харжам цабиняхь а къастам хӀотточехь.\n\nИшта чу ханчохь, ахьа дехьа яккха йезар ю йа куьйга хӀоттайар, нагахь иза хьашт йалахь.",
"movearticle": "ЦӀе хийца агӀон",
"moveuserpage-warning": "'''Тергам бе.''' Хьо декъашхочун агӀона цӀе хийца гӀерта. Дехар до, тергам бе, декъашхочун агӀона цӀе бен хийца лур яц, декъашхочун дӀаяздаран цӀе хийца лур яц.",
"protectedpagemovewarning": "'''ДӀахьедар.''' ХӀара агӀо гӀаролла йина ю; цӀе хийца я нисйа а бакъо йолуш куьйгалхой бе бац.\nЛахахьа тептаро балийна тӀаьхьаралера дӀаязбина хаам:",
"semiprotectedpagemovewarning": "'''ДӀахьедо.''' ХӀара агӀо гӀаролла йина ю; дӀабазбиначу декъашхошка бе цӀе хийцалуш яц.\nЛахахьа тептаро балийна тӀаьхьаралера дӀаязбина хаам:",
"export": "АгӀонаш араяхар",
- "exporttext": "ШÑ\83Ñ\8cга далÑ\83Ñ\80 дÑ\83 кÑ\85еÑ\87Ñ\83 меÑ\82Ñ\82еÑ\80а Ñ\87Ñ\83даÑ\85аÑ\80Ñ\88, йоза а Ñ\85ийÑ\86аме Ñ\82епÑ\82аÑ\80Ñ\88 билгалла йолÑ\83 агÓ\80онаÑ\88 йа гÑ\83лдина йолÑ\83 агÓ\80онаÑ\88 Ñ\85Ó\80окÑ\85 XML баÑ\80амÑ\86а, Ñ\8eÑ\85а Ñ\82Ó\80Ñ\8fÑ\85Ñ\8cа Ñ\87Ñ\83Ñ\80а [[Special:Import|Ñ\85Ñ\8cаÑ\8dÑ\86алÑ\83Ñ\80долÑ\88]] кÑ\85еÑ\87Ñ\83 вики-Ñ\85Ñ\8cалÑ\85ен, болÑ\85 беÑ\88 йолÑ\83 Ñ\85lокÑ\85Ñ\83 MediaWiki гlиÑ\80Ñ\81аÑ\86а.\n\nÐ\9aÑ\85еÑ\87Ñ\83 меÑ\82Ñ\82еÑ\80а Ñ\8fззамаÑ\88 Ñ\87Ñ\83йаÑ\85а, Ñ\87Ñ\83Ñ\8fзйе Ñ\86Ó\80е Ñ\82адеÑ\87Ñ\83 меÑ\82Ñ\82е, Ñ\86Ó\80Ñ\85Ñ\8cа могÓ\80ан Ñ\86Ó\80е могÓ\80аÑ\80Ñ\88каÑ\85Ñ\8c, Ñ\8eÑ\85а Ñ\85аÑ\80жа лаÑ\8cи Ñ\88Ñ\83на Ð\9aÑ\85еÑ\87Ñ\83 меÑ\82Ñ\82еÑ\80 Ñ\87Ñ\83йаÑ\85а маÑ\81Ñ\81о Ñ\8fззамаÑ\88на иÑ\81Ñ\82оÑ\80и Ñ\85ийÑ\86амбаÑ\80Ñ\88 йа Ñ\82Ó\80Ñ\8fÑ\85Ñ\8cаÑ\80алеÑ\80а Ñ\8fззамна баÑ\88Ñ\85о.\n\nШÑ\83Ñ\8cга кÑ\85и даландеÑ\80г, лелаеÑ\88 йолÑ\83 меÑ\82Ñ\82иг кÑ\8aаÑ\81Ñ\82аман маÑ\88ан Ñ\85Ñ\8cажоÑ\80аг кÑ\85еÑ\87Ñ\83 меÑ\82Ñ\82еÑ\80 Ñ\87Ñ\83даÑ\85а Ñ\82Ó\80аÑ\8cÑ\85Ñ\8cаÑ\80леÑ\80аÑ\87Ñ\83 баÑ\88Ñ\85он Ñ\8fззамаÑ\88. Ð\9cаÑ\81ала оÑ\86Ñ\83 Ñ\8fззамна [[{{MediaWiki:Mainpage}}]] Ñ\85Ó\80аÑ\80а Ñ\85иÑ\80а Ñ\8e Ñ\85Ñ\8cажоÑ\80аг [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]].",
+ "exporttext": "ШÑ\83Ñ\8cга далÑ\83Ñ\80 дÑ\83 кÑ\85еÑ\87Ñ\83 меÑ\82Ñ\82еÑ\80а Ñ\87Ñ\83даÑ\85аÑ\80Ñ\88, йоза а Ñ\85ийÑ\86аме Ñ\82епÑ\82аÑ\80Ñ\88 билгалла йолÑ\83 агÓ\80онаÑ\88 йа гÑ\83лдина йолÑ\83 агÓ\80онаÑ\88 Ñ\85Ó\80окÑ\85 XML баÑ\80амÑ\86а, Ñ\8eÑ\85а Ñ\82Ó\80Ñ\8fÑ\85Ñ\8cа Ñ\87Ñ\83Ñ\80а [[Special:Import|Ñ\85Ñ\8cаÑ\8dÑ\86алÑ\83Ñ\80долÑ\88]] кÑ\85еÑ\87Ñ\83 вики-Ñ\85Ñ\8cалÑ\85ен, болÑ\85 беÑ\88 йолÑ\83 Ñ\85lокÑ\85Ñ\83 MediaWiki гlиÑ\80Ñ\81аÑ\86а.\n\nÐ\9aÑ\85еÑ\87Ñ\83 меÑ\82Ñ\82еÑ\80а Ñ\8fззамаÑ\88 Ñ\87Ñ\83йаÑ\85а, Ñ\87Ñ\83Ñ\8fзйе Ñ\86Ó\80е Ñ\82адеÑ\87Ñ\83 меÑ\82Ñ\82е, Ñ\86Ó\80Ñ\85Ñ\8cа могÓ\80ан Ñ\86Ó\80е могÓ\80аÑ\80Ñ\88каÑ\85Ñ\8c, Ñ\8eÑ\85а Ñ\85аÑ\80жа лаÑ\8cи Ñ\88Ñ\83на Ð\9aÑ\85еÑ\87Ñ\83 меÑ\82Ñ\82еÑ\80 Ñ\87Ñ\83йаÑ\85а маÑ\81Ñ\81о Ñ\8fззамаÑ\88на иÑ\81Ñ\82оÑ\80и Ñ\85ийÑ\86амбаÑ\80Ñ\88 йа Ñ\82Ó\80Ñ\8fÑ\85Ñ\8cаÑ\80алеÑ\80а Ñ\8fззамна баÑ\88Ñ\85о.\n\nШÑ\83Ñ\8cга кÑ\85и даландеÑ\80г, лелаеÑ\88 йолÑ\83 меÑ\82Ñ\82иг кÑ\8aаÑ\81Ñ\82аман маÑ\88ан Ñ\85Ñ\8cажоÑ\80г кÑ\85еÑ\87Ñ\83 меÑ\82Ñ\82еÑ\80 Ñ\87Ñ\83даÑ\85а Ñ\82Ó\80аÑ\8cÑ\85Ñ\8cаÑ\80леÑ\80аÑ\87Ñ\83 баÑ\88Ñ\85он Ñ\8fззамаÑ\88. Ð\9cаÑ\81ала оÑ\86Ñ\83 Ñ\8fззамна [[{{MediaWiki:Mainpage}}]] Ñ\85Ó\80аÑ\80а Ñ\85иÑ\80а Ñ\8e Ñ\85Ñ\8cажоÑ\80г [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]].",
"exportall": "Массо агӀонаш экспорт ян",
"exportcuronly": "Карара верси бен юкъа ма тоха, юзийна хьалхалерра истори йоцуш",
"export-submit": "Экспорт ян",
"tooltip-t-upload": "Чуйаха файлаш",
"tooltip-t-specialpages": "Белха агӀонанийн могӀам",
"tooltip-t-print": "Хlокху агlонна зорба туху башхо",
- "tooltip-t-permalink": "Ð\94аима йолÑ\83 Ñ\85Ñ\8cажоÑ\80аг Ñ\85Ó\80окÑ\85Ñ\83 баÑ\88Ñ\85а агÓ\80онна",
+ "tooltip-t-permalink": "Даима йолу хьажорг хӀокху башха агӀонна",
"tooltip-ca-nstab-main": "Яззамна чулацам",
"tooltip-ca-nstab-user": "ХӀора декъашхочун долахь йолу агӀо ю",
"tooltip-ca-nstab-media": "Медиа-файл",
"creditspage": "Баркаллаш",
"nocredits": "Бац декъашхойн могӀам хӀокху яззамца",
"spamprotectiontitle": "Совбиларна литтар",
- "spamprotectiontext": "Ð¥Ñ\8cо дÓ\80аÑ\8fзÑ\8aÑ\8fн гÓ\80еÑ\80Ñ\82а агÓ\80о Ñ\81пам-лиÑ\82Ñ\82аÑ\80о дÓ\80акÑ\8aоÑ\8cвлина.\nЦÑ\83на баÑ\85Ñ\8cна Ñ\85ила Ñ\82ам бÑ\83 агÓ\80она Ñ\87оÑ\85Ñ\8c зÑ\83лам лиÑ\82Ñ\82аÑ\80ан Ñ\87Ñ\83Ñ\82оÑ\8cÑ\85на йолÑ\83 Ñ\85Ñ\8cажоÑ\80аг Ñ\85илаÑ\80.",
+ "spamprotectiontext": "Хьо дӀаязъян гӀерта агӀо спам-литтаро дӀакъоьвлина.\nЦуна бахьна хила там бу агӀона чохь зулам литтаран чутоьхна йолу хьажорг хилар.",
"spambot_username": "Спам дӀацӀаняр",
"pageinfo-title": "Хаамаш цу «$1»",
"pageinfo-not-current": "Шира версийн оьцу хааме хьажа таро яц.",
"saturday-at": "шот дийнахь $1",
"sunday-at": "кӀиранан дийнахь $1",
"yesterday-at": "селхана $1 даьлча",
- "bad_image_list": "Ð\91аÑ\80ам Ñ\85ила беза иÑ\88Ñ\82а:\n\nÐ\9bоÑ\80аÑ\88 Ñ\85иÑ\80а Ñ\8e могÓ\80амÑ\8fÑ\85Ñ\8c йолÑ\83 Ñ\85Ó\80Ñ\83мнаÑ\88 (могÓ\80ийн, йола лÑ\83Ñ\88 йолÑ\83 Ñ\81имвол Ñ\82Ó\80иÑ\80а *).\nÐ\94Ñ\83Ñ\8cÑ\85Ñ\85Ñ\8cаÑ\80алеÑ\80а Ñ\85Ñ\8cажоÑ\80аг магÓ\80аÑ\80Ñ\88и Ñ\85ила беза Ñ\85Ñ\8cажоÑ\80аг кÑ\85Ñ\83 Ñ\86амагдо Ñ\81Ñ\83Ñ\80Ñ\82 дÑ\83Ñ\8cлаÑ\87е.\nТÓ\80Ñ\8fÑ\85Ñ\8cа йогÓ\80Ñ\83Ñ\88 йолÑ\83 Ñ\85Ñ\8cажоÑ\80аг оцу могӀарехь хира ю магóш, билгалла аьлча яззамаш долуче, сурт хьаллаточехь.",
+ "bad_image_list": "Ð\91аÑ\80ам Ñ\85ила беза иÑ\88Ñ\82а:\n\nÐ\9bоÑ\80аÑ\88 Ñ\85иÑ\80а Ñ\8e могÓ\80амÑ\8fÑ\85Ñ\8c йолÑ\83 Ñ\85Ó\80Ñ\83мнаÑ\88 (могÓ\80ийн, йола лÑ\83Ñ\88 йолÑ\83 Ñ\81имвол Ñ\82Ó\80иÑ\80а *).\nÐ\94Ñ\83Ñ\8cÑ\85Ñ\85Ñ\8cаÑ\80алеÑ\80а Ñ\85Ñ\8cажоÑ\80г магÓ\80анийн Ñ\85ила беза Ñ\85Ñ\8cажоÑ\80г кÑ\85Ñ\83 Ñ\86амагдо Ñ\81Ñ\83Ñ\80Ñ\82 дÑ\83Ñ\8cлаÑ\87е.\nТÓ\80Ñ\8fÑ\85Ñ\8cа йогÓ\80Ñ\83Ñ\88 йолÑ\83 Ñ\85Ñ\8cажоÑ\80г оцу могӀарехь хира ю магóш, билгалла аьлча яззамаш долуче, сурт хьаллаточехь.",
"metadata": "Метахаамаш",
"metadata-help": "ХӀокху файлаца кхин тӀе хаам бу, даиман чуйоккхуш йолу терахьца чоьнашца йа тӀейоккхучуьнца. Нагахь файлан тӀаьхьа хийцам биняхь, тӀаккха цӀхьаболу барам цӀхьаьна ца ба мега хӀинцалера суьртаца.",
"metadata-expand": "Гайта кхин тlе болу хаам",
"tog-shownumberswatching": "Zobrazovat počet sledujících uživatelů",
"tog-oldsig": "Stávající podpis:",
"tog-fancysig": "Používat v podpisu wikitext (bez automatického odkazu)",
- "tog-uselivepreview": "Používat rychlý náhled (experimentální)",
+ "tog-uselivepreview": "Používat rychlý náhled",
"tog-forceeditsummary": "Upozornit, když nevyplním shrnutí editace",
"tog-watchlisthideown": "Na seznamu sledovaných stránek skrýt moje editace",
"tog-watchlisthidebots": "Na seznamu sledovaných stránek skrýt editace botů",
"anoneditwarning": "'''Varování:''' Nejste přihlášen(a). Pokud uložíte jakoukoli editaci, bude vaše IP adresa zveřejněna v historii této stránky. Pokud se <strong>[$1 přihlásíte]</strong> nebo si <strong>[$2 vytvoříte účet]</strong>, budou vaše editace připsány vašemu uživatelskému jménu a získáte i další výhody.",
"anonpreviewwarning": "''Nejste přihlášen(a). Uložením zveřejníte svou IP adresu v historii této stránky.''",
"missingsummary": "'''Připomenutí:''' Nezadali jste shrnutí editace. Pokud ještě jednou kliknete na Uložit změny, bude vaše editace zapsána bez shrnutí.",
+ "selfredirect": "<strong>Upozornění:</strong> Vytváříte přesměrování na týž článek. Pokud ještě jednou kliknete na „{{int:savearticle}}“, bude přesměrování vytvořeno.",
"missingcommenttext": "Zadejte komentář",
"missingcommentheader": "'''Připomenutí:''' Nezadali jste předmět/nadpis pro tento komentář.\nPokud ještě jednou kliknete na „{{int:savearticle}}“, bude vaše editace zapsána i bez toho.",
"summary-preview": "Náhled shrnutí:",
"log-name-pagelang": "Kniha změn jazyků",
"log-description-pagelang": "Toto je protokol změn jazyků stránek.",
"logentry-pagelang-pagelang": "$1 {{GENDER:$2|změnil|změnila}} jazyk stránky $3 z $4 na $5.",
- "default-skin-not-found": "Jejda! Výchozí vzhled vaší wiki, definovaný ve <code dir=\"ltr\">$wgDefaultSkin</code> jako <code>$1</code>, není dostupný.\n\nVaše instalace zřejmě obsahuje následující vzhledy. Informace o tom, jak je povolit a vybrat výchozí, najdete na stránce [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_configuration/cs Manual:Skin configuration].\n\n$2\n\n; Pokud jste právě nainstalovali MediaWiki:\n: Zřejmě jste instalovali z gitu nebo nějakým jiným způsobem přímo ze zdrojového kódu. Tak to má fungovat. Zkuste nainstalovat některé vzhledy ze [https://www.mediawiki.org/wiki/Category:All_skins seznamu vzhledů na mediawiki.org] buď:\n:* Můžete si stáhnout [https://www.mediawiki.org/wiki/Download/cs instalace v tarballu], která zahrnuje několik vzhledů a rozšíření, a vykopírovat si z ní adresář <code dir=\"ltr\">skins/</code>, nebo\n:* Nebo si můžete gitem naklonovat jeden z repozitářů <code>mediawiki/skins/*</code> do adresáře <code>skins/</code> ve vaší instalaci MediaWiki.\n: Pokud jste vývojářem MediaWiki, nemělo by to nijak narušit váš gitový repozitář.\n\n; Pokud jste právě aktualizovali MediaWiki:\n: MediaWiki 1.24 a novější již automaticky nepovolují nainstalované vzhledy (vizte [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_autodiscovery/cs Manual:Skin autodiscovery]). Pro povolení všech právě nainstalovaných vzhledů vlepte následující řádky do <code>LocalSettings.php</code>:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Pokud jste právě upravili <code>LocalSettings.php</code>:\n: Překontrolujte případné překlepy v názvech vzhledů.",
- "default-skin-not-found-no-skins": "Jejda! Výchozí vzhled vaší wiki, definovaný ve <code dir=\"ltr\">$wgDefaultSkin</code> jako <code>$1</code>, není dostupný.\n\nNemáte nainstalovány žádné vzhledy.\n\n; Pokud jste právě nainstalovali nebo aktualizovali MediaWiki:\n: Zřejmě jste instalovali z gitu nebo nějakým jiným způsobem přímo ze zdrojového kódu. Tak to má fungovat. MediaWiki 1.24 a novější již v hlavním repozitáři neobsahují žádné vzhledy. Zkuste nainstalovat některé vzhledy ze [https://www.mediawiki.org/wiki/Category:All_skins seznamu vzhledů na mediawiki.org] buď:\n:* Můžete si stáhnout [https://www.mediawiki.org/wiki/Download/cs instalace v tarballu], která zahrnuje několik vzhledů a rozšíření, a vykopírovat si z ní adresář <code>skins/</code>, nebo\n:* Nebo si můžete gitem naklonovat jeden z repozitářů <code>mediawiki/skins/*</code> do adresáře <code dir=\"ltr\">skins/</code> ve vaší instalaci MediaWiki.\n: Pokud jste vývojářem MediaWiki, nemělo by to nijak narušit váš gitový repozitář. Informace o tom, jak povolit vzhledy a vybrat výchozí, najdete na stránce [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_configuration/cs Manual:Skin configuration].",
+ "default-skin-not-found": "Jejda! Výchozí vzhled vaší wiki, definovaný ve <code dir=\"ltr\">$wgDefaultSkin</code> jako <code>$1</code>, není dostupný.\n\nVaše instalace zřejmě obsahuje následující vzhledy. Informace o tom, jak je povolit a vybrat výchozí, najdete na stránce [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_configuration/cs Manual:Skin configuration].\n\n$2\n\n; Pokud jste právě nainstalovali MediaWiki:\n: Zřejmě jste instalovali z gitu nebo nějakým jiným způsobem přímo ze zdrojového kódu. Tak to má fungovat. Zkuste nainstalovat některé vzhledy ze [https://www.mediawiki.org/wiki/Category:All_skins seznamu vzhledů na mediawiki.org] buď:\n:* Můžete si stáhnout [https://www.mediawiki.org/wiki/Download/cs instalaci v tarballu], která zahrnuje několik vzhledů a rozšíření, a vykopírovat si z ní adresář <code dir=\"ltr\">skins/</code>.\n:* Nebo si můžete stáhnout tarbally jednotlivých vzhledů z [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* Nebo si můžete gitem naklonovat jeden z repozitářů <code>mediawiki/skins/*</code> do adresáře <code>skins/</code> ve vaší instalaci MediaWiki.\n: Pokud jste vývojářem MediaWiki, nemělo by to nijak narušit váš gitový repozitář.\n\n; Pokud jste právě aktualizovali MediaWiki:\n: MediaWiki 1.24 a novější již automaticky nepovolují nainstalované vzhledy (vizte [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_autodiscovery/cs Manual:Skin autodiscovery]). Pro povolení všech právě nainstalovaných vzhledů vlepte následující řádky do <code>LocalSettings.php</code>:\n\n<pre dir=\"ltr\">$3</pre>\n\n; Pokud jste právě upravili <code>LocalSettings.php</code>:\n: Překontrolujte případné překlepy v názvech vzhledů.",
+ "default-skin-not-found-no-skins": "Jejda! Výchozí vzhled vaší wiki, definovaný ve <code dir=\"ltr\">$wgDefaultSkin</code> jako <code>$1</code>, není dostupný.\n\nNemáte nainstalovány žádné vzhledy.\n\n; Pokud jste právě nainstalovali nebo aktualizovali MediaWiki:\n: Zřejmě jste instalovali z gitu nebo nějakým jiným způsobem přímo ze zdrojového kódu. Tak to má fungovat. MediaWiki 1.24 a novější již v hlavním repozitáři neobsahují žádné vzhledy. Zkuste nainstalovat některé vzhledy ze [https://www.mediawiki.org/wiki/Category:All_skins seznamu vzhledů na mediawiki.org] buď:\n:* Můžete si stáhnout [https://www.mediawiki.org/wiki/Download/cs instalaci v tarballu], která zahrnuje několik vzhledů a rozšíření, a vykopírovat si z ní adresář <code>skins/</code>.\n:* Nebo si můžete stáhnout tarbally jednotlivých vzhledů z [https://www.mediawiki.org/wiki/Special:SkinDistributor mediawiki.org].\n:* Nebo si můžete gitem naklonovat jeden z repozitářů <code>mediawiki/skins/*</code> do adresáře <code dir=\"ltr\">skins/</code> ve vaší instalaci MediaWiki.\n: Pokud jste vývojářem MediaWiki, nemělo by to nijak narušit váš gitový repozitář. Informace o tom, jak povolit vzhledy a vybrat výchozí, najdete na stránce [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Skin_configuration/cs Manual:Skin configuration].",
"default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (povolený)",
"default-skin-not-found-row-disabled": "* <code>$1</code> / $2 ('''zakázaný''')",
"mediastatistics": "Statistika souborů",
"anoneditwarning": "<strong>Warnung:</strong> Du bist nicht angemeldet. Deine IP-Adresse wird öffentlich sichtbar, falls du Bearbeitungen durchführst. Wenn du dich <strong>[$1 anmeldest]</strong> oder <strong>[$2 ein Benutzerkonto erstellst]</strong>, werden deine Bearbeitungen zusammen mit anderen Beiträgen deinem Benutzernamen zugeordnet.",
"anonpreviewwarning": "''Du bist nicht angemeldet. Beim Speichern wird deine IP-Adresse in der Versionsgeschichte aufgezeichnet.''",
"missingsummary": "'''Hinweis:''' Du hast keine Zusammenfassung angegeben. Wenn du erneut auf „{{int:savearticle}}“ klickst, wird deine Änderung ohne Zusammenfassung übernommen.",
+ "selfredirect": "<strong>Warnung:</strong> Du erstellst eine Weiterleitung auf den gleichen Artikel.\nWenn du erneut auf „{{int:savearticle}}“ klickst, wird die Weiterleitung erstellt.",
"missingcommenttext": "Dein Abschnitt enthält keinen Text.",
"missingcommentheader": "'''Achtung:''' Du hast kein Betreff/Überschrift eingegeben. Wenn du erneut auf „{{int:savearticle}}“ klickst, wird deine Bearbeitung ohne Überschrift gespeichert.",
"summary-preview": "Vorschau der Zusammenfassungszeile:",
"tog-shownumberswatching": "Fà vèder al nómer ed j utèint che gh'àn la pàgina sòta uservasiòun",
"tog-oldsig": "La fîrma 'd adèsa",
"tog-fancysig": "Trâta la fîrma cme wikitèst (sèinsa colegamèint avtomâtich)",
- "tog-uselivepreview": "Permèt la funsiòun \"Live preview\" (guêrda préma 'd salvêr dal vîv - in sperimèint)",
+ "tog-uselivepreview": "Permèt la funsiòun \"Live preview\" (guêrda préma 'd salvêr in dirèta)",
"tog-forceeditsummary": "Dmânda s'l'è vèira che al câmp argumèint l' é vōd",
"tog-watchlisthideown": "Lōga al mé mudéfichi int i tgnû 'd ôc specêl",
"tog-watchlisthidebots": "Lōga al mudéfichi di bot int i tgnû 'd ôc specêl",
"anoneditwarning": "<strong>Atèinti:</strong> An n'é mìa stê fât l'ingrès. S' ét farê dal mudéfichi al tó indirés IP al srà vést da tót. Se <strong>[$1 và dèinter]</strong> o <strong>[$2 fà 'n' utèinsa]</strong>, al tô mudéfichi a srân sgnêdi al tó nòm utèint, insèm a êter benefési.",
"anonpreviewwarning": "\"An n'é mìa stê fât l'ingrès. Mèinter es sêlva la pàgina, l'indirés IP al srà sgnê int la stòria 'd la pàgina.\"",
"missingsummary": "'''Atensiòun:''' an n'é mìa stê precişê al mutîv de sté mudéfica. S'es tōrna a clichêr insém a \"{{int:savearticle}}\" la mudéfica la gnirà salvêda cun al mutîv vōd.",
+ "selfredirect": "<strong>Ateinti:</strong>t'é drē fêr un rinvéi a l'istèsa vōş. S'ét fê cléch incòra in sém a \"{{int:savearticle}}\", al rinvéi al gnirà fât",
"missingcommenttext": "Scréver un cumèint ché sòta.",
"missingcommentheader": "'''Atensiòun:''' an n'é mìa stê precişê al mutîv/al tétol de sté mudéfica. S'es tōrna a clichêr insém a \"{{int:savearticle}}\" la mudéfica la gnirà salvêda sèinsa tétol.",
"summary-preview": "Guêrda préma sûnt:",
"right-editmyprivateinfo": "Câmbia 'l tō infurmasiòun personêli (per eşèimpi: indirés ed pôsta eletrônica, nòm vèira)",
"right-editmyoptions": "Câmbia al tō preferèinsi",
"right-rollback": "Scanşèla a la şvêlta al mudéfichi ed l'ûltèint ch'l'à mudifichê 'na pàgina pariculêra",
+ "right-markbotedits": "Sègna al mudéfichi da turnêr a mèter cme préma cme fâti da 'na mâchina in avtomâtich",
+ "right-noratelimit": "An n'é mìa ublighê al lémit 'd asiòun",
+ "right-import": "Côpia dal pàgini da 'd j êter wiki",
"newuserlogpage": "Utèint nōv",
"action-read": "lēzer cla pàgina ché",
"action-edit": "Mudifichêr cla pàgina ché",
"specialpages": "Páginas especiales",
"specialpages-note-top": "Leyenda",
"specialpages-note": "* Páginas especiales normales\n* <span class=\"mw-specialpagerestricted\">Páginas especiales restringidas.</span>\n* <span class=\"mw-specialpagecached\">Páginas especiales en caché (podrían ser obsoletas).</span>",
- "specialpages-group-maintenance": "Reportes de mantenimiento",
+ "specialpages-group-maintenance": "Informes de mantenimiento",
"specialpages-group-other": "Otras páginas especiales",
"specialpages-group-login": "Acceder/crear cuenta",
"specialpages-group-changes": "Cambios recientes y registros",
"anoneditwarning": "<strong>Varoitus:</strong> Et ole kirjautunut sisään. IP-osoitteesi näkyy julkisesti kaikille, jos muokkaat. Jos <strong>[$1 kirjaudut sisään]</strong> tai <strong>[$2 luot tunnuksen]</strong>, muokkauksesi kirjataan käyttäjätunnuksesi tekemiksi ja samalla saat käyttöösi hyödyllisiä välineitä.",
"anonpreviewwarning": "''Et ole kirjautunut sisään. Tallentaminen kirjaa IP-osoitteesi tämän sivun muutoshistoriaan.''",
"missingsummary": "Et ole antanut yhteenvetoa. Jos valitset Tallenna uudelleen, niin muokkauksesi tallennetaan ilman yhteenvetoa.",
+ "selfredirect": "<strong>Varoitus:</strong> Olet tekemässä uudelleenohjausta samaan artikkeliin. Jos painat toimintoa \"{{int:savearticle}}\" uudestaan, tämä ohjaussivu luodaan.",
"missingcommenttext": "Kirjoita viesti alle.",
"missingcommentheader": "Et ole antanut otsikkoa kommentillesi. Napsauta ”{{int:savearticle}}”, jos et halua antaa otsikkoa.",
"summary-preview": "Yhteenvedon esikatselu:",
"content-model-javascript": "JavaScript",
"content-model-css": "CSS",
"duplicate-args-category": "Sivut, jotka käyttävät kaksinkertaisia argumentteja mallinekutsuissa",
+ "duplicate-args-category-desc": "Tämä sivu sisältää sellaisia mallinekutsuja, jotka käyttävät kaksi kertaa samaa argumenttia kuten <nowiki>{{foo|bar=1|bar=2}}</nowiki></code> taikka <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
"expensive-parserfunction-warning": "Tällä sivulla on liian monta hitaiden laajennusfunktioiden kutsua.\nKutsuja pitäisi olla alle $2 {{PLURAL:$2|kappale|kappaletta}}, mutta nyt niitä on $1 {{PLURAL:$1|kappale|kappaletta}}.",
"expensive-parserfunction-category": "Sivut, joissa on liian monta vaativaa jäsenninfunktiota",
"post-expand-template-inclusion-warning": "'''Varoitus:''' Sisällytettyjen mallineiden koko on liian suuri.\nJoitakin mallineita ei ole sisällytetty.",
"expand_templates_generate_xml": "Näytä XML-jäsennyspuu",
"expand_templates_generate_rawhtml": "Näytä raaka HTML",
"expand_templates_preview": "Esikatselu",
+ "expand_templates_preview_fail_html": "<em>Koska sivustolla {{SITENAME}} on käytössä puhdas HTML-koodi ja koska istunnon tiedot ovat kadonneet, esikatselu on piilotettu JavaScript-hyökkäyksien torjumiseksi.</em>\n\n<strong>Jos olet oikealla asialla, yritä uudestaan.</strong>\nJos esikatselu ei vieläkään toimi, kokeile [[Special:UserLogout|kirjautua ulos]] ja sen jälkeen kirjaudu uudestaan sisään.",
+ "expand_templates_preview_fail_html_anon": "<em>Koska sivustolla {{SITENAME}} on käytössä puhdas HTML-koodi ja koska et ole kirjautunut sisään, esikatselu on piilotettu JavaScript-hyökkäyksien torjumiseksi.</em>\n\n<strong>Jos olet oikealla asialla, [[Special:UserLogin|kirjaudu sisään]] ja yritä uudestaan.</strong>",
"pagelanguage": "Sivun kielen valinta",
"pagelang-name": "Sivu",
"pagelang-language": "Kieli",
"anoneditwarning": "<strong>Attention :</strong> Vous n’êtes pas connecté. Votre adresse IP sera visible de tout le monde si vous faites des modifications. Si vous <strong>[$1 vous connectez]</strong> ou <strong>[$2 créez un compte]</strong>, vos modifications seront attribuées à votre nom d’utilisateur, entre autres avantages.",
"anonpreviewwarning": "''Vous n’êtes pas identifié(e). Sauvegarder enregistrera votre adresse IP dans l’historique des modifications de la page.''",
"missingsummary": "'''Rappel :''' vous n'avez pas encore fourni le résumé de votre modification.\nSi vous cliquez de nouveau sur le bouton « {{int:savearticle}} », la publication sera faite sans nouvel avertissement.",
+ "selfredirect": "<strong>Attention :</strong> Vous êtes en train de créer une redirection vers le même article.\nSi vous cliquez de nouveau sur « {{int:savearticle}} », la redirection sera créée.",
"missingcommenttext": "Veuillez entrer un commentaire ci-dessous.",
"missingcommentheader": "'''Rappel :''' vous n'avez pas fourni de sujet ou de titre à ce commentaire.\nSi vous cliquez de nouveau sur « {{int:Savearticle}} », votre modification sera enregistrée sans titre.",
"summary-preview": "Aperçu du résumé :",
"tog-shownumberswatching": "Mostrar o número de usuarios que están a vixiar",
"tog-oldsig": "Sinatura actual:",
"tog-fancysig": "Tratar a sinatura como se fose texto wiki (sen ligazón automática)",
- "tog-uselivepreview": "Usar a vista previa en tempo real (experimental)",
+ "tog-uselivepreview": "Usar a vista previa en tempo real",
"tog-forceeditsummary": "Avisádeme cando o campo resumo estea baleiro",
"tog-watchlisthideown": "Agochar as edicións propias na lista de vixilancia",
"tog-watchlisthidebots": "Agochar as edicións dos bots na lista de vixilancia",
"anoneditwarning": "<strong>Aviso:</strong> Non accedeu ao sistema. O seu enderezo IP será rexistado no histórico de edicións desta páxina. Se <strong>[$1 accede ao sistema]</strong> ou <strong>[$2 crea unha conta]</strong>, as súas edicións serán rexistadas co seu nome de usuario, ademais doutros beneficios.",
"anonpreviewwarning": "''Non accedeu ao sistema. Se garda a páxina, o seu enderezo IP quedará rexistrado no historial de edicións.''",
"missingsummary": "'''Aviso:''' Esqueceu incluír o texto do campo resumo.\nSe preme en \"{{int:savearticle}}\" a súa edición gardarase sen ningunha descrición da edición.",
+ "selfredirect": "<strong>Atención:</strong> Está a crear unha redireción cara o mesmo artigo. Se preme \"{{int:savearticle}}\" de novo, crearase a redireción.",
"missingcommenttext": "Por favor, escriba un comentario a continuación.",
"missingcommentheader": "'''Aviso:''' Non escribiu ningún texto no asunto/título deste comentario.\nSe preme sobre \"{{int:savearticle}}\", a súa edición gardarase sen el.",
"summary-preview": "Vista previa do resumo:",
"protectedpagetext": "Ova stranica je zaključana da bi se onemogućile izmjene.",
"viewsourcetext": "Možete pogledati i kopirati izvorni sadržaj ove stranice:",
"viewyourtext": "Možete vidjeti i kopirati tekst '''vaših uređivanja''' na ovoj stranici:",
- "protectedinterface": "Ova stranica je zaštićena od izmjena jer sadrži tekst MediaWiki softvera.\nAKo želite prevesti neprevedenu poruku ili popraviti prijevod neke druge poruke za sve MediaWiki wikije, posjetite [//translatewiki.net/ translatewiki.net], projekt za lokalizaciju MediaWiki softvera.",
+ "protectedinterface": "Ova stranica je zaštićena od izmjena jer sadrži tekst MediaWiki softvera.\nAko želite prevesti neprevedenu poruku ili popraviti prijevod neke druge poruke za sve MediaWiki wikije, posjetite [//translatewiki.net/ translatewiki.net], projekt za lokalizaciju MediaWiki softvera.",
"editinginterface": "'''Upozorenje:''' Uređujete stranicu koja se rabi za prikaz teksta u sučelju softvera. Promjene učinjene na ovoj stranici će se odraziti na izgled korisničkog sučelja kod drugih suradnika. Za prijevod, razmotrite uporabu [//translatewiki.net/wiki/Main_Page?setlang=hr translatewiki.net], projekta lokalizacije MedijeWiki.",
+ "translateinterface": "Za dodavanje ili promjenu prijevoda za sve wikije koristite [//translatewiki.net/ translatewiki.net], projekt za lokalizaciju MediaWikija.",
"cascadeprotected": "Ova je stranica zaključana za uređivanja jer je uključena u {{PLURAL:$1|slijedeću stranicu|slijedeće stranice}}, koje su zaštićene \"prenosivom zaštitom\":\n$2",
"namespaceprotected": "Ne možete uređivati stranice u imenskom prostoru '''$1'''.",
"customcssprotected": "Ne možete uređivati ovu CSS stranicu zato što ona sadrži osobne postavke drugog suradnika.",
"download": "skidanje",
"unwatchedpages": "Nepraćene stranice",
"listredirects": "Popis preusmjeravanja",
+ "listduplicatedfiles": "Popis kopija datoteka",
+ "listduplicatedfiles-summary": "Ovo je popis datoteka kojima je zadnja inačica kopija zadnje inačice druge datoteke. Na popisu su samo lokalno postavljene datoteke.",
"unusedtemplates": "Nekorišteni predlošci",
"unusedtemplatestext": "Slijedi popis svih stranica imenskog prostora {{ns:template}}, koje nisu umetnute na drugim stranicama. Pripazite da prije brisanja provjerite druge poveznice koje vode na te predloške.",
"unusedtemplateswlh": "druge poveznice",
"pageinfo-category-pages": "Broj stranica",
"pageinfo-category-subcats": "Broj podkategorija",
"pageinfo-category-files": "Broj datoteka",
- "markaspatrolleddiff": "Označi za pregledano",
+ "markaspatrolleddiff": "Označi pregledanim",
"markaspatrolledtext": "Označi ovaj članak pregledanim",
"markedaspatrolled": "Pregledano",
"markedaspatrolledtext": "Odabrana promjena [[:$1]] označena je pregledanom.",
"expand_templates_remove_comments": "Ukloni komentare",
"expand_templates_remove_nowiki": "Ukloni <nowiki> tagove u rezultatima.",
"expand_templates_generate_xml": "Prikaži XML stablo",
- "expand_templates_preview": "Vidi kako će izgledati"
+ "expand_templates_preview": "Vidi kako će izgledati",
+ "mediastatistics": "Statistika datoteka",
+ "mediastatistics-summary": "Slijede statistike postavljenih datoteka koje pokazuju zadnju inačicu datoteke. Starije ili izbrisane inačice nisu prikazane."
}
"anoneditwarning": "<strong>Attenzione:</strong> Accesso non effettuato. Se effettuerai delle modifiche il tuo indirizzo IP sarà visibile pubblicamente. Se <strong>[$1 accedi]</strong> o <strong>[$2 crei un'utenza]</strong>, le tue modifiche saranno attribuite al tuo nome utente, insieme ad altri benefici.",
"anonpreviewwarning": "''Non è stato eseguito il login. Salvando la pagina, il proprio indirizzo IP sarà registrato nella cronologia.''",
"missingsummary": "'''Attenzione:''' non è stato specificato l'oggetto di questa modifica. Premendo di nuovo \"{{int:savearticle}}\" la modifica verrà salvata con l'oggetto vuoto.",
+ "selfredirect": "<strong>Attenzione:</strong> stai creando un redirect alla medesima voce.\nSe fai clic nuovamente su \"{{int:savearticle}}\", il redirect sarà creato.",
"missingcommenttext": "Inserire un commento qui sotto.",
"missingcommentheader": "'''Attenzione:''' non è stata specificato l'oggetto/l'intestazione di questo commento. Premendo di nuovo \"{{int:savearticle}}\" la modifica verrà salvata senza intestazione.",
"summary-preview": "Anteprima dell'oggetto:",
"tog-shownumberswatching": "მაკონტროლებელ მომხმარებელთა რიცხვის ჩვენება",
"tog-oldsig": "არსებული ხელმოწერა:",
"tog-fancysig": "საკუთარი ვიკიფორმატიანი ხელმოწერა (ავტომატური ბმულის გარეშე)",
- "tog-uselivepreview": "გამოიყენეთ სწრაფი წინასწარი გადახედვა (ექსპერიმენტული)",
+ "tog-uselivepreview": "გამოიყენეთ სწრაფი წინასწარი გადახედვა",
"tog-forceeditsummary": "გამაფრთხილე ცარიელი რედაქტირების რეზიუმეს შემთხვევაში",
"tog-watchlisthideown": "დამალე ჩემი რედაქტირება კონტროლის სიაში",
"tog-watchlisthidebots": "დამალე რობოტის რედაქტირება კონტროლის სიაში",
"permalink": "მუდმივი ბმული",
"print": "ამობეჭდე",
"view": "იხილე",
+ "view-foreign": "იხილეთ $1-ზე",
"edit": "რედაქტირება",
"edit-local": "ლოკალური აღწერის რედაქტირება",
"create": "შექმნა",
"otherlanguages": "სხვა ენებზე",
"redirectedfrom": "(გადმომისამართდა $1-დან)",
"redirectpagesub": "გადამისამართება გვერდზე",
+ "redirectto": "გადამისამართება:",
"lastmodifiedat": "ეს გვერდი ბოლოს განახლდა $2, $1.",
"viewcount": "ეს გვერდი შემოწმდა {{PLURAL:$1|ერთხელ|$1-ჯერ}}.",
"protectedpage": "დაბლოკილი გვერდი",
"viewsourcetext": "თქვენ შეგიძლიათ ნახოთ ამ გვერდის საწყისი ფაილი და მისი ასლი შექმნათ:",
"viewyourtext": "თქვენ შეგიძლიათ იხილოთ და დააკოპიროთ '''თქვენი რედაქტირებების''' საწყისი ტექსტი ამ გვერდზე:",
"protectedinterface": "ეს გვერდი წარმოადგენს ტექსტურ ინტერფეისს პროგრამული უზრუნველყოფისათვის და დაცულია ვანდალიზმის აღკვეთის მიზნით.",
- "editinginterface": "'''á\83§á\83£á\83 á\83\90á\83\93á\83¦á\83\94á\83\91á\83\90:''' á\83\97á\83¥á\83\95á\83\94á\83\9c á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\9dá\83 á\83\9dá\83\91á\83\97 á\83\92á\83\95á\83\94á\83 á\83\93á\83¡, á\83 á\83\9dá\83\9bá\83\94á\83\9aá\83\98á\83ª á\83\9eá\83 á\83\9dá\83\92á\83 á\83\90á\83\9bá\83\98á\83¡ á\83\98á\83\9cá\83¢á\83\94á\83 á\83¤á\83\94á\83\98á\83¡á\83\98á\83¡ á\83¢á\83\94á\83¥á\83¡á\83¢á\83¡ á\83¨á\83\94á\83\98á\83ªá\83\90á\83\95á\83¡. \ná\83\90á\83\9b á\83\92á\83\95á\83\94á\83 á\83\93á\83\96á\83\94 á\83\92á\83\90á\83\9cá\83®á\83\9dá\83 á\83ªá\83\98á\83\94á\83\9aá\83\94á\83\91á\83£á\83\9aá\83\98 á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\98á\83 á\83\94á\83\91á\83\90 á\83\92á\83\90á\83\9bá\83\9dá\83\98á\83¬á\83\95á\83\94á\83\95á\83¡ á\83\90á\83\9b á\83\95á\83\98á\83\99á\83\98á\83¡ á\83¡á\83®á\83\95á\83\90 á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\97á\83\90 á\83¡á\83\90á\83\9bá\83£á\83¨á\83\90á\83\9d á\83\98á\83\9cá\83¢á\83\94á\83 á\83¤á\83\94á\83\98á\83¡á\83\98á\83¡ á\83¨á\83\94á\83ªá\83\95á\83\9aá\83\90á\83¡á\83\90á\83ª. \ná\83\98á\83\9bá\83\98á\83¡á\83\90á\83\97á\83\95á\83\98á\83¡, á\83 á\83\9dá\83\9b á\83\93á\83\90á\83\90á\83\9bá\83\90á\83¢á\83\9dá\83\97 á\83\90á\83\9c á\83¨á\83\94á\83ªá\83\95á\83\90á\83\9aá\83\9dá\83\97 á\83\97á\83\90á\83 á\83\92á\83\9bá\83\90á\83\9cá\83\94á\83\91á\83\98 á\83§á\83\95á\83\94á\83\9aá\83\90 á\83\95á\83\98á\83\99á\83\98á\83¨á\83\98 გთხოვთ, გამოიყენოთ მედიავიკის ლოკალიზაციის პროექტი [//translatewiki.net/ translatewiki.net].",
+ "editinginterface": "'''á\83§á\83£á\83 á\83\90á\83\93á\83¦á\83\94á\83\91á\83\90:''' á\83\97á\83¥á\83\95á\83\94á\83\9c á\83\90á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\98á\83 á\83\94á\83\91á\83\97 á\83\92á\83\95á\83\94á\83 á\83\93á\83¡, á\83 á\83\9dá\83\9bá\83\94á\83\9aá\83\98á\83ª á\83\9eá\83 á\83\9dá\83\92á\83 á\83\90á\83\9bá\83\98á\83¡ á\83\98á\83\9cá\83¢á\83\94á\83 á\83¤á\83\94á\83\98á\83¡á\83\98á\83¡ á\83¢á\83\94á\83¥á\83¡á\83¢á\83¡ á\83¨á\83\94á\83\98á\83ªá\83\90á\83\95á\83¡. \ná\83\90á\83\9b á\83\92á\83\95á\83\94á\83 á\83\93á\83\96á\83\94 á\83\92á\83\90á\83\9cá\83®á\83\9dá\83 á\83ªá\83\98á\83\94á\83\9aá\83\94á\83\91á\83£á\83\9aá\83\98 á\83 á\83\94á\83\93á\83\90á\83¥á\83¢á\83\98á\83 á\83\94á\83\91á\83\90 á\83\92á\83\90á\83\9bá\83\9dá\83\98á\83¬á\83\95á\83\94á\83\95á\83¡ á\83\90á\83\9b á\83\95á\83\98á\83\99á\83\98á\83¡ á\83¡á\83®á\83\95á\83\90 á\83\9bá\83\9dá\83\9bá\83®á\83\9bá\83\90á\83 á\83\94á\83\91á\83\94á\83\9aá\83\97á\83\90 á\83¡á\83\90á\83\9bá\83£á\83¨á\83\90á\83\9d á\83\98á\83\9cá\83¢á\83\94á\83 á\83¤á\83\94á\83\98á\83¡á\83\98á\83¡ á\83¨á\83\94á\83ªá\83\95á\83\9aá\83\90á\83¡á\83\90á\83ª. \ná\83\98á\83\9bá\83\98á\83¡á\83\90á\83\97á\83\95á\83\98á\83¡, á\83 á\83\9dá\83\9b á\83\93á\83\90á\83\90á\83\9bá\83\90á\83¢á\83\9dá\83\97 á\83\90á\83\9c á\83¨á\83\94á\83ªá\83\95á\83\90á\83\9aá\83\9dá\83\97 á\83\97á\83\90á\83 á\83\92á\83\9bá\83\90á\83\9cá\83\94á\83\91á\83\98 á\83§á\83\95á\83\94á\83\9aá\83\90 á\83\95á\83\98á\83\99á\83\98á\83¨á\83\98, გთხოვთ, გამოიყენოთ მედიავიკის ლოკალიზაციის პროექტი [//translatewiki.net/ translatewiki.net].",
"cascadeprotected": "ეს გვერდი რედაქტირებისგან დაცულია, რადგან იგი ჩართულია შემდეგ {{PLURAL:$1|გვერდში, რომლის |გვერდებში, რომელთა}} დასაცავადაც ჩართულია პარამეტრი \"იერარქიული\":\n$2",
"namespaceprotected": "თქვენ არ გაქვთ '''$1''' სახელთა სივრცეში გვერდების რედაქტირების უფლება.",
"customcssprotected": "თქვენ არ გაქვთ ამ CSS გვერდის რედაქტირების უფლება, ვინაიდან ის სხვა მომხმარებლის პირად კონფიგურაციას შეიცავს.",
"tog-shownumberswatching": "D'Zuel vun de Benotzer déi dës Säit iwwerwaache weisen",
"tog-oldsig": "Aktuell Ënnerschrëft:",
"tog-fancysig": "Ënnerschrëft als Wiki-Text behandelen (Ouni automatesche Link)",
- "tog-uselivepreview": "Live-Preview benotzen (experimentell)",
+ "tog-uselivepreview": "Live-Preview benotzen",
"tog-forceeditsummary": "Warnen, wa beim Späicheren de Resumé feelt",
"tog-watchlisthideown": "Meng Ännerungen op menger Iwwerwaachungslëscht verstoppen",
"tog-watchlisthidebots": "Ännerunge vu Botten op menger Iwwerwaachungslëscht verstoppen",
"tog-shownumberswatching": "Прикажи го бројот на корисници кои набљудуваат",
"tog-oldsig": "Постоечки потпис:",
"tog-fancysig": "Сметај го потписот за викитекст (без автоматска врска)",
- "tog-uselivepreview": "Користи преглед во живо (експериментално)",
+ "tog-uselivepreview": "Користи преглед во живо",
"tog-forceeditsummary": "Извести ме кога нема опис на промените",
"tog-watchlisthideown": "Скриј мои уредувања од списокот на набљудувања",
"tog-watchlisthidebots": "Скриј ботовски уредувања од списокот на набљудувања",
"anoneditwarning": "<strong>Предупредување:</strong> Не сте најавени. Вашата IP-адреса ќе биде јавно видлива ако уредувате. Ако <strong>[$1 се најавите]</strong> или <strong>[$2 направите сметка]</strong>, тогаш уредувањата ќе се припишуваат на вашето корисничко име, покрај другите погодности.",
"anonpreviewwarning": "''Не сте најавени. Ако ја зачувате, Вашата IP-адреса ќе биде заведена во историјата на уредување на страницата.''",
"missingsummary": "'''Потсетник:''' Не внесовте опис на измените. Ако притиснете Зачувај повторно, вашите измени ќе се зачуваат без опис.",
+ "selfredirect": "<strong>Предупредување:</strong> Создавате пренасочување кон истата статија.\nАко стиснете на „{{int:savearticle}}“ повторно, тогаш пренасочувањето ќе се создаде.",
"missingcommenttext": "Ве молиме внесете коментар подолу.",
"missingcommentheader": "'''Потсетување:''' Не внесовте наслов за овој коментар.\nАко повторно стиснете на „{{int:savearticle}}“, уредувањето ќе биде зачувано без наслов.",
"summary-preview": "Изглед на описот:",
"pager-older-n": "{{PLURAL:$1|постара 1|постари $1}}",
"suppress": "Скривање",
"querypage-disabled": "Оваа службена страница е оневозможена за да не попречува на делотворноста.",
- "apihelp": "Ð\9fомоÑ\88 Ñ\81о пÑ\80илогот",
+ "apihelp": "Ð\9fомоÑ\88 Ñ\81о извÑ\80Ñ\88никот",
"apihelp-no-such-module": "Модулот „$1“ не е пронајден.",
"booksources": "Печатени извори",
"booksources-search-legend": "Пребарување на извори за книга",
"version-parserhooks": "Расчленувачки куки",
"version-variables": "Променливи",
"version-antispam": "Спречување на спам",
- "version-api": "Ð\9fÑ\80илози",
+ "version-api": "Ð\98звÑ\80Ñ\88ниÑ\86и",
"version-other": "Друго",
"version-mediahandlers": "Ракувачи со мултимедијални содржини",
"version-hooks": "Куки",
"feedback-cancel": "Откажи",
"feedback-submit": "Поднеси мислење",
"feedback-adding": "Го додавам искажаното мислење во страницата...",
- "feedback-error1": "Ð\93Ñ\80еÑ\88ка: Ð\9dепÑ\80епознаен Ñ\80езÑ\83лÑ\82аÑ\82 од пÑ\80илогот (API)",
+ "feedback-error1": "Ð\93Ñ\80еÑ\88ка: Ð\9dепÑ\80епознаен Ñ\80езÑ\83лÑ\82аÑ\82 од извÑ\80Ñ\88никот (API)",
"feedback-error2": "Грешка: Уредувањето не успеа",
- "feedback-error3": "Ð\93Ñ\80еÑ\88ка: Ð\9fÑ\80илогоÑ\82 (API) не одговара",
+ "feedback-error3": "Ð\93Ñ\80еÑ\88ка: Ð\98звÑ\80Ñ\88никоÑ\82 не одговара",
"feedback-thanks": "Благодариме! Вашиот одѕив е објавен на страницата „[$2 $1]“.",
"feedback-close": "Готово",
"feedback-bugcheck": "Одлично! Само проверете да не е една од [$1 веќе познатите грешки].",
"tog-shownumberswatching": "ശ്രദ്ധിക്കുന്ന ഉപയോക്താക്കളുടെ എണ്ണം കാണിക്കുക",
"tog-oldsig": "നിലവിലുള്ള ഒപ്പ്:",
"tog-fancysig": "ഒപ്പ് ഒരു വിക്കി എഴുത്തായി പരിഗണിക്കുക (കണ്ണി സ്വയം ചേർക്കേണ്ടതില്ല)",
- "tog-uselivepreview": "തത്സമയ പ്രിവ്യൂ ഉപയോഗപ്പെടുത്തുക (പരീക്ഷണാടിസ്ഥാനം)",
+ "tog-uselivepreview": "തത്സമയ പ്രിവ്യൂ ഉപയോഗപ്പെടുത്തുക",
"tog-forceeditsummary": "തിരുത്തുകളുടെ ചുരുക്കം നൽകിയില്ലെങ്കിൽ എന്നെ ഓർമ്മിപ്പിക്കുക",
"tog-watchlisthideown": "ഞാൻ ശ്രദ്ധിക്കുന്ന താളുകളുടെ പട്ടികയിൽനിന്ന് എന്റെ തിരുത്തുകൾ മറയ്ക്കുക",
"tog-watchlisthidebots": "ഞാൻ ശ്രദ്ധിക്കുന്ന താളുകളുടെ പട്ടികയിൽനിന്ന് യന്ത്രങ്ങൾ വരുത്തിയ തിരുത്തുകൾ മറയ്ക്കുക",
"anoneditwarning": "<strong>മുന്നറിയിപ്പ്:</strong> താങ്കൾ ലോഗിൻ ചെയ്തിട്ടില്ല. താങ്കൾ തിരുത്തുകളെന്തെങ്കിലും ചെയ്യുകയാണെങ്കിൽ താങ്കളുടെ ഐ.പി. വിലാസം എല്ലാവർക്കും ലഭ്യമായിരിക്കും. താങ്കൾ <strong>[$1 ലോഗിൻ ചെയ്യുകയോ]</strong> <strong>[$2 അംഗത്വമെടുക്കുകയോ]</strong> ചെയ്യുന്നതുവഴി മറ്റ് ഗുണങ്ങളോടൊപ്പം താങ്കളുടെ തിരുത്തുകൾ ഉപയോക്തൃനാമത്തിലാവും അറിയപ്പെടുക.",
"anonpreviewwarning": "''താങ്കൾ ലോഗിൻ ചെയ്തിട്ടില്ല. സേവ് ചെയ്യുമ്പോൾ താളിന്റെ തിരുത്തൽ ചരിത്രത്തിൽ താങ്കളുടെ ഐ.പി. വിലാസം ചേർത്തു സൂക്ഷിക്കപ്പെടും.''",
"missingsummary": "'''ഓർമ്മക്കുറിപ്പ്:''' താങ്കൾ തിരുത്തലിന്റെ ചുരുക്കരൂപം നൽകിയിട്ടില്ല. ''സേവ് ചെയ്യുക'' ബട്ടൺ ഒരുവട്ടം കൂടി അമർത്തിയാൽ താങ്കൾ വരുത്തിയ മാറ്റം കാത്തുസൂക്ഷിക്കുന്നതാണ്.",
+ "selfredirect": "<strong>മുന്നറിയിപ്പ്:</strong> അതേ ലേഖനത്തിലേക്കുള്ള തിരിച്ചുവിടലാണ് താങ്കൾ സൃഷ്ടിക്കുന്നത്.\nവീണ്ടും \"{{int:savearticle}}\" അമർത്തിയാൽ, തിരിച്ചുവിടൽ സൃഷ്ടിക്കപ്പെടുന്നതാണ്.",
"missingcommenttext": "താങ്കളുടെ അഭിപ്രായം ദയവായി താഴെ രേഖപ്പെടുത്തുക.",
"missingcommentheader": "'''ഓർമ്മക്കുറിപ്പ്:''' ഈ കുറിപ്പിന് താങ്കൾ വിഷയം/തലക്കെട്ട് നൽകിയിട്ടില്ല. ''{{int:savearticle}}'' എന്ന ബട്ടൺ ഒരുവട്ടം കൂടി അമർത്തിയാൽ വിഷയം/തലക്കെട്ട് ഇല്ലാതെ തന്നെ കാത്തുസൂക്ഷിക്കുന്നതാവും.",
"summary-preview": "ചുരുക്കരൂപം എങ്ങനെയുണ്ടെന്നു കാണുക:",
"tog-shownumberswatching": "Fa' vedé 'o nummero d'utente che teneno 'a paggena cuntrullata",
"tog-oldsig": "Firma 'e mmo:",
"tog-fancysig": "Piglia 'a firma comme fosse nu wikitesto (senza fà link automatico)",
- "tog-uselivepreview": "Abilita 'o \"Live preview\" (sperimentale)",
+ "tog-uselivepreview": "Abbìa 'o \"Live preview\"",
"tog-forceeditsummary": "Chiere a mme quanno se sta azzeccanno nu campo oggetto abbacante",
"tog-watchlisthideown": "Annascunne 'e cagnamiente d' 'a lista 'e cuntrollo mia",
"tog-watchlisthidebots": "Annasconne 'e cagnamiènte d' 'e bot ncopp'a l'elenco 'e cuntrollo",
"anoneditwarning": "'''Attenzione:''' Nun avite fatto l'acciesso. 'A cronologgia d' 'a vosta sarrà visibbele pubbrecamente si facite cocche cagnamiento. Si <strong>[$1 tràse]</strong> o <strong>[$2 crìe nu cunto]</strong>, 'e cagnamiente vuoste ve sarranno attribbuite a vvuje, nzieme a n'ati migliuramente.",
"anonpreviewwarning": "''Nun avite fatto 'o login. Sarvann' 'a paggena, l'indirizzo IP d' 'o vuosto sarrà riggistrato dint'a cronologgia.''",
"missingsummary": "'''Attenziò:''' nun s'è specificato l'oggetto 'e stu cagnamiento. Clicann' 'a \"{{int:savearticle}}\" n'ata vota 'o cagnamiento sarrà sarvato cu l'oggetto abbacante.",
+ "selfredirect": "<strong>Attenziò:</strong> State crianno nu redirect a 'o stesso articolo.\nSi cliccate \"{{int:savearticle}}\" n'ata vota, si criarrà 'o redirect.",
"missingcommenttext": "Pe' piacere scrivete nu commento ccà abbascio.",
"missingcommentheader": "'''Attenziò:''' nun s'è specificato l'oggetto/titolo 'e stu commento. Clicann' 'a \"{{int:savearticle}}\" n'ata vota 'o cagnamiento sarrà sarvato c' 'o titolo abbacante.",
"summary-preview": "Anteprimma'e l'oggetto:",
"tog-shownumberswatching": "Smon-e ël nùmer d'utent che as ten-o la pàgina sot-euj",
"tog-oldsig": "Firma esistenta:",
"tog-fancysig": "Traté la firma com dël test wiki (sensa n'anliura automàtica)",
- "tog-uselivepreview": "Dovré la fonsion ''Preuva dal viv'' (sperimental)",
+ "tog-uselivepreview": "Dovré la fonsion ''Preuva dal viv''",
"tog-forceeditsummary": "Ciamé conferma se ël resumé dla modìfica a l'é veujd",
"tog-watchlisthideown": "Stërmé mie modìfiche ant la ròba che im ten-o sot-euj",
"tog-watchlisthidebots": "Stërmé le modìfiche fàite daj trigomiro ant la lista dle ròbe che im ten-o sot-euj",
"anoneditwarning": "<strong>Atension:<strong> A l'é nen rintrà ant ël sistema. Soa adrëssa IP a së sc-iairërà s'a fà dle modìfiche. Si chiel a <strong>[$1 rintra ant ël sistema]</strong> o <strong>[$2 a crea an cont]</strong>, soe modìfiche a saran atribuìe a sò stranòm, ansema a d'àutri vantagg.",
"anonpreviewwarning": "''A l'é nen rintrà ant ël sistema. An salvand a sarà memorisà soa adrëssa IP ant la stòria dle modìfiche ëd sa pàgina.''",
"missingsummary": "'''Nòta:''' a l'ha butà gnun resumé dla modìfica. Se a sgnaca «{{int:savearticle}}» n'àutra vira, soa modìfica a resterà salvà sensa resumé.",
+ "selfredirect": "<strong>Atension:</strong> A l'é an camin ch'a crea na ridiriression a l'istess artìcol.\nS'a sgnaca torna ansima a «{{int:savearticle}}», la ridiression a sarà creà.",
"missingcommenttext": "Për piasì, che a buta un coment sì-sota.",
"missingcommentheader": "'''Ch'a arcòrda:''' A l'ha pa dàit ëd soget o d'intestassion për cost coment.\nSe a sgnaca torna «{{int:savearticle}}», soa modìfica a sarà salvà sensa gnun-a intestassion.",
"summary-preview": "Preuva dël resumé:",
"anoneditwarning": "<strong>Atenție:</strong> Nu v-ați autentificat. Adresa dumneavoastră IP va fi vizibilă în mod public dacă efectuați modificări. Dacă vă <strong>[$1 autentificați]</strong> sau vă <strong>[$2 creați un cont]</strong>, modificările dumneavoastră vor fi asociate numelui de utilizator, pe lângă alte beneficii.",
"anonpreviewwarning": "''Nu v-ați autentificat. Dacă salvați pagina adresa dumneavoastră IP va fi înregistrată în istoric.''",
"missingsummary": "'''Atenție:''' Nu ați completat caseta „descriere modificări”. Dacă apăsați din nou butonul „salvează pagina” modificările vor fi salvate fără descriere.",
+ "selfredirect": "<strong>Atenție:</strong> Sunteți pe cale să creați o redirecționare către același articol.\nDacă apăsați din nou pe „{{int:savearticle}}”, redirecționarea va fi creată.",
"missingcommenttext": "Vă rugăm să introduceți un comentariu.",
"missingcommentheader": "'''Atenție,''' nu ați pus titlu sau subiect la acest comentariu.\nDacă dați din nou clic pe „{{int:savearticle}}” modificarea va fi salvată fără titlu.",
"summary-preview": "Previzualizare descriere:",
"tog-shownumberswatching": "Показывать число участников, включивших страницу в свой список наблюдения",
"tog-oldsig": "Текущая подпись:",
"tog-fancysig": "Собственная вики-разметка подписи (без автоматической ссылки)",
- "tog-uselivepreview": "Использовать быстрый предварительный просмотр (экспериментально)",
+ "tog-uselivepreview": "Использовать быстрый предварительный просмотр",
"tog-forceeditsummary": "Предупреждать, когда не заполнено поле описания правки",
"tog-watchlisthideown": "Скрывать мои правки из списка наблюдения",
"tog-watchlisthidebots": "Скрывать правки ботов из списка наблюдения",
"anoneditwarning": "<strong>Opozorilo:</strong> Niste prijavljeni. Vaš IP-naslov bo javno viden, če naredite kakršno koli urejanje. Če se <strong>[$1 prijavite]</strong> ali <strong>[$2 ustvarite račun]</strong>, bodo vaša urejanja pripisana vašemu uporabniškemu imenu skupaj z drugimi prednostmi.",
"anonpreviewwarning": "Niste prijavljeni. Ob spremembi strani se bo vaš IP-naslov zapisal v zgodovini urejanja te strani.",
"missingsummary": "'''Opozorilo:''' Niste napisali povzetka urejanja. Ob ponovnem kliku gumba ''Shrani'' se bo vaše urejanje shranilo brez njega.",
+ "selfredirect": "<strong>Opozorilo:</strong> Ustvarjate preusmeritev na isti članek.\nČe ponovno kliknete »{{int:savearticle}}«, bomo preusmeritev ustvarili.",
"missingcommenttext": "Prosimo, vpišite v spodnje polje komentar.",
"missingcommentheader": "'''Opozorilo:''' Niste vnesli zadeve/naslova za ta komentar.\nČe boste ponovno kliknili »{{int:savearticle}}«, bo vaše urejanje shranjeno brez le-tega.",
"summary-preview": "Predogled povzetka",
"tog-shownumberswatching": "Visa antalet användare som bevakar",
"tog-oldsig": "Nuvarande signatur:",
"tog-fancysig": "Behandla signatur som wikitext (utan en automatisk länk)",
- "tog-uselivepreview": "Använd direktuppdaterad förhandsgranskning (experimentell)",
+ "tog-uselivepreview": "Använd direktuppdaterad förhandsgranskning",
"tog-forceeditsummary": "Påminn mig om jag inte fyller i en redigeringskommentar",
"tog-watchlisthideown": "Dölj mina redigeringar i bevakningslistan",
"tog-watchlisthidebots": "Visa inte robotredigeringar i bevakningslistan",
"anoneditwarning": "<strong>Varning:</strong> Du är inte inloggad. Din IP-adress kommer att vara publikt synlig om du gör några redigeringar. Om du <strong>[$1 loggar in]</strong> eller <strong>[$2 skapar ett konto]</strong> kommer dina redigeringar att tillskrivas ditt användarnamn, tillsammans med andra fördelar.",
"anonpreviewwarning": "''Du är inte inloggad. Om du sparar kommer din IP-adress registreras på denna sidas redigeringshistorik.''",
"missingsummary": "<strong>Påminnelse:</strong> Du har inte skrivit någon redigeringskommentar.\nOm du klickar på \"{{int:savearticle}}\" igen kommer din redigering att sparas utan en sådan.",
+ "selfredirect": "<strong>Varning:</strong> Du omdirigerar till samma artikel.\nOm du klickar på \"{{int:savearticle}}\" igen kommer omdirigeringen att skapas.",
"missingcommenttext": "Var god och skriv in en kommentar nedan.",
"missingcommentheader": "<strong>Påminnelse:</strong> Du har inte skrivit något ämne/rubrik för den här kommentaren.\nOm du trycker på \"{{int:savearticle}}\" igen kommer din redigering sparas utan rubrik.",
"summary-preview": "Förhandsgranskning av sammanfattning:",
"tog-shownumberswatching": "వీక్షకుల సంఖ్యను చూపు",
"tog-oldsig": "ప్రస్తుత సంతకం:",
"tog-fancysig": "సంతకాన్ని వికీపాఠ్యంగా తీసుకో (ఆటోమెటిక్ లింకు లేకుండా)",
- "tog-uselivepreview": "à°µà±\86à°¨à±\81à°µà±\86à°\82à°\9f à°®à±\81à°¨à±\81à°\9cà±\82à°ªà±\81à°¨à±\81 వాడà±\81 (à°ªà±\8dà°°à°¯à±\8bà°\97ాతà±\8dà°®à°\95à°\82)",
+ "tog-uselivepreview": "తాà°\9cà°¾ à°®à±\81à°¨à±\81à°\9cà±\82à°ªà±\81à°¨à±\81 వాడà±\81",
"tog-forceeditsummary": "దిద్దుబాటు సారాంశం ఖాళీగా ఉంటే ఆ విషయాన్ని నాకు సూచించు",
"tog-watchlisthideown": "నా మార్పులను వీక్షణా జాబితాలో చూపించొద్దు",
"tog-watchlisthidebots": "బాట్లు చేసిన మార్పులను నా వీక్షణా జాబితాలో చూపించొద్దు",
"hidetoc": "దాచు",
"collapsible-collapse": "కుదించు",
"collapsible-expand": "విస్తరించు",
+ "confirmable-yes": "అవును",
+ "confirmable-no": "కాదు",
"thisisdeleted": "$1ను చూస్తారా, పునఃస్థాపిస్తారా?",
"viewdeleted": "$1 చూస్తారా?",
"restorelink": "{{PLURAL:$1|ఒక తొలగించిన మార్పు|$1 తొలగించిన మార్పులు}}",
"search-result-category-size": "{{PLURAL:$1|1 సభ్యుడు|$1 సభ్యులు}} ({{PLURAL:$2|1 ఉవవర్గం|$2 ఉపవర్గాలు}}, {{PLURAL:$3|1 దస్త్రం|$3 దస్త్రాలు}})",
"search-redirect": "(దారిమార్పు $1)",
"search-section": "(విభాగం $1)",
+ "search-category": "(వర్గం $1)",
"search-file-match": "(ఫైలు విషయంతో సరిపోలుతోంది)",
"search-suggest": "మీరు అంటున్నది ఇదా: $1",
"search-interwiki-caption": "సోదర ప్రాజెక్టులు",
"license-nopreview": "(మునుజూపు అందుబాటులో లేదు)",
"upload_source_url": " (సార్వజనికంగా అందుబాటులో ఉన్న, సరైన URL)",
"upload_source_file": " (మీ కంప్యూటర్లో ఒక ఫైలు)",
+ "listfiles-delete": "తొలగించు",
"listfiles-summary": "ఈ ప్రత్యేక పేజీ, ఎక్కించిన ఫైళ్ళన్నిటినీ చూపిస్తుంది.",
"listfiles_search_for": "మీడియా పేరుకై వెతుకు:",
"imgfile": "దస్త్రం",
"randomincategory": "వర్గంలోని యాదృచ్చిక పేజీ",
"randomincategory-invalidcategory": "\"$1\" అనేది సరైన పర్గం పేరు కాదు.",
"randomincategory-nopages": "[[:Category:$1|$1]] వర్గంలో పేజీలేమీ లేవు.",
+ "randomincategory-category": "వర్గం:",
"randomredirect": "యాదృచ్చిక దారిమార్పు",
"randomredirect-nopages": "\"$1\" పేరుబరిలో దారిమార్పులేమీ లేవు.",
"statistics": "గణాంకాలు",
"querypage-disabled": "పనితీరు కారణాల వలన, ఈ ప్రత్యేకపేజీని అశక్తం చేసాం.",
"booksources": "పుస్తక మూలాలు",
"booksources-search-legend": "పుస్తక మూలాల కోసం వెతుకు",
+ "booksources-search": "వెతుకు",
"booksources-text": "కొత్త, పాత పుస్తకాలు అమ్మే ఇతర సైట్లకు లింకులు కింద ఇచ్చాం. మీరు వెతికే పుస్తకాలకు సంబంధించిన మరింత సమాచారం కూడా అక్కడ దొరకొచ్చు:",
"booksources-invalid-isbn": "మీరిచ్చిన ISBN సరైనదిగా అనిపించుటలేదు; అసలు మూలాన్నుండి కాపీ చేయడంలో పొరపాట్లున్నాయేమో చూసుకోండి.",
"specialloguserlabel": "కర్త:",
"confirm-watch-top": "ఈ పుటను మీ వీక్షణ జాబితాలో చేర్చాలా?",
"confirm-unwatch-button": "సరే",
"confirm-unwatch-top": "ఈ పుటను మీ వీక్షణ జాబితా నుండి తొలగించాలా?",
+ "quotation-marks": "“$1”",
"imgmultipageprev": "← మునుపటి పేజీ",
"imgmultipagenext": "తరువాతి పేజీ →",
"imgmultigo": "వెళ్ళు!",
"autosumm-replace": "పేజీని '$1' తో మారుస్తున్నాం",
"autoredircomment": "[[$1]]కు దారిమళ్ళించారు",
"autosumm-new": "'$1' తో కొత్త పేజీని సృష్టించారు",
+ "autosumm-newblank": "ఖాళీ పేజీని సృష్టించారు",
"lag-warn-normal": "$1 {{PLURAL:$1|క్షణం|క్షణాల}} లోపు జరిగిన మార్పులు ఈ జాబితాలో కనిపించకపోవచ్చు.",
"lag-warn-high": "అధిక వత్తిడి వలన డేటాబేసు సర్వరు వెనుకబడింది, $1 {{PLURAL:$1|క్షణం|క్షణాల}} కంటే కొత్తవైన మార్పులు ఈ జాబితాలో కనిపించకపోవచ్చు.",
"watchlistedit-normal-title": "వీక్షణ జాబితాను మార్చు",
"duplicate-defaultsort": "హెచ్చరిక: డిఫాల్టు పేర్చు కీ \"$2\", గత డిఫాల్టు పేర్చు కీ \"$1\" ని అతిక్రమిస్తుంది.",
"version": "సంచిక",
"version-extensions": "స్థాపించిన పొడగింతలు",
- "version-skins": "అలంకారాలు",
+ "version-skins": "à°¸à±\8dథాపిà°\82à°\9aà°¿à°¨ à°\85à°²à°\82à°\95ారాలà±\81",
"version-specialpages": "ప్రత్యేక పేజీలు",
"version-parserhooks": "పార్సరు కొక్కాలు",
"version-variables": "చరరాశులు",
"version-hook-name": "కొక్కెం పేరు",
"version-hook-subscribedby": "ఉపయోగిస్తున్నవి",
"version-version": "(కూర్పు $1)",
+ "version-no-ext-name": "[పేరు లేదు]",
"version-license": "MediaWiki లైసెన్సు",
"version-ext-license": "లైసెన్సు",
"version-ext-colheader-name": "పొడిగింత",
+ "version-skin-colheader-name": "అలంకారం",
"version-ext-colheader-version": "కూర్పు",
"version-ext-colheader-license": "లైసెన్సు",
"version-ext-colheader-description": "వివరణ",
"specialpages-group-wiki": "డాటా మరియు పనిముట్లు",
"specialpages-group-redirects": "ప్రత్యేక పేజీల దారిమార్పులు",
"specialpages-group-spam": "స్పామ్ పనిముట్లు",
+ "specialpages-group-developer": "వికాసకుల పనిముట్లు",
"blankpage": "ఖాళీ పేజీ",
"intentionallyblankpage": "బెంచిమార్కింగు, మొదలగు వాటికై ఈ పేజీని కావాలనే ఖాళీగా వదిలాము.",
"external_image_whitelist": " #ఈ లైనును ఎలా ఉన్నదో అలాగే వదిలెయ్యండి<pre>\n#regular expression తునకలను (// ల మధ్య ఉండే భాగం)కింద పెట్టండి\n#వీటిని బయటి బొమ్మల URLలతో సరిపోల్చుతాము\n#సరిపోలిన బొమ్మలను చూపిస్తాము, మిగిలినవాటి లింకులను మాత్రమే చూపిస్తాము\n##తో మొదలయ్యే లైనులు వ్యాఖ్యానాలుగా భావించబడతాయి\n#ఇది కేస్-సెన్సిటివ్\n\n#అన్ని తునకలను ఈ లైనుకు పైన ఉంచండి. ఈ లైనును ఎలా ఉన్నదో అలాగే వదిలెయ్యండి</pre>",
"expand_templates_remove_nowiki": "ఫలితంలో <nowiki> ట్యాగులను అణచిపెట్టు",
"expand_templates_generate_xml": "XML పార్స్ ట్రీని చూపించు",
"expand_templates_generate_rawhtml": "ముడి HTML ను చూపించు",
- "expand_templates_preview": "మునుజూపు"
+ "expand_templates_preview": "మునుజూపు",
+ "pagelang-name": "పేజీ",
+ "pagelang-language": "భాష",
+ "pagelang-use-default": "అప్రమేయ భాషను వాడు"
}
"tog-shownumberswatching": "แสดงจำนวนผู้ใช้ที่เฝ้าดู",
"tog-oldsig": "ลายเซ็นที่ใช้อยู่:",
"tog-fancysig": "ถือลายเซ็นเป็นข้อความวิกิ (โดยไม่มีลิงก์อัตโนมัติ)",
- "tog-uselivepreview": "à¹\83à¸\8aà¹\89à¸\95ัวà¸à¸¢à¹\88าà¸\87à¸\97ัà¸\99à¸\97ี (à¸\97à¸\94ลà¸à¸\87)",
+ "tog-uselivepreview": "à¹\83à¸\8aà¹\89à¸\81ารà¹\81สà¸\94à¸\87à¸\95ัวà¸à¸¢à¹\88าà¸\87à¹\81à¸\9aà¸\9aสà¸\94",
"tog-forceeditsummary": "เตือนเมื่อช่องคำอธิบายอย่างย่อว่าง",
"tog-watchlisthideown": "ซ่อนการแก้ไขของฉันจากรายการเฝ้าดู",
"tog-watchlisthidebots": "ซ่อนการแก้ไขของบอตจากรายการเฝ้าดู",
"anoneditwarning": "<strong>คำเตือน:</strong> คุณมิได้ล็อกอิน สาธารณะจะเห็นเลขที่อยู่ไอพีของคุณหากคุณแก้ไข หากคุณ<strong>[$1 ล็อกอิน]</strong>หรือ<strong>[$2 สร้างบัญชี]</strong> การแก้ไขของคุณจะถือว่าเป็นของชื่อผู้ใช้ของคุณ ร่วมกับประโยชน์อื่น",
"anonpreviewwarning": "<em>คุณมิได้ล็อกอิน การบันทึกจะเก็บเลขที่อยู่ไอพีของคุณในประวัติการแก้ไขของหน้านี้</em>",
"missingsummary": "<strong>อย่าลืม:</strong> คุณยังไม่ได้ให้คำอธิบายการแก้ไข \nถ้าคุณคลิก \"{{int:savearticle}}\" อีก จะบันทึกการแก้ไขของคุณโดยไม่มีคำอธิบายการแก้ไข",
+ "selfredirect": "<strong>คำเตือน:</strong> คุณกำลังสร้างการเปลี่ยนทางไปบทความเดียวกัน หากคุณคลิก \"{{int:savearticle}}\" อีกครั้ง จะสร้างการเปลี่ยนทาง",
"missingcommenttext": "กรุณากรอกความเห็นด้านล่าง",
"missingcommentheader": "<strong>อย่าลืม:</strong> คุณยังไม่ได้ใส่หัวข้อ/พาดหัวสำหรับความเห็นนี้ \nถ้าคุณคลิก \"{{int:savearticle}}\" อีก จะบันทึกการแก้ไขของคุณโดยไม่มีหัวข้อ/พาดหัว",
"summary-preview": "ตัวอย่างคำอธิบาย:",
"anoneditwarning": "<strong>警告:</strong>您没有登录。您做出任何编辑后您的IP地址会公开可见。如果您<strong>[$1 登陆]</strong>或<strong>[$2 注册]</strong>一个账户,您的编辑将归属于您的用户名,以及有其他好处。",
"anonpreviewwarning": "<em>你没有登录。保存会记录你的IP地址于该页面的编辑历史中。</em>",
"missingsummary": "'''提示:'''你没有提供编辑摘要。如果你再次点击“{{int:savearticle}}”,你的编辑将不带编辑摘要保存。",
+ "selfredirect": "<strong>警告:</strong>您正在创建重定向到同一条目的重定向。\n如果您再次点击“{{int:savearticle}}”,重定向将被创建。",
"missingcommenttext": "请在下面输入评论。",
"missingcommentheader": "'''提示:''' 您还没有为此评论提供一个标题。如果您再次点击“{{int:savearticle}}”,您的编辑将不带标题保存。",
"summary-preview": "摘要预览:",
"protectlogtext": "下面是页面保护更改的列表。请见[[Special:ProtectedPages|受保护页面列表]]查看目前正在进行的页面保护的列表。",
"protectedarticle": "保护“[[$1]]”",
"modifiedarticleprotection": "更改“[[$1]]”的保护等级",
- "unprotectedarticle": "移除保护自“[[$1]]”",
+ "unprotectedarticle": "移除页面“[[$1]]”的保护",
"movedarticleprotection": "移动保护设置自“[[$2]]”至“[[$1]]”",
"protect-title": "更改“$1”的保护等级",
"protect-title-notallowed": "查看“$1”的保护等级",
"confirm-purge-top": "要清除此页面的缓存吗?",
"confirm-purge-bottom": "清除页面数据会清除缓存并强制显示最近的版本。",
"confirm-watch-button": "确定",
- "confirm-watch-top": "将此页添加到您的监视吗?",
+ "confirm-watch-top": "å°\86æ¤é¡µæ·»å\8a å\88°æ\82¨ç\9a\84ç\9b\91è§\86å\88\97表å\90\97ï¼\9f",
"confirm-unwatch-button": "确定",
"confirm-unwatch-top": "从监视列表中删除此页吗?",
"semicolon-separator": ";",
"api-error-stashnosuchfilekey": "您试图在藏匿处访问的文件密钥不存在。",
"api-error-timeout": "服务器没有在预期内响应。",
"api-error-unclassified": "出现未知错误。",
- "api-error-unknown-code": "未知错误:$1",
+ "api-error-unknown-code": "未知错误:“$1”。",
"api-error-unknown-error": "内部错误:尝试上传文件时出错。",
"api-error-unknown-warning": "未知的警告:“$1”。",
"api-error-unknownerror": "未知错误:$1。",
"tog-shownumberswatching": "顯示正在監視的使用者數",
"tog-oldsig": "現有簽名:",
"tog-fancysig": "將簽名視為 Wikitext 語言 (不自動產生連結)",
- "tog-uselivepreview": "使用即時預覽 (實驗中)",
+ "tog-uselivepreview": "使用即時預覽",
"tog-forceeditsummary": "未填寫編輯摘要時提示我",
"tog-watchlisthideown": "隱藏監視清單中我的編輯",
"tog-watchlisthidebots": "隱藏監視清單中機器人的編輯",
"generic-pool-error": "抱歉,太多使用者正嘗試檢視此資源,伺服器超出負荷。\n請稍候片刻再嘗試。",
"pool-timeout": "正在等待取消鎖定",
"pool-queuefull": "程序序列已滿",
- "pool-errorunknown": "未知錯誤",
+ "pool-errorunknown": "不明錯誤",
"pool-servererror": "無法使用程序計數服務 ($1)。",
"aboutsite": "關於 {{SITENAME}}",
"aboutpage": "Project:About",
"anoneditwarning": "<strong>警告:</strong>您尚未登入。 若您進行任何的編輯您的 IP 位置將會被公開。 若您 <strong>[$1 登入]</strong> 或 <strong>[$2 建立帳號]</strong>,您的編輯將會以您的使用者名稱標示,擁有其他優點。",
"anonpreviewwarning": "<em>您尚未登入。儲存頁面會將您的 IP 位址記錄在此頁面的編輯歷史中。</em>",
"missingsummary": "<strong>提醒:</strong>您未填寫編輯摘要。\n若您再點選 \"{{int:savearticle}}\" 一次,將略過摘要直接儲存您的編輯。",
+ "selfredirect": "<strong>警告:</strong> 您正建立連結至自己的重新導向。\n若您再點選 \"{{int:savearticle}}\" 一次,將會繼續建立重新導向。",
"missingcommenttext": "請在下方輸入評論。",
"missingcommentheader": "<strong>提醒:</strong>您未填寫此評論的主旨/標題。\n若您再點選 \"{{int:savearticle}}\" 一次,將略過主旨/標題直接儲存您的評論。",
"summary-preview": "摘要預覽:",
"semiprotectedpagewarning": "<strong>注意:</strong>本頁已經被保護,只有已註冊的使用者才可編輯。\n以下提供最近的日誌以便參考:",
"cascadeprotectedwarning": "<strong>警告:</strong>本頁已經被保護,只有擁有管理員權限的使用者才可編輯,此頁面被下列頁面引用因此連鎖保護:",
"titleprotectedwarning": "<strong>警告:本頁面已被保護,需要 [[Special:ListGroupRights|特殊權限]] 方可建立。</strong>\n以下提供最近的日誌以便參考:",
- "templatesused": "此頁面使用了以下{{PLURAL:$1|樣版}}:",
+ "templatesused": "此頁面使用了以下{{PLURAL:$1|樣板}}:",
"templatesusedpreview": "此預覽使用了以下{{PLURAL:$1|樣板}}:",
- "templatesusedsection": "此頁面使用了以下{{PLURAL:$1|樣版}}:",
+ "templatesusedsection": "此頁面使用了以下{{PLURAL:$1|樣板}}:",
"template-protected": "(受保護)",
"template-semiprotected": "(受半保護)",
"hiddencategories": "此頁面屬於 {{PLURAL:$1|1 個隱藏分類|$1 個隱藏分類}}的成員:",
"content-model-text": "純文字",
"content-model-javascript": "JavaScript",
"content-model-css": "CSS",
- "duplicate-args-category": "樣版呼叫時使用重複的參數的頁面",
- "duplicate-args-category-desc": "該頁面包含重複使用參數的樣版呼叫,如 <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> 或 <code><nowiki>{{foo|bar|1=baz}}</nowiki>。",
+ "duplicate-args-category": "樣板呼叫時使用重複的參數的頁面",
+ "duplicate-args-category-desc": "該頁面包含重複使用參數的樣板呼叫,如 <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> 或 <code><nowiki>{{foo|bar|1=baz}}</nowiki>。",
"expensive-parserfunction-warning": "<strong>警告:</strong>此頁面使用了太多消耗系統資源的解析函數。\n\n使用次數應小於 $2 次,但目前使用了 $1 次。",
"expensive-parserfunction-category": "使用了太多消耗系統資源的分析函數的頁面",
"post-expand-template-inclusion-warning": "<strong>警告:</strong>引用樣板後大小超出限制。\n部份樣板內容將不會被使用。",
"post-expand-template-inclusion-category": "引用樣板後大小超出限制的頁面",
- "post-expand-template-argument-warning": "<strong>警告:</strong>此頁面有一個以上的樣版參數過長。\n過長的參數會被直接忽略。",
+ "post-expand-template-argument-warning": "<strong>警告:</strong>此頁面有一個以上的樣板參數過長。\n過長的參數會被直接忽略。",
"post-expand-template-argument-category": "樣板參數有部份被忽略的頁面",
"parser-template-loop-warning": "偵測到樣板遞迴:[[$1]]",
- "parser-template-recursion-depth-warning": "超出樣版遞迴深度限制 ($1)",
+ "parser-template-recursion-depth-warning": "超出樣板遞迴深度限制 ($1)",
"language-converter-depth-warning": "已超出語言轉換器深度限制 ($1)",
"node-count-exceeded-category": "節點數量超出限制的頁面",
"node-count-exceeded-category-desc": "超出節點數量限制的頁面。",
"history-feed-empty": "請求的頁面不存在,\n可能已被刪除或重新命名。\n請嘗試 [[Special:Search|搜尋本站]] 取得其他相關的新頁面。",
"rev-deleted-comment": "(已移除編輯摘要)",
"rev-deleted-user": " (已移除使用者名稱)",
- "rev-deleted-event": "(已移除日誌)",
+ "rev-deleted-event": "(已移除日誌操作)",
"rev-deleted-user-contribs": "[使用者名稱或 IP 位址已移除 - 已隱藏貢獻清單中的編輯]",
"rev-deleted-text-permission": "此頁面修訂已被 <strong>刪除</strong>。\n可至 [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} 刪除日誌] 取得詳細資訊。",
"rev-suppressed-text-permission": "此頁面修訂已被 <strong>禁止顯示</strong>。\n可至 [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} 禁止顯示日誌] 取得詳細資訊。",
"searchprofile-advanced-tooltip": "搜尋自訂命名空間",
"search-result-size": "$1 ($2 個字)",
"search-result-category-size": "$1 位成員 ($2 個子分類,$3 個檔案)",
- "search-redirect": "(重新導向自 $1 )",
+ "search-redirect": " (重新導向自 $1 )",
"search-section": "(章節 $1)",
"search-category": "(分類 $1)",
"search-file-match": "(符合檔案內容)",
"listduplicatedfiles-summary": "此清單中包含最新版本的檔案與其他檔案重複的清單,本清單只顯示本地檔案。",
"listduplicatedfiles-entry": "[[:File:$1|$1]] 有[[$3|其他 $2 個重複檔案]]。",
"unusedtemplates": "未使用的樣板",
- "unusedtemplatestext": "此頁面列出所有於 {{ns:template}} 命名空間下未被其他頁面引用的樣版。\n在刪除前,仍需檢查是否有連結這些樣版的其他頁面。",
+ "unusedtemplatestext": "此頁面列出所有於 {{ns:template}} 命名空間下未被其他頁面引用的樣板。\n在刪除前,仍需檢查是否有連結這些樣板的其他頁面。",
"unusedtemplateswlh": "其他連結",
"randompage": "隨機頁面",
"randompage-nopages": "在{{PLURAL:$2|命名空間}}中沒有任何頁面:$1。",
"uncategorizedpages": "未分類的頁面",
"uncategorizedcategories": "未分類的分類",
"uncategorizedimages": "未分類的檔案",
- "uncategorizedtemplates": "待分類樣版",
+ "uncategorizedtemplates": "待分類樣板",
"unusedcategories": "未使用的分類",
"unusedimages": "未使用的檔案",
"wantedcategories": "需要的分類",
"wantedfiletext-cat-noforeign": "下列檔案已被使用但不存在。 除此之外,頁面已內嵌但不存在的檔案列於 [[:$1]]。",
"wantedfiletext-nocat": "下列檔案被時用,但檔案不存在。 外部儲存庫的檔案儘管存在,但此清單仍會列出。 這類誤報的項目會以 <del>刪除線</del> 標示。",
"wantedfiletext-nocat-noforeign": "下列檔案已被使用但不存在。",
- "wantedtemplates": "需要的樣版",
+ "wantedtemplates": "需要的樣板",
"mostlinked": "被連結最多的頁面",
"mostlinkedcategories": "被連結最多的分類",
"mostlinkedtemplates": "被引用最多的頁面",
"trackingcategories-desc": "分類收錄標準",
"noindex-category-desc": "命名空間允許,且含有魔術字 <code><nowiki>__NOINDEX__</nowiki></code> 未被機器人列入索引的頁面。",
"index-category-desc": "命名空間允許,且含有魔術字 <code><nowiki>__INDEX__</nowiki></code> 被機器人列入索引的頁面。",
- "post-expand-template-inclusion-category-desc": "展開樣版後大小超過 <code>$wgMaxArticleSize</code> 導致部份樣版未正常展開的頁面。",
- "post-expand-template-argument-category-desc": "展開樣版參數後大小超過 <code>$wgMaxArticleSize</code> 的頁面 (有些於三括號中,如 <code>{{{Foo}}}</code>)。",
+ "post-expand-template-inclusion-category-desc": "展開樣板後大小超過 <code>$wgMaxArticleSize</code> 導致部份樣板未正常展開的頁面。",
+ "post-expand-template-argument-category-desc": "展開樣板參數後大小超過 <code>$wgMaxArticleSize</code> 的頁面 (有些於三括號中,如 <code>{{{Foo}}}</code>)。",
"expensive-parserfunction-category-desc": "頁面使用太多消耗系統資源的解析器函數 (如 <code>#ifexist</code>)。\n請參考 [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Manual:$wgExpensiveParserFunctionLimit]。",
"broken-file-category-desc": "含有損壞檔案連結的頁面 (內嵌檔案連結的檔案不存在)。",
"hidden-category-category-desc": "內容中使用 <code><nowiki>__HIDDENCAT__</nowiki></code> 的分類,可隱藏預設在頁面上顯示的分類連結方塊。",
"whatlinkshere-prev": "前 $1 筆",
"whatlinkshere-next": "後 $1 筆",
"whatlinkshere-links": "← 連結",
- "whatlinkshere-hideredirs": "$1重新導向頁面",
+ "whatlinkshere-hideredirs": "$1 重新導向頁面",
"whatlinkshere-hidetrans": "$1 引用",
"whatlinkshere-hidelinks": "$1 連結",
"whatlinkshere-hideimages": "$1 檔案連結",
"tooltip-search": "搜尋 {{SITENAME}}",
"tooltip-search-go": "若與此名稱相符的頁面存在,前往該頁面",
"tooltip-search-fulltext": "搜尋使用此文字的頁面",
- "tooltip-p-logo": "前往主頁面",
- "tooltip-n-mainpage": "前往主頁面",
- "tooltip-n-mainpage-description": "前往主頁面",
+ "tooltip-p-logo": "前往主頁",
+ "tooltip-n-mainpage": "前往主頁",
+ "tooltip-n-mainpage-description": "前往主頁",
"tooltip-n-portal": "關於本專案、您可以做什麼、哪裡可以找到您需要的事物",
"tooltip-n-currentevents": "於最新動態中尋找背景資訊",
"tooltip-n-recentchanges": "列出此 Wiki 中的近期變更清單",
"pageinfo-recent-authors": "最近作者數",
"pageinfo-magic-words": "魔術{{PLURAL:$1|字}} ($1)",
"pageinfo-hidden-categories": "隱藏分類 ($1)",
- "pageinfo-templates": "引用樣版 ($1)",
+ "pageinfo-templates": "引用樣板 ($1)",
"pageinfo-transclusions": "頁面被引用於 ($1)",
"pageinfo-toolboxlink": "頁面資訊",
"pageinfo-redirectsto": "重新導向至",
"exif-datetimemetadata": "資料定義最後修改日期",
"exif-nickname": "非正式的影像名稱",
"exif-rating": "評分 (共 5 分)",
- "exif-rightscertificate": "版權管理證書",
+ "exif-rightscertificate": "版權管理憑證",
"exif-copyrighted": "版權狀態",
"exif-copyrightowner": "版權所有人",
"exif-usageterms": "使用條款",
"api-error-overwrite": "不允許覆蓋已存在的檔案。",
"api-error-stashfailed": "內部錯誤:伺服器儲存暫存檔案失敗。",
"api-error-publishfailed": "內部錯誤:伺服器發佈暫存檔案失敗。",
- "api-error-stasherror": "上傳檔案至儲存庫時發生錯誤。",
- "api-error-stashedfilenotfound": "嘗試從藏匿處上傳時找不到藏匿的檔案。",
- "api-error-stashpathinvalid": "æ\89¾å\88°ç\9a\84è\97\8få\8c¿æª\94æ¡\88ç\9a\84è·¯å¾\91æ\98¯ç\84¡æ\95\88ç\9a\84。",
- "api-error-stashfilestorage": "儲存檔案至藏匿處時出錯。",
- "api-error-stashzerolength": "伺服器不能藏匿檔案,因爲它已經沒有藏匿空間了。",
- "api-error-stashnotloggedin": "您必須登入以儲存檔案至上傳藏匿處。",
- "api-error-stashwrongowner": "您嘗試在藏匿處存取的檔案不屬於您。",
- "api-error-stashnosuchfilekey": "您嘗試在藏匿處存取的檔案金鑰不存在。",
+ "api-error-stasherror": "上傳檔案至儲藏庫時發生錯誤。",
+ "api-error-stashedfilenotfound": "嘗試從儲藏庫上傳檔案時查無該檔案。",
+ "api-error-stashpathinvalid": "æ\87\89該å\98å\9c¨å\84²è\97\8fæª\94æ¡\88ç\9a\84è·¯å¾\91ç\84¡æ\95\88。",
+ "api-error-stashfilestorage": "儲存檔案至儲藏庫時發生錯誤。",
+ "api-error-stashzerolength": "伺服器無法儲藏該檔案,因為該檔案大小為 0。",
+ "api-error-stashnotloggedin": "您必須登入以儲存檔案於上傳儲藏庫。",
+ "api-error-stashwrongowner": "您嘗試在儲藏庫存取的檔案不屬於您的。",
+ "api-error-stashnosuchfilekey": "您嘗試在儲藏庫存取的檔案金鑰不存在。",
"api-error-timeout": "伺服器沒有在預期的時間內回應。",
"api-error-unclassified": "發生不明錯誤。",
"api-error-unknown-code": "不明錯誤:\"$1\"。",
"limitreport-expansiondepth": "最高展開深度",
"limitreport-expensivefunctioncount": "高消耗解析器函數次數",
"expandtemplates": "展開樣板",
- "expand_templates_intro": "本特殊頁面會將文字中的樣版展開,可以包含支援的解析器語法,如 <code><nowiki>{{</nowiki>#language:…}}</code> 與變數如 <code><nowiki>{{</nowiki>CURRENTDAY}}</code>。\n實際上,絕大部分在雙括號中的內容都會被展開。",
+ "expand_templates_intro": "本特殊頁面會將文字中的樣板展開,可以包含支援的解析器語法,如 <code><nowiki>{{</nowiki>#language:…}}</code> 與變數如 <code><nowiki>{{</nowiki>CURRENTDAY}}</code>。\n實際上,絕大部分在雙括號中的內容都會被展開。",
"expand_templates_title": "上下文標題,用於 {{FULLPAGENAME}} 等:",
"expand_templates_input": "輸入文字:",
"expand_templates_output": "結果",
'Listgrouprights' => array( 'רשימת_הרשאות_לקבוצה' ),
'Listredirects' => array( 'רשימת_הפניות', 'הפניות' ),
'Listusers' => array( 'רשימת_משתמשים', 'משתמשים' ),
+ 'ListDuplicatedFiles' => array( 'רשימת_קבצים_כפולים' ),
'Lockdb' => array( 'נעילת_בסיס_הנתונים' ),
'Log' => array( 'יומנים' ),
'Lonelypages' => array( 'דפים_יתומים' ),
'Specialpages' => array( 'דפים_מיוחדים' ),
'Statistics' => array( 'סטטיסטיקות' ),
'Tags' => array( 'תגיות' ),
+ 'TrackingCategories' => array( 'קטגוריות_מעקב' ),
'Unblock' => array( 'שחרור_חסימה' ),
'Uncategorizedcategories' => array( 'קטגוריות_חסרות_קטגוריה' ),
'Uncategorizedimages' => array( 'קבצים_חסרי_קטגוריה', 'תמונות_חסרות_קטגוריה' ),
* We default as considering stdin a tty (for nice readline methods)
* but treating stout as not a tty to avoid color codes
*
- * @param int $fd File descriptor
+ * @param mixed $fd File descriptor
* @return bool
*/
public static function posix_isatty( $fd ) {
*/
require_once __DIR__ . '/Maintenance.php';
-require_once 'PHPUnit/Autoload.php';
/**
* @ingroup Maintenance
// require it here.
require_once __DIR__ . '/../tests/TestsAutoLoader.php';
+ // If phpunit isn't available by autoloader try pulling it in
+ if ( !class_exists( 'PHPUnit_Framework_TestCase' ) ) {
+ require_once 'PHPUnit/Autoload.php';
+ }
+
+ // RequestContext::resetMain() will print warnings unless this
+ // is defined.
+ if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
+ define( 'MW_PHPUNIT_TEST', true );
+ }
+
$textUICommand = new PHPUnit_TextUI_Command();
$argv = array(
"$IP/tests/phpunit/phpunit.php",
$IP . '/includes/jobqueue/',
$IP . '/includes/json/',
$IP . '/includes/logging/',
+ $IP . '/includes/mail/',
$IP . '/includes/media/',
$IP . '/includes/page/',
$IP . '/includes/parser/',
* @param int $pageId
*/
function doPage( $pageId ) {
- $title = Title::newFromId( $pageId );
+ $title = Title::newFromID( $pageId );
if ( $title ) {
$titleText = $title->getPrefixedText();
} else {
parent::__construct();
$this->mDescription = "Count of the number of articles and update the site statistics table";
$this->addOption( 'update', 'Update the site_stats table with the new count' );
+ $this->addOption( 'use-master', 'Count using the master database' );
}
public function execute() {
$this->output( "Counting articles..." );
- $counter = new SiteStatsInit( false );
+ if ( $this->hasOption( 'use-master' ) ) {
+ $dbr = wfGetDB( DB_MASTER );
+ } else {
+ $dbr = wfGetDB( DB_SLAVE, 'vslow' );
+ }
+ $counter = new SiteStatsInit( $dbr );
$result = $counter->articles();
$this->output( "found {$result}.\n" );
'zh-cn' => 'resources/lib/moment/locale/zh-cn.js',
'zh-tw' => 'resources/lib/moment/locale/zh-tw.js',
),
+ 'targets' => array( 'desktop', 'mobile' ),
),
/* MediaWiki */
*/
( function ( mw, $ ) {
$( function () {
- var api = new mw.Api(), pending = null, $form = $( '#editform' );
+ var idleTimeout = 5000,
+ api = new mw.Api(),
+ pending = null,
+ $form = $( '#editform' ),
+ $text = $form.find( '#wpTextbox1' ),
+ data = {},
+ timer = null;
function stashEdit( token ) {
- var data = $form.serializeObject();
+ data = $form.serializeObject();
pending = api.post( {
action: 'stashedit',
} );
}
+ /* Has the edit body text changed since the last stashEdit() call? */
+ function isChanged() {
+ // Normalize line endings to CRLF, like $.fn.serializeObject does.
+ var newText = $text.val().replace( /\r?\n/g, '\r\n' );
+ return newText !== data.wpTextbox1;
+ }
+
function onEditChanged() {
- // If a stash request is already in flight, abort it, since its
- // payload has just been invalidated by this change.
+ if ( !isChanged() ) {
+ return;
+ }
+
+ // If a request is in progress, abort it; its payload is stale.
if ( pending ) {
pending.abort();
}
+
api.getToken( 'edit' ).then( stashEdit );
}
+ function onKeyPress( e ) {
+ // Ignore keystrokes that don't modify text, like cursor movements.
+ // See <http://stackoverflow.com/q/2284844>.
+ if ( e.which === 0 ) {
+ return;
+ }
+
+ clearTimeout( timer );
+
+ if ( pending ) {
+ pending.abort();
+ }
+
+ timer = setTimeout( onEditChanged, idleTimeout );
+ }
+
// We don't attempt to stash new section edits because in such cases
// the parser output varies on the edit summary (since it determines
// the new section's name).
return;
}
- $form.find( '#wpTextbox1' ).on( 'change', onEditChanged );
+ $text.on( { change: onEditChanged, keypress: onKeyPress } );
+
} );
}( mediaWiki, jQuery ) );
function sortDependencies( module, resolved, unresolved ) {
var n, deps, len, skip;
- if ( registry[module] === undefined ) {
+ if ( !hasOwn.call( registry, module ) ) {
throw new Error( 'Unknown dependency: ' + module );
}
// Build a list of modules which are in one of the specified states
for ( s = 0; s < states.length; s += 1 ) {
for ( m = 0; m < modules.length; m += 1 ) {
- if ( registry[modules[m]] === undefined ) {
+ if ( !hasOwn.call( registry, modules[m] ) ) {
// Module does not exist
if ( states[s] === 'unregistered' ) {
// OK, undefined
var key, value, media, i, urls, cssHandle, checkCssHandles,
cssHandlesRegistered = false;
- if ( registry[module] === undefined ) {
+ if ( !hasOwn.call( registry, module ) ) {
throw new Error( 'Module has not been registered yet: ' + module );
} else if ( registry[module].state === 'registered' ) {
throw new Error( 'Module has not been requested from the server yet: ' + module );
// Appends a list of modules from the queue to the batch
for ( q = 0; q < queue.length; q += 1 ) {
// Only request modules which are registered
- if ( registry[queue[q]] !== undefined && registry[queue[q]].state === 'registered' ) {
+ if ( hasOwn.call( registry, queue[q] ) && registry[queue[q]].state === 'registered' ) {
// Prevent duplicate entries
if ( $.inArray( queue[q], batch ) === -1 ) {
batch[batch.length] = queue[q];
for ( b = 0; b < batch.length; b += 1 ) {
bSource = registry[batch[b]].source;
bGroup = registry[batch[b]].group;
- if ( splits[bSource] === undefined ) {
+ if ( !hasOwn.call( splits, bSource ) ) {
splits[bSource] = {};
}
- if ( splits[bSource][bGroup] === undefined ) {
+ if ( !hasOwn.call( splits[bSource], bGroup ) ) {
splits[bSource][bGroup] = [];
}
bSourceGroup = splits[bSource][bGroup];
prefix = modules[i].substr( 0, lastDotIndex );
suffix = modules[i].slice( lastDotIndex + 1 );
- bytesAdded = moduleMap[prefix] !== undefined
+ bytesAdded = hasOwn.call( moduleMap, prefix )
? suffix.length + 3 // '%2C'.length == 3
: modules[i].length + 3; // '%7C'.length == 3
async = true;
l = currReqBaseLength + 9;
}
- if ( moduleMap[prefix] === undefined ) {
+ if ( !hasOwn.call( moduleMap, prefix ) ) {
moduleMap[prefix] = [];
}
moduleMap[prefix].push( suffix );
return true;
}
- if ( sources[id] !== undefined ) {
+ if ( hasOwn.call( sources, id ) ) {
throw new Error( 'source already registered: ' + id );
}
if ( typeof module !== 'string' ) {
throw new Error( 'module must be a string, not a ' + typeof module );
}
- if ( registry[module] !== undefined ) {
+ if ( hasOwn.call( registry, module ) ) {
throw new Error( 'module already registered: ' + module );
}
// List the module as registered
throw new Error( 'templates must be an object, not a ' + typeof templates );
}
// Automatically register module
- if ( registry[module] === undefined ) {
+ if ( !hasOwn.call( registry, module ) ) {
mw.loader.register( module );
}
// Check for duplicate implementation
- if ( registry[module] !== undefined && registry[module].script !== undefined ) {
+ if ( hasOwn.call( registry, module ) && registry[module].script !== undefined ) {
throw new Error( 'module already implemented: ' + module );
}
// Attach components
// an array of unrelated modules, whereas the modules passed to
// using() are related and must all be loaded.
for ( filtered = [], m = 0; m < modules.length; m += 1 ) {
- module = registry[modules[m]];
- if ( module !== undefined ) {
+ if ( hasOwn.call( registry, modules[m] ) ) {
+ module = registry[modules[m]];
if ( $.inArray( module.state, ['error', 'missing'] ) === -1 ) {
filtered[filtered.length] = modules[m];
}
}
return;
}
- if ( registry[module] === undefined ) {
+ if ( !hasOwn.call( registry, module ) ) {
mw.loader.register( module );
}
if ( $.inArray( state, ['ready', 'error', 'missing'] ) !== -1
* in the registry.
*/
getVersion: function ( module ) {
- if ( !registry[module] || registry[module].version === undefined ) {
+ if ( !hasOwn.call( registry, module ) || registry[module].version === undefined ) {
return null;
}
return formatVersionNumber( registry[module].version );
* in the registry.
*/
getState: function ( module ) {
- if ( !registry[module] || registry[module].state === undefined ) {
+ if ( !hasOwn.call( registry, module ) || registry[module].state === undefined ) {
return null;
}
return registry[module].state;
* @return {string|null} Module key or null if module does not exist
*/
getModuleKey: function ( module ) {
- return typeof registry[module] === 'object' ?
+ return hasOwn.call( registry, module ) ?
( module + '@' + registry[module].version ) : null;
},
# cat add category links
# ill add inter-language links
# subpage enable subpages (disabled by default)
-# noxml don't check for XML well formdness
+# noxml don't check for XML well-formedness
# title=[[XXX]] run test using article title XXX
# language=XXX set content language to XXX for this test
# variant=XXX set the variant of language for this test (eg zh-tw)
</p>
!!end
-
!! test
Italics and bold: 2-quote opening sequence: (2,3)
!! options
</p>
!!end
-
# same html as previous, but wikitext adjusted to match parsoid html2wt
!! test
Italics and bold: 2-quote opening sequence: (2,3) w/ nowiki
!! wikitext
-''<nowiki>foo'</nowiki>''
+''foo'<nowiki/>''
!! html
<p><i>foo'</i>
</p>
!! end
-
!! test
Italics and bold: 2-quote opening sequence: (2,4)
!! options
</p>
!!end
-
# same html as previous, but wikitext adjusted to match parsoid html2wt
!! test
Italics and bold: 2-quote opening sequence: (2,4) w/ nowiki
!! wikitext
-''<nowiki>foo''</nowiki>''
+''foo<nowiki>''</nowiki>''
!! html
<p><i>foo''</i>
</p>
!! end
-
# The PHP parser strips the empty tags out for giggles; parsoid doesn't.
!! test
Italics and bold: 2-quote opening sequence: (2,5)
!! test
Italics and bold: 3-quote opening sequence: (3,2)
+!! options
+parsoid=wt2html
!! wikitext
'''foo''
-!! html
+!! html/*
<p>'<i>foo</i>
</p>
!!end
+# same html as previous, but wikitext adjusted to match parsoid html2wt
+!! test
+Italics and bold: 3-quote opening sequence: (3,2) w/ nowiki
+!! wikitext
+'<nowiki/>''foo''
+!! html
+<p>'<i>foo</i>
+</p>
+!!end
!! test
Italics and bold: 3-quote opening sequence: (3,3)
</p>
!!end
-
!! test
Italics and bold: 3-quote opening sequence: (3,4)
!! options
</p>
!!end
-
# same html as previous, but wikitext adjusted to match parsoid html2wt
!! test
Italics and bold: 3-quote opening sequence: (3,4) w/ nowiki
!! wikitext
-'''<nowiki>foo'</nowiki>'''
+'''foo'<nowiki/>'''
!! html
<p><b>foo'</b>
</p>
!! end
-
# The PHP parser strips the empty tags out for giggles; parsoid doesn't.
!! test
Italics and bold: 3-quote opening sequence: (3,5)
</p>
!!end
-
# same html as previous, but wikitext adjusted to match parsoid html2wt
!! test
Italics and bold: 4-quote opening sequence: (4,2) w/ nowiki
</p>
!! end
-
!! test
Italics and bold: 4-quote opening sequence: (4,3)
+!! options
+parsoid=wt2html
!! wikitext
''''foo'''
-!! html
+!! html/*
<p>'<b>foo</b>
</p>
!!end
+# same html as previous, but wikitext adjusted to match parsoid html2wt
+!! test
+Italics and bold: 4-quote opening sequence: (4,3) w/ nowiki
+!! wikitext
+'<nowiki/>'''foo'''
+!! html
+<p>'<b>foo</b>
+</p>
+!!end
!! test
Italics and bold: 4-quote opening sequence: (4,4)
</p>
!!end
-
# same html as previous, but wikitext adjusted to match parsoid html2wt
!! test
Italics and bold: 4-quote opening sequence: (4,4) w/ nowiki
!! wikitext
-''''<nowiki>foo'</nowiki>'''
+'<nowiki/>'''foo'<nowiki/>'''
!! html
<p>'<b>foo'</b>
</p>
!! end
-
# The PHP parser strips the empty tags out for giggles; parsoid doesn't.
!! test
Italics and bold: 4-quote opening sequence: (4,5)
!! test
Italics and bold: 4-quote opening sequence: (4,5+2) w/ nowiki
!! wikitext
-''''foo'''''<nowiki/>''
+'<nowiki/>'''foo'''''<nowiki/>''
!! html/php
<p>'<b>foo</b>
</p>
</p>
!!end
-
# same html as previous, but wikitext adjusted to match parsoid html2wt
# skipping wt2html and html2html because it wants to put <i> before <b>
!! test
</p>
!!end
-
# same html as previous, but wikitext adjusted to match parsoid html2wt
!! test
Italics and bold: 5-quote opening sequence: (5,3+2)
</p>
!! end
-
!! test
Italics and bold: 5-quote opening sequence: (5,4)
!! options
</p>
!!end
-
# same html as previous, but wikitext adjusted to match parsoid html2wt
!! test
Italics and bold: 5-quote opening sequence: (5,4+2) w/ nowiki
!! wikitext
-'''''<nowiki>foo'</nowiki>'''''
+'''''foo'<nowiki/>'''''
!! html
<p><i><b>foo'</b></i>
</p>
!! end
-
!! test
Italics and bold: 5-quote opening sequence: (5,5)
!! wikitext
!! test
Italics and bold: multiple quote sequences: (2,4,2+3) w/ nowiki
!! wikitext
-''<nowiki>foo'</nowiki>'''bar'''''
+''foo'<nowiki/>'''bar'''''
!! html
<p><i>foo'<b>bar</b></i>
</p>
!! test
Italics and bold: multiple quote sequences: (2,4,3+2) w/ nowiki
!! wikitext
-''<nowiki>foo'</nowiki>'''bar'''''
+''foo'<nowiki/>'''bar'''''
!! html
<p><i>foo'<b>bar</b></i>
</p>
!! test
Italics and bold: multiple quote sequences: (2,4,4+2) w/ nowiki
!! wikitext
-''<nowiki>foo'</nowiki>'''<nowiki>bar'</nowiki>'''''
+''foo'<nowiki/>'''bar'<nowiki/>'''''
!! html
<p><i>foo'<b>bar'</b></i>
</p>
# same html as previous, but wikitext adjusted to match parsoid html2wt
-# add 'parsoid' option to use 'parsoid' normalization of the placeholder
!! test
Italics and bold: other quote tests: (3,2,3+2+2,2)
-!! options
-parsoid
!! wikitext
'''this is about ''foo'''''<nowiki/>''s family''
-!! html/*
+!! html
<p><b>this is about <i>foo</i></b><i>s family</i>
</p>
!! end
!! test
Italics and bold: other quote tests: (3,2,3,3)
!! options
+parsoid=wt2html
!! wikitext
'''this is about ''foo'''s family'''
+!! html/*
+<p>'<i>this is about </i>foo<b>s family</b>
+</p>
+!!end
+
+
+# same html as previous, but wikitext adjusted to match parsoid html2wt
+!! test
+Italics and bold: other quote tests: (3,2,3,3) w/ nowiki
+!! wikitext
+'<nowiki/>''this is about ''foo'''s family'''
!! html
<p>'<i>this is about </i>foo<b>s family</b>
</p>
## of eager output of buffered tokens in the p-wrapper. But, I'm going to ignore
## them for now.
!! test
-P-wrapping should leave sol-transparent tags outside p-tags where possible
+1. P-wrapping should leave sol-transparent tags outside p-tags where possible
!! options
parsoid=wt2html
!! wikitext
<link href="Category:A1"/> <link href="Category:A2"/> <link href="Category:A3"/> <link href="Category:A4"/>
!! end
+!! test
+2. P-wrapping should leave sol-transparent tags outside p-tags where possible
+!! options
+parsoid=wt2html
+!! wikitext
+[[Category:A1]]a
+!! html/parsoid
+<link href="Category:A1"/><p>a</p>
+!! end
+
###
### Preformatted text
###
<table><pre></pre></table>
!! html/parsoid
-<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<pre <pre>x</pre>"}},"i":0}}]}'><pre </p><pre>x</pre>
+<pre about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"a":{"<pre":null},"sa":{"<pre":""},"stx":"html","pi":[[{"k":"1","spc":["","","",""]}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"<pre <pre>x</pre>"}},"i":0}}]}'>x</pre>
+
<p><pre </p>
<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo"}},"i":0}}]}'>foo</p>
!!end
+!! test
+Templates: Handle comments in parameter names (bug 67657)
+!! wikitext
+{{echo|1
+<!-- should be ignored -->
+=foo}}
+
+{{echo|
+<!-- should be ignored -->
+1 = foo}}
+
+{{echo|1<!-- should be ignored --> = foo}}
+
+{{echo|<!-- should be ignored -->1 = foo}}
+!!html/parsoid
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo","key":{"wt":"1\n<!-- should be ignored -->"}}},"i":0}}]}'>foo</p>
+
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo","key":{"wt":"<!-- should be ignored -->\n1"}}},"i":0}}]}'>foo</p>
+
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo","key":{"wt":"1<!-- should be ignored -->"}}},"i":0}}]}'>foo</p>
+
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"foo","key":{"wt":"<!-- should be ignored -->1"}}},"i":0}}]}'>foo</p>
+!!end
+
+!! test
+Templates: Other wikitext in parameter names (bug 67657)
+!! wikitext
+{{echo|''1''=foo}}
+!!html/parsoid
+<p typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"''1''":{"wt":"foo"}},"i":0}}]}'>{{{1}}}</p>
+!!html/php
+<p>{{{1}}}
+</p>
+!!end
+
#--------------------------------------------------------------------
# Transclusion parameter escaping tests
#--------------------------------------------------------------------
</p>
!! end
+!! test
+External links: No preceding word characters allowed (bug 65278)
+!! wikitext
+NOPEhttp://example.com
+N0http://example.com
+ok:http://example.com
+ok-http://example.com
+!! html
+<p>NOPEhttp://example.com
+N0http://example.com
+ok:<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>
+ok-<a rel="nofollow" class="external free" href="http://example.com">http://example.com</a>
+</p>
+!! end
+
!! test
External image
!! wikitext
{|
|{{table_attribs}}
| {{table_attribs}}
+| <!--foo--> <!--bar--> <!--baz--> {{table_attribs}}
+|align=center {{table_attribs}}
+| <!--foo--> align=center <!--bar--> {{table_attribs}}
|}
!! html
<table>
<td style="color: red"> Foo
</td>
<td style="color: red"> Foo
-</td></tr></table>
-
-!! end
-
-!! test
-Template-generated table cell attributes and cell content (2)
-!! wikitext
-{|
-|align=center {{table_attribs}}
-|}
-!! html
-<table>
-<tr>
+</td>
+<td style="color: red"> Foo
+</td>
+<td align="center" style="color: red"> Foo
+</td>
<td align="center" style="color: red"> Foo
</td></tr></table>
!! end
!! test
-Template-generated table cell attributes and cell content (3)
+Template-generated table cell attributes and cell content (2)
!! wikitext
{|
|align=center {{table_cells}}
!! end
+!! test
+Build table with pipe as data
+!! wikitext
+{| class="wikitable"
+! header
+! second header
+|- style="color:red;"
+| data || style="color:red;" | second data
+|-
+| style="color:red;" | data with | || style="color:red;" | second data with |
+|-
+|| data with | ||| second data with |
+|}
+!! html
+<table class="wikitable">
+<tr>
+<th> header
+</th>
+<th> second header
+</th></tr>
+<tr style="color:red;">
+<td> data </td>
+<td style="color:red;"> second data
+</td></tr>
+<tr>
+<td style="color:red;"> data with | </td>
+<td style="color:red;"> second data with |
+</td></tr>
+<tr>
+<td> data with | </td>
+<td> second data with |
+</td></tr></table>
+
+!! end
+
+!! test
+Build table with wikilink
+!! wikitext
+{| class="wikitable"
+! header || second header
+|- style="color:red;"
+| data [[Main Page|linktext]] || second data [[Main Page|linktext]]
+|-
+| data || second data [[Main Page|link|text with pipe]]
+|}
+!! html
+<table class="wikitable">
+<tr>
+<th> header </th>
+<th> second header
+</th></tr>
+<tr style="color:red;">
+<td> data <a href="/wiki/Main_Page" title="Main Page">linktext</a> </td>
+<td> second data <a href="/wiki/Main_Page" title="Main Page">linktext</a>
+</td></tr>
+<tr>
+<td> data </td>
+<td> second data <a href="/wiki/Main_Page" title="Main Page">link|text with pipe</a>
+</td></tr></table>
+
+!! end
+
# The expected HTML structure in this test is debatable. The PHP parser does
# not parse this kind of table at all. The main focus for Parsoid is on
# round-tripping, so this output is ok for now. TODO: revisit!
!! test
Link with double quotes in title part (literal) and alternate part (interpreted)
!! wikitext
-[[File:Denys Savchenko ''Pentecoste''.jpg]]
+[[File:Denys_Savchenko_''Pentecoste''.jpg]]
[[''Pentecoste'']]
</p><p><a href="/index.php?title=%27%27Pentecoste%27%27&action=edit&redlink=1" class="new" title="''Pentecoste'' (page does not exist)"><i>Pentecoste</i></a>
</p>
!! html/parsoid
-<meta typeof="mw:Placeholder"/>
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="./File:Denys_Savchenko_''Pentecoste''.jpg"><img resource="./File:Denys_Savchenko_''Pentecoste''.jpg" src="./Special:FilePath/Denys_Savchenko_''Pentecoste''.jpg" height="220" width="220"/></a></span></p>
<p><a rel="mw:WikiLink" href="''Pentecoste''" title="''Pentecoste''">''Pentecoste''</a></p>
<p><a rel="mw:WikiLink" href="''Pentecoste''" title="''Pentecoste''">Pentecoste</a></p>
<p><a rel="mw:WikiLink" href="''Pentecoste''" title="''Pentecoste''"><i>Pentecoste</i></a></p>
Broken image links with HTML captions (bug 39700)
!! wikitext
[[File:Nonexistent|<script></script>]]
-[[File:Nonexistent|100px|<script></script>]]
+[[File:Nonexistent|100x100px|<script></script>]]
[[File:Nonexistent|<]]
[[File:Nonexistent|a<i>b</i>c]]
-!! html
+!! html/php
<p><a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><script></script></a>
<a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><script></script></a>
<a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent"><</a>
<a href="/index.php?title=Special:Upload&wpDestFile=Nonexistent" class="new" title="File:Nonexistent">abc</a>
</p>
+!! html/parsoid
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"<script></script>"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220"/></a></span>
+<span typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"<script></script>"}'><a href="./File:Nonexistent" data-parsoid='{"a":{"href":"./File:Nonexistent"},"sa":{}}'><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="100" width="100"/></a></span>
+<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"&lt;"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220"/></a></span>
+<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"a<i>b</i>c"}'><a href="./File:Nonexistent"><img resource="./File:Nonexistent" src="./Special:FilePath/Nonexistent" height="220" width="220"/></a></span></p>
!! end
!! test
!! test
Interlanguage link
+!! options
+parsoid=wt2html,wt2wt,html2html
!! wikitext
Blah blah blah
[[zh:Chinese]]
!! test
Double interlanguage link
+!! options
+parsoid=wt2html,wt2wt,html2html
!! wikitext
Blah blah blah
[[es:Spanish]]
!! test
Interlanguage link variations
+!! options
+parsoid=wt2html,wt2wt,html2html
!! wikitext
Blah blah blah
[[ es :Spanish]]
[[ ZH :Chinese]]
+[[es:Foo_bar]]
+[[es:Foo bar]]
!! html/php
<p>Blah blah blah
</p>
!! html/parsoid
<p>Blah blah blah</p>
-<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Spanish" data-parsoid='{"stx":"simple","a":{"href":"http://es.wikipedia.org/wiki/Spanish"},"sa":{"href":" es :Spanish"}}'/>
-<link rel="mw:PageProp/Language" href="http://zh.wikipedia.org/wiki/Chinese" data-parsoid='{"stx":"simple","a":{"href":"http://zh.wikipedia.org/wiki/Chinese"},"sa":{"href":" ZH :Chinese"}}'/>
+<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Spanish" />
+<link rel="mw:PageProp/Language" href="http://zh.wikipedia.org/wiki/Chinese" />
+<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Foo_bar" />
+<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Foo_bar" />
!! end
!! test
</p>
!!end
+## FIXME: Is Parsoid's acceptance of self-closing html-tags
+## a feature or a bug? See https://phabricator.wikimedia.org/T76962
!! test
Handling html with a div self-closing tag
!! wikitext
<div title=bar />
<div title=bar/>
<div title=bar/ >
-!! html
+!! html/php
<p><div title />
<div title/>
</p>
<div title="bar/"></div>
</div>
+!! html/parsoid
+<div title="" data-parsoid='{"stx":"html","selfClose":true}'></div>
+<div title="" data-parsoid='{"stx":"html","selfClose":true}'></div>
+<div title="" data-parsoid='{"stx":"html","selfClose":true,"brokenHTMLTag":true}'></div>
+<div title="bar" data-parsoid='{"stx":"html","selfClose":true}'></div>
+<div title="bar" data-parsoid='{"stx":"html","selfClose":true}'></div>
+<div title="bar/" data-parsoid='{"stx":"html","autoInsertedEnd":true}'></div>
!! end
!! test
!! html/parsoid
<p><br title="" />
<br title="" />
-<br />
+<br title="" />
<br title="bar" />
<br title="bar" />
<br title="bar/" />
</p>
!! end
+!! test
+Magic links: RFC (bug 65278)
+!! wikitext
+This is RFC 822 but thisRFC 822 is not RFC 822linked.
+!! html
+<p>This is <a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc822">RFC 822</a> but thisRFC 822 is not RFC 822linked.
+</p>
+!! end
+
!! test
Magic links: ISBN (bug 1937)
!! wikitext
</p>
!! end
+!! test
+Magic links: ISBN (bug 65278)
+!! wikitext
+This is ISBN 978-0-316-09811-3 but thisISBN 978-0-316-09811-3 is not ISBN 978-0-316-09811-3linked.
+!! html
+<p>This is <a href="/wiki/Special:BookSources/9780316098113" class="internal mw-magiclink-isbn">ISBN 978-0-316-09811-3</a> but thisISBN 978-0-316-09811-3 is not ISBN 978-0-316-09811-3linked.
+</p>
+!! end
+
!! test
Magic links: PMID incorrectly converts space to underscore
!! wikitext
</p>
!! end
+!! test
+Magic links: PMID (bug 65278)
+!! wikitext
+This is PMID 1234 but thisPMID 1234 is not PMID 1234linked.
+!! html
+<p>This is <a class="external mw-magiclink-pmid" rel="nofollow" href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract">PMID 1234</a> but thisPMID 1234 is not PMID 1234linked.
+</p>
+!! end
+
###
### Templates
####
!! test
Template with thumb image (with link in description)
!! wikitext
-{{paramtest|
- param =[[Image:noimage.png|thumb|[[no link|link]] [[no link|caption]]]]}}
+{{paramtest|param =[[Image:noimage.png|thumb|[[no link|link]] [[no link|caption]]]]}}
!! html/php
This is a test template with parameter <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=Special:Upload&wpDestFile=Noimage.png" class="new" title="File:Noimage.png">File:Noimage.png</a> <div class="thumbcaption"><a href="/index.php?title=No_link&action=edit&redlink=1" class="new" title="No link (page does not exist)">link</a> <a href="/index.php?title=No_link&action=edit&redlink=1" class="new" title="No link (page does not exist)">caption</a></div></div></div>
<div class="thumbcaption"><a href="/index.php?title=No_link&action=edit&redlink=1" class="new" title="No link (page does not exist)">link</a> <a href="/index.php?title=No_link&action=edit&redlink=1" class="new" title="No link (page does not exist)">caption</a></div>
</div>
</div>
+!! html/parsoid
+<p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"paramtest","href":"./Template:Paramtest"},"params":{"param":{"wt":"[[Image:noimage.png|thumb|[[no link|link]] [[no link|caption]]]]"}},"i":0}}]}'>This is a test template with parameter </p><figure class="mw-default-size" typeof="mw:Error mw:Image/Thumb" about="#mwt1" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="./File:Noimage.png" ><img resource="./File:Noimage.png" src="./Special:FilePath/Noimage.png" height="220" width="220"/></a><figcaption><a rel="mw:WikiLink" href="./No_link" title="No link">link</a> <a rel="mw:WikiLink" href="./No_link" title="No link">caption</a></figcaption></figure>
!! end
!! article
#REDIRECT [[File:Barfoo.jpg]]
!! endarticle
+# FIXME: Parsoid should run this test -- but we'd need to teach the
+# mockAPI about the redirected Barfoo.jpg image.
!! test
Redirected image
!! wikitext
[[Image:Barfoo.jpg]]
-!! html
+!! html/php
<p><a href="/wiki/File:Barfoo.jpg" title="File:Barfoo.jpg">File:Barfoo.jpg</a>
</p>
!! end
!! options
wgEnableUploads=0
!! wikitext
-[[Image:Foobaz.jpg]]
-!! html
+[[File:Foobaz.jpg]]
+!! html/php
<p><a href="/wiki/File:Foobaz.jpg" title="File:Foobaz.jpg">File:Foobaz.jpg</a>
</p>
+!! html/parsoid
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="File:Foobaz.jpg"><img resource="./File:Foobaz.jpg" src="./Special:FilePath/Foobaz.jpg" height="220" width="220"/></a></span></p>
!! end
# Parsoid-specific testing for images
</p>
!! end
-# TODO: make this PHP-parser compatible!
+!! article
+Subpage test/1/2/subpage
+!! text
+blah
+!! endarticle
+
!! test
Relative subpage noslash link
!! options
[[../../subpage/]]
[[../../subpage]]
-!! html
-<p><a rel="mw:WikiLink" href="Subpage_test/1/2/subpage/" title="Subpage test/1/2/subpage/">subpage</a></p>
+!! html/php
+<p><a href="/wiki/Subpage_test/1/2/subpage" title="Subpage test/1/2/subpage">subpage</a>
+</p><p><a href="/wiki/Subpage_test/1/2/subpage" title="Subpage test/1/2/subpage">Subpage test/1/2/subpage</a>
+</p>
+!! html/parsoid
+<p><a rel="mw:WikiLink" href="Subpage_test/1/2/subpage" title="Subpage test/1/2/subpage">subpage</a></p>
<p><a rel="mw:WikiLink" href="Subpage_test/1/2/subpage" title="Subpage test/1/2/subpage">Subpage_test/1/2/subpage</a></p>
!! end
!! test
Image link to nonexistent file (bug 1850 - good)
!! wikitext
-[[Image:No such.jpg]]
-!! html
+[[File:No_such.jpg]]
+!! html/php
<p><a href="/index.php?title=Special:Upload&wpDestFile=No_such.jpg" class="new" title="File:No such.jpg">File:No such.jpg</a>
</p>
+!! html/parsoid
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="File:No_such.jpg"><img resource="./File:No_such.jpg" src="./Special:FilePath/No_such.jpg" height="220" width="220"/></a></span></p>
!! end
!! test
:Image link to nonexistent file (bug 1850 - bad)
!! wikitext
[[:Image:No such.jpg]]
-!! html
+!! html/php
<p><a href="/index.php?title=File:No_such.jpg&action=edit&redlink=1" class="new" title="File:No such.jpg (page does not exist)">Image:No such.jpg</a>
</p>
+!! html/parsoid
+<p><a rel="mw:WikiLink" href="./File:No_such.jpg" title="File:No such.jpg">Image:No such.jpg</a></p>
!! end
<div class="thumb tright"><div class="thumbinner" style="width:182px;">Error creating thumbnail: <div class="thumbcaption"></div></div></div>
!! html/parsoid
-<meta typeof="mw:Placeholder" data-parsoid='{"src":"[[Image:foobar.jpg|thumbnail= ]]","optList":[{"ck":"manualthumb","ak":"thumbnail= "}]}'/>
+<figure class="mw-default-size" typeof="mw:Error mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"manualthumb","ak":"thumbnail= "}],"dsr":[0,32,2,2]}' data-mw='{"errors":[{"key":"missing-thumbnail","message":"This thumbnail does not exist.","params":{"name":""}}],"thumb":""}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"},"sa":{},"dsr":[2,30,null,null]}'><img resource="./File:Foobar.jpg" src="./Special:FilePath/" height="220" width="220" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"220","width":"220"},"sa":{"resource":"Image:foobar.jpg"}}'/></a></figure>
!!end
!! test
djvu
!! wikitext
[[File:LoremIpsum.djvu|page=2]]
-!! html
+!! html/php
<p><a href="/index.php?title=File:LoremIpsum.djvu&page=2" class="image"><img alt="LoremIpsum.djvu" src="http://example.com/images/thumb/5/5f/LoremIpsum.djvu/page2-2480px-LoremIpsum.djvu.jpg" width="2480" height="3508" srcset="http://example.com/images/thumb/5/5f/LoremIpsum.djvu/page2-3720px-LoremIpsum.djvu.jpg 1.5x, http://example.com/images/thumb/5/5f/LoremIpsum.djvu/page2-4960px-LoremIpsum.djvu.jpg 2x" /></a>
</p>
+!! html/parsoid
+<p><span class="mw-default-size" typeof="mw:Image" data-parsoid='{"optList":[{"ck":"page","ak":"page=2"}]}'><a href="./File:LoremIpsum.djvu" data-parsoid='{"a":{"href":"./File:LoremIpsum.djvu"},"sa":{}}'><img resource="./File:LoremIpsum.djvu" src="//example.com/images/5/5f/LoremIpsum.djvu" height="3508" width="2480" data-parsoid='{"a":{"resource":"./File:LoremIpsum.djvu","height":"3508","width":"2480"},"sa":{"resource":"File:LoremIpsum.djvu"}}'/></a></span></p>
!! end
!! test
<a href="/index.php?title=ABC3D%25_%2B%2B&action=edit&redlink=1" class="new" title="ABC3D% ++ (page does not exist)">ABC3D% ++</a> <a href="/index.php?title=ABC3D%25_%2B%2B&action=edit&redlink=1" class="new" title="ABC3D% ++ (page does not exist)">+%20</a>
!! end
-# FIXME: Omitting the php sections here because of differences in the local and
-# jenkins output. But, more importantly, the Bad.jpg isn't being stripped,
-# which seems to be a problem with the testing infrastructure.
+# Parsoid doesn't support this yet: see bug 73581
+# but it *should* omit the 'src' attribute if the image is bad.
+# PHP side of tests was disabled in
+# mediawiki/core:6bd31e7d95161a6e88fa86df60871051da997c3c
+# because of issues in the PHP parserTests infrastructure
+# (but the output below is indeed what the PHP side emits)
!! test
Bad images - basic functionality
!! wikitext
[[File:Bad.jpg]]
+!! DISABLED/html/php
!! html/parsoid
-<meta typeof="mw:Placeholder" data-parsoid='{"src":"[[File:Bad.jpg]]","optList":[]}'/>
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"bad-image","message":"This image is blacklisted in this context."}]}'><a href="File:Bad.jpg"><img resource="./File:Bad.jpg" height="220" width="220"/></a></span></p>
!! end
-# FIXME: Same reasoning as above. The expected php is:
-# <p>Foo bar
-# </p><p>Bar foo
-# </p>
!! test
Bad images - bug 16039: text after bad image disappears
!! wikitext
Foo bar
[[File:Bad.jpg]]
Bar foo
+!! DISABLED/html/php
+<p>Foo bar
+</p><p>Bar foo
+</p>
!! html/parsoid
<p>Foo bar
-<meta typeof="mw:Placeholder" data-parsoid='{"src":"[[File:Bad.jpg]]","optList":[]}'/>
+<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"bad-image","message":"This image is blacklisted in this context."}]}'><a href="File:Bad.jpg"><img resource="./File:Bad.jpg" height="220" width="220"/></a></span>
Bar foo</p>
!! end
!! wikitext
[[User:+%]] [[Page+title%]]
[[%+]] [[%+|%20]] [[%+ ]] [[%+r]]
-[[%]] [[+]] [[image:%+abc%39|foo|[[bar]]]]
+[[%]] [[+]] [[File:%+abc%39|foo|[[bar]]]]
[[%33%45]] [[%33%45+]]
-!! html
+!! html/php
<p><a href="/index.php?title=User:%2B%25&action=edit&redlink=1" class="new" title="User:+% (page does not exist)">User:+%</a> <a href="/index.php?title=Page%2Btitle%25&action=edit&redlink=1" class="new" title="Page+title% (page does not exist)">Page+title%</a>
<a href="/index.php?title=%25%2B&action=edit&redlink=1" class="new" title="%+ (page does not exist)">%+</a> <a href="/index.php?title=%25%2B&action=edit&redlink=1" class="new" title="%+ (page does not exist)">%20</a> <a href="/index.php?title=%25%2B&action=edit&redlink=1" class="new" title="%+ (page does not exist)">%+ </a> <a href="/index.php?title=%25%2Br&action=edit&redlink=1" class="new" title="%+r (page does not exist)">%+r</a>
<a href="/index.php?title=%25&action=edit&redlink=1" class="new" title="% (page does not exist)">%</a> <a href="/index.php?title=%2B&action=edit&redlink=1" class="new" title="+ (page does not exist)">+</a> <a href="/index.php?title=Special:Upload&wpDestFile=%25%2Babc9" class="new" title="File:%+abc9">bar</a>
<a href="/index.php?title=3E&action=edit&redlink=1" class="new" title="3E (page does not exist)">3E</a> <a href="/index.php?title=3E%2B&action=edit&redlink=1" class="new" title="3E+ (page does not exist)">3E+</a>
</p>
+!! html/parsoid
+<p><a rel="mw:WikiLink" href="User:+%" title="User:+%">User:+%</a> <a rel="mw:WikiLink" href="Page+title%" title="Page+title%">Page+title%</a> <a rel="mw:WikiLink" href="%+" title="%+">%+</a> <a rel="mw:WikiLink" href="%+" title="%+">%20</a> <a rel="mw:WikiLink" href="%+" title="%+">%+ </a> <a rel="mw:WikiLink" href="%+r" title="%+r">%+r</a> <a rel="mw:WikiLink" href="%" title="%">%</a> <a rel="mw:WikiLink" href="+" title="+">+</a> <span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"[[bar]]"}'><a href="File:%+abc9"><img resource="./File:%25+abc9" src="./Special:FilePath/%+abc9" height="220" width="220"/></a></span> <a rel="mw:WikiLink" href="3E" title="3E">3E</a> <a rel="mw:WikiLink" href="3E+" title="3E+">3E+</a></p>
!! end
!! test
!! wikitext
[[File:Contains & ampersand.jpg]]
[[File:Does not exist.jpg|Title with & ampersand]]
-!! html
+!! html/php
<p><a href="/index.php?title=Special:Upload&wpDestFile=Contains_%26_ampersand.jpg" class="new" title="File:Contains & ampersand.jpg">File:Contains & ampersand.jpg</a>
<a href="/index.php?title=Special:Upload&wpDestFile=Does_not_exist.jpg" class="new" title="File:Does not exist.jpg">Title with & ampersand</a>
</p>
+!! html/parsoid
+<p><span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}]}'><a href="File:Contains_&_ampersand.jpg"><img resource="./File:Contains_&_ampersand.jpg" src="./Special:FilePath/Contains_&_ampersand.jpg" height="220" width="220"/></a></span>
+<span class="mw-default-size" typeof="mw:Error mw:Image" data-mw='{"errors":[{"key":"missing-image","message":"This image does not exist."}],"caption":"Title with & ampersand"}'><a href="File:Does_not_exist.jpg"><img resource="./File:Does_not_exist.jpg" src="./Special:FilePath/Does_not_exist.jpg" height="220" width="220"/></a></span></p>
!! end
-
!! test
Confirm that 'apos' named character reference doesn't make it to output (not legal in HTML 4)
!! wikitext
<li about="#cite_note-1" id="cite_note-1"><span rel="mw:referencedBy"><a href="#cite_ref-1-0">↑</a></span> foo</li></ol>
!!end
+!!test
+Ref: 17. Generate valid HTML5 id/about attributes
+!!options
+parsoid
+!!wikitext
+<ref name="a b">foo</ref>
+
+<references />
+!!html
+<p><span class="reference" id="cite_ref-a_b-1-0" rel="dc:references" typeof="mw:Extension/ref" data-mw='{"name":"ref","body":{"html":"foo"},"attrs":{"name":"a b"}}'><a href="#cite_note-a_b-1">[1]</a></span>
+</p>
+
+<ol class="references" typeof="mw:Extension/references" data-mw='{"name":"references","attrs":{}}'>
+<li id="cite_note-a_b-1"><span rel="mw:referencedBy"><a href="#cite_ref-a_b-1-0">↑</a></span> foo</li>
+!!end
+
!!test
References: 1. references tag without any refs should be handled properly
!!options
!! wikitext
<ref name="test & me">hi</ref>
!! html
-<p><span about="#mwt2" class="reference" id="cite_ref-test & me-1-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref name=\"test &amp; me\">hi</ref>"}' data-mw='{"name":"ref","body":{"html":"hi"},"attrs":{"name":"test & me"}}'><a href="#cite_note-test & me-1">[1]</a></span></p>
+<p><span about="#mwt2" class="reference" id="cite_ref-test_&_me-1-0" rel="dc:references" typeof="mw:Extension/ref" data-parsoid='{"src":"<ref name=\"test &amp; me\">hi</ref>"}' data-mw='{"name":"ref","body":{"html":"hi"},"attrs":{"name":"test & me"}}'><a href="#cite_note-test_&_me-1">[1]</a></span></p>
!! end
# This test is wt2html only because we're permitting the serializer to produce
!! options
parsoid=html2wt,wt2wt
!! wikitext
-''<nowiki>'foo'</nowiki>''
+''<nowiki/>'foo'<nowiki/>''
''<nowiki>''foo''</nowiki>''
''<nowiki>'''foo'''</nowiki>''
''foo''<nowiki/>'s
-'''<nowiki>'foo'</nowiki>'''
+'''<nowiki/>'foo'<nowiki/>'''
'''<nowiki>''foo''</nowiki>'''
'''<nowiki>'''foo'''</nowiki>'''
-'''<nowiki>foo'</nowiki>''<nowiki>bar'</nowiki>''baz'''
+'''foo'<nowiki/>''bar'<nowiki/>''baz'''
'''foo'''<nowiki/>'s
-'''foo''
+'<nowiki/>''foo''
''foo''<nowiki/>'
'<nowiki/>''foo''<nowiki/>'
-''''foo'''
+'<nowiki/>'''foo'''
'''foo'''<nowiki/>'
'<nowiki/>'''foo'''<nowiki/>'
''fools'<span> errand</span>''
''<span>fool</span>'s errand''
-!! html
+!! html/*
<p><i>'foo'</i>
<i>''foo''</i>
<i>'''foo'''</i>
'<i>foo</i>'
'<b>foo</b>
<b>foo</b>'
-'<b>foo</b>'</p>
+'<b>foo</b>'
<i>fools'<span> errand</span></i>
<i><span>fool</span>'s errand</i>
+</p>
!! end
!! test
!!test
Multi-line image caption generated by templates with/without trailing newlines
-!!options
-parsoid
!! wikitext
-[[File:foo.jpg|thumb|300px|foo\n{{echo|A}}\n{{echo|B}}\n{{echo|C}}]]
-[[File:foo.jpg|thumb|300px|foo\n{{echo|A}}\n{{echo|B}}\n{{echo|C}}\n\n]]
-!! html
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=Special:Upload&wpDestFile=Foo.jpg" class="new" title="File:Foo.jpg">File:Foo.jpg</a> <div class="thumbcaption">foo\nA\nB\nC</div></div></div>
-<div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/index.php?title=Special:Upload&wpDestFile=Foo.jpg" class="new" title="File:Foo.jpg">File:Foo.jpg</a> <div class="thumbcaption">foo\nA\nB\nC\n\n</div></div></div>
-
+[[File:Foobar.jpg|thumb|300x300px|foo\n{{echo|A}}\n{{echo|B}}\n{{echo|C}}]]
+[[File:Foobar.jpg|thumb|300x300px|foo\n{{echo|A}}\n{{echo|B}}\n{{echo|C}}\n\n]]
+!! html/parsoid
+<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg" height="34" width="300"/></a><figcaption>foo\n<span about="#mwt9" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"A"}},"i":0}}]}'>A</span>\n<span about="#mwt10" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"B"}},"i":0}}]}'>B</span>\n<span about="#mwt11" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"C"}},"i":0}}]}'>C</span></figcaption></figure>
+<figure typeof="mw:Image/Thumb"><a href="./File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/300px-Foobar.jpg" height="34" width="300"/></a><figcaption>foo\n<span about="#mwt12" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"A"}},"i":0}}]}'>A</span>\n<span about="#mwt13" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"B"}},"i":0}}]}'>B</span>\n<span about="#mwt14" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"C"}},"i":0}}]}'>C</span>\n\n</figcaption></figure>
!!end
!! test
<object data="test.swf"></object>
!!end
+!! test
+Don't block XML namespace declaration
+!! wikitext
+<span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">MediaWiki</span>
+!! html/php
+<p><span>MediaWiki</span>
+</p>
+!! html/parsoid
+<p><span xmlns:dct="http://purl.org/dc/terms/" data-x-property="dct:title" data-parsoid='{"stx":"html"}'>MediaWiki</span></p>
+!! end
+
# -----------------------------------------------------------------
# The following section of tests are primarily to spec requirements
# around serialization of new/edited content.
<p><a rel="mw:ExtLink" href="http://mi.wikipedia.org/wiki/Foo">Foo</a></p>
!! end
+!! test
+New wiki links (href variations)
+!! options
+parsoid=html2wt
+!! html
+<a rel="mw:WikiLink" href="./Foo_bar">Foo_bar</a>
+<a rel="mw:WikiLink" href="Foo_bar">Foo_bar</a>
+<a rel="mw:WikiLink" href="Foo bar">Foo_bar</a>
+<a rel="mw:WikiLink" href="./Toxine_bact%C3%A9rienne">Toxine bactérienne</a>
+!! wikitext
+[[Foo_bar]]
+[[Foo_bar]]
+[[Foo_bar]]
+[[Toxine bactérienne]]
+!! end
+
+!! test
+New wiki links (content string variations)
+!! options
+parsoid=html2wt
+!! html
+<a rel="mw:WikiLink" href="./Foo_bar">Foo_bar</a>
+<a rel="mw:WikiLink" href="./Foo_bar">Foo bar</a>
+<a rel="mw:WikiLink" href="./Foo_bar">./Foo_bar</a>
+!! wikitext
+[[Foo_bar]]
+[[Foo bar]]
+[[Foo_bar|./Foo_bar]]
+!! end
+
+!! test
+New category links (href variations)
+!! options
+parsoid=html2wt
+!! html
+<link rel="mw:PageProp/Category" href="./Category:Toxine_bactérienne" />
+<link rel="mw:PageProp/Category" href="./Category:Toxine_bact%C3%A9rienne" />
+<link rel="mw:PageProp/Category" href="Category:Toxine_bact%C3%A9rienne" />
+!! wikitext
+[[Category:Toxine bactérienne]]
+[[Category:Toxine bactérienne]]
+[[Category:Toxine bactérienne]]
+!! end
+
+!! test
+New interlanguage links (href variations)
+!! options
+parsoid=html2wt
+!! html
+<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Toxine bactérienne" />
+<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Toxine_bactérienne" />
+<link rel="mw:PageProp/Language" href="http://es.wikipedia.org/wiki/Toxine_bact%C3%A9rienne" />
+!! wikitext
+[[es:Toxine bactérienne]]
+[[es:Toxine_bactérienne]]
+[[es:Toxine_bactérienne]]
+!! end
+
!! test
Image: Modifying size of an image (1)
!! options
#!! options
#parsoid=html2wt
#language=ar
-#!! input
+#!! wikitext
#[[Imagen:Foobar.jpg|derecha|miniaturadeimagen]]
-#!! result
+#!! html
#<figure class="mw-default-size mw-halign-right" typeof="mw:Image/Thumb"><a href="Imagen:Foobar.jpg"><img resource="./Imagen:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="20" width="180"/></a></figure>
#!! end
!! test
Image: Block level image should have \n before and after
-!! options
-parsoid
!! wikitext
123
[[File:Foobar.jpg|right|thumb|150x150px]]
456
-!! html
-<p>123</p><figure typeof="mw:Image/Thumb" class="mw-halign-right"><a href="./File:Foobar.png"><img src="http://192.168.142.128/mw/images/thumb/b/bc/Foobar.png/131px-Foobar.png" width="131" height="150" resource="./File:Foobar.png" data-parsoid='{"a":{"resource":"./File:Foobar.png","width":"131"},"sa":{"resource":"File:Foobar.png","width":"150"}}'></a></figure><p>456</p>
+!! html/parsoid
+<p>123</p>
+<figure class="mw-halign-right" typeof="mw:Image/Thumb"><a href="File:Foobar.jpg"><img resource="./File:Foobar.jpg" src="//example.com/images/3/3a/Foobar.jpg" height="17" width="150"/></a></figure>
+<p>456</p>
!!end
!! test
Image: New block level image should have \n before and after (existing content)
-!! options
-parsoid
!! wikitext
123
[[File:Foobar.jpg|right|thumb|150x150px]]
456
-!! html
+!! html/parsoid
<p>123</p>
<figure class="mw-halign-right" typeof="mw:Image/Thumb" data-parsoid='{"optList":[{"ck":"right","ak":"right"},{"ck":"thumbnail","ak":"thumb"},{"ck":"width","ak":"150x150px"}]}'><a href="./File:Foobar.jpg" data-parsoid='{"a":{"href":"./File:Foobar.jpg"}}'><img resource="./File:Foobar.jpg" src="//example.com/images/thumb/3/3a/Foobar.jpg/150px-Foobar.jpg" height="17" width="150" data-parsoid='{"a":{"resource":"./File:Foobar.jpg","height":"17","width":"150"},"sa":{"resource":"File:Foobar.jpg"}}'/></a></figure>
<p>456</p>
!! wikitext
''A''<i>B</i>
-''A'''''<i>B</i>'''
+''A''<nowiki/>'''<i>B</i>'''
!! html
<p><i>A</i><i data-parsoid='{"stx":"html"}'>B</i></p>
<p><i>A</i><b><i data-parsoid='{"stx":"html"}'>B</i></b></p>
<link rel="mw:PageProp/redirect" href="Bar" data-parsoid='{"src":"#REDIRECT ","a":{"href":"./Foo"},"sa":{"href":"Foo"}}'>
!! end
+!! test
+T75121: Infer extension name from typeOf if data-mw is not present
+!! options
+parsoid=html2wt
+!! wikitext
+<foo />
+!! html
+<div typeOf="mw:Extension/foo"></div>
+!! end
+
# -----------------------------------------------------------------
# End of section for Parsoid-only html2wt tests for serialization
# of new content
*/
class ApiFormatWddxTest extends ApiFormatTestBase {
- /**
- * @requires function wddx_deserialize
- */
public function testValidSyntax( ) {
+ if ( !function_exists( 'wddx_deserialize' ) ) {
+ $this->markTestSkipped( "Function 'wddx_deserialize' not exist, skipping." );
+ }
+
$data = $this->apiRequest( 'wddx', array( 'action' => 'query', 'meta' => 'siteinfo' ) );
$this->assertInternalType( 'array', wddx_deserialize( $data ) );
assert.equal( $.escapeRE( '0123456789' ), '0123456789', 'escapeRE - Leave numbers alone' );
} );
- QUnit.test( 'Is functions', 15, function ( assert ) {
- assert.strictEqual( $.isDomElement( document.getElementById( 'qunit-header' ) ), true,
- 'isDomElement: #qunit-header Node' );
- assert.strictEqual( $.isDomElement( document.getElementById( 'random-name' ) ), false,
- 'isDomElement: #random-name (null)' );
+ QUnit.test( 'isDomElement', 6, function ( assert ) {
+ assert.strictEqual( $.isDomElement( document.createElement( 'div' ) ), true,
+ 'isDomElement: HTMLElement' );
+ assert.strictEqual( $.isDomElement( document.createTextNode( '' ) ), true,
+ 'isDomElement: TextNode' );
+ assert.strictEqual( $.isDomElement( null ), false,
+ 'isDomElement: null' );
assert.strictEqual( $.isDomElement( document.getElementsByTagName( 'div' ) ), false,
- 'isDomElement: getElementsByTagName Array' );
- assert.strictEqual( $.isDomElement( document.getElementsByTagName( 'div' )[0] ), true,
- 'isDomElement: getElementsByTagName(..)[0] Node' );
+ 'isDomElement: NodeList' );
assert.strictEqual( $.isDomElement( $( 'div' ) ), false,
- 'isDomElement: jQuery object' );
- assert.strictEqual( $.isDomElement( $( 'div' ).get( 0 ) ), true,
- 'isDomElement: jQuery object > Get node' );
- assert.strictEqual( $.isDomElement( document.createElement( 'div' ) ), true,
- 'isDomElement: createElement' );
+ 'isDomElement: jQuery' );
assert.strictEqual( $.isDomElement( { foo: 1 } ), false,
- 'isDomElement: Object' );
+ 'isDomElement: Plain Object' );
+ } );
+ QUnit.test( 'isEmpty', 7, function ( assert ) {
assert.strictEqual( $.isEmpty( 'string' ), false, 'isEmpty: "string"' );
assert.strictEqual( $.isEmpty( '0' ), true, 'isEmpty: "0"' );
assert.strictEqual( $.isEmpty( '' ), true, 'isEmpty: ""' );
} );
} );
+ QUnit.asyncTest( 'mw.loader with Object method as module name', 2, function ( assert ) {
+ var isAwesomeDone;
+
+ mw.loader.testCallback = function () {
+ QUnit.start();
+ assert.strictEqual( isAwesomeDone, undefined, 'Implementing module hasOwnProperty: isAwesomeDone should still be undefined' );
+ isAwesomeDone = true;
+ };
+
+ mw.loader.implement( 'hasOwnProperty', [QUnit.fixurl( mw.config.get( 'wgScriptPath' ) + '/tests/qunit/data/callMwLoaderTestCallback.js' )], {}, {} );
+
+ mw.loader.using( 'hasOwnProperty', function () {
+
+ // /sample/awesome.js declares the "mw.loader.testCallback" function
+ // which contains a call to start() and ok()
+ assert.strictEqual( isAwesomeDone, true, 'hasOwnProperty module should\'ve caused isAwesomeDone to be true' );
+ delete mw.loader.testCallback;
+
+ }, function () {
+ QUnit.start();
+ assert.ok( false, 'Error callback fired while loader.using "hasOwnProperty" module' );
+ } );
+ } );
+
QUnit.asyncTest( 'mw.loader.using( .. ).promise', 2, function ( assert ) {
var isAwesomeDone;