}
}
+ // "wpExtraQueryRedirect" is a hidden input to modify
+ // after save URL and is not used by actual edit form
+ $request = RequestContext::getMain()->getRequest();
+ $extraQueryRedirect = $request->getVal( 'wpExtraQueryRedirect' );
+
switch ( $status->value ) {
case self::AS_HOOK_ERROR_EXPECTED:
case self::AS_CONTENT_TOO_BIG:
case self::AS_SUCCESS_NEW_ARTICLE:
$query = $resultDetails['redirect'] ? 'redirect=no' : '';
+ if ( $extraQueryRedirect ) {
+ if ( $query === '' ) {
+ $query = $extraQueryRedirect;
+ } else {
+ $query = $query . '&' . $extraQueryRedirect;
+ }
+ }
$anchor = isset( $resultDetails['sectionanchor'] ) ? $resultDetails['sectionanchor'] : '';
$wgOut->redirect( $this->mTitle->getFullURL( $query ) . $anchor );
return false;
$extraQuery = 'redirect=no&' . $extraQuery;
}
}
+ if ( $extraQueryRedirect ) {
+ if ( $extraQuery === '' ) {
+ $extraQuery = $extraQueryRedirect;
+ } else {
+ $extraQuery = $extraQuery . '&' . $extraQueryRedirect;
+ }
+ }
+
$wgOut->redirect( $this->mTitle->getFullURL( $extraQuery ) . $sectionanchor );
return false;
* WARNING: do not use this function on arbitrary user-supplied titles!
* On heavily-used templates it will max out the memory.
*
- * @param array $options May be FOR UPDATE
+ * @param array $options Query option to Database::select()
* @return Title[] Array of Title the Title objects linking here
*/
public function getTemplateLinksTo( $options = [] ) {
* WARNING: do not use this function on arbitrary user-supplied titles!
* On heavily-used templates it will max out the memory.
*
- * @param array $options May be FOR UPDATE
+ * @param array $options Query option to Database::select()
* @param string $table Table name
* @param string $prefix Fields prefix
* @return array Array of Title objects linking here
return [];
}
- if ( count( $options ) > 0 ) {
- $db = wfGetDB( DB_MASTER );
- } else {
- $db = wfGetDB( DB_SLAVE );
- }
+ $db = wfGetDB( DB_SLAVE );
$blNamespace = "{$prefix}_namespace";
$blTitle = "{$prefix}_title";
return $wgLang;
}
+ // Checking if DB language is set
+ $dbPageLanguage = $this->getDbPageLanguageCode();
+ if ( $dbPageLanguage ) {
+ $pageLang = wfGetLangObj( $dbPageLanguage );
+ $variant = $pageLang->getPreferredVariant();
+ if ( $pageLang->getCode() !== $variant ) {
+ $pageLang = Language::factory( $variant );
+ }
+
+ return $pageLang;
+ }
+
// @note Can't be cached persistently, depends on user settings.
// @note ContentHandler::getPageViewLanguage() may need to load the
// content to determine the page language!
$this->addWhereIf( 'rc_user != 0', isset( $show['!anon'] ) );
$this->addWhereIf( 'rc_patrolled = 0', isset( $show['!patrolled'] ) );
$this->addWhereIf( 'rc_patrolled != 0', isset( $show['patrolled'] ) );
- $this->addWhereIf( 'wl_notificationtimestamp IS NOT NULL', isset( $show['unread'] ) );
- $this->addWhereIf( 'wl_notificationtimestamp IS NULL', isset( $show['!unread'] ) );
+ $this->addWhereIf( 'rc_timestamp >= wl_notificationtimestamp', isset( $show['unread'] ) );
+ $this->addWhereIf(
+ 'wl_notificationtimestamp IS NULL OR rc_timestamp < wl_notificationtimestamp',
+ isset( $show['!unread'] )
+ );
}
if ( !is_null( $params['type'] ) ) {
$params = [ 'redirect' => 'no' ];
}
- $articlelink = Linker::linkKnown(
+ $articlelink = Linker::link(
$rc->getTitle(),
null,
[ 'class' => 'mw-changeslist-title' ],
$table, $var, $cond = '', $fname = __METHOD__, $options = [], $join_conds = []
) {
if ( $var === '*' ) { // sanity
- throw new DBUnexpectedError( $this, "Cannot use a * field: got '$var'" );
+ throw new DBUnexpectedError( $this, "Cannot use a * field" );
+ } elseif ( !is_string( $var ) ) { // sanity
+ throw new DBUnexpectedError( $this, "Cannot use an array of fields" );
}
if ( !is_array( $options ) ) {
$url = $match['file'] . $match['query'];
$file = $local . $match['file'];
if (
- !CSSMin::isRemoteUrl( $url ) && !CSSMin::isLocalUrl( $url )
+ !self::isRemoteUrl( $url ) && !self::isLocalUrl( $url )
&& file_exists( $file )
) {
$mimeTypes[ CSSMin::getMimeType( $file ) ] = true;
/**
* Is this CSS rule referencing a remote URL?
*
- * @private Until we require PHP 5.5 and we can access self:: from closures.
* @param string $maybeUrl
* @return bool
*/
- public static function isRemoteUrl( $maybeUrl ) {
+ protected static function isRemoteUrl( $maybeUrl ) {
if ( substr( $maybeUrl, 0, 2 ) === '//' || parse_url( $maybeUrl, PHP_URL_SCHEME ) ) {
return true;
}
/**
* Is this CSS rule referencing a local URL?
*
- * @private Until we require PHP 5.5 and we can access self:: from closures.
* @param string $maybeUrl
* @return bool
*/
- public static function isLocalUrl( $maybeUrl ) {
+ protected static function isLocalUrl( $maybeUrl ) {
if ( $maybeUrl !== '' && $maybeUrl[0] === '/' && !self::isRemoteUrl( $maybeUrl ) ) {
return true;
}
global $wgUseRCPatrol, $wgUseNPPatrol, $wgLocalInterwikis,
$wgCanonicalServer, $wgScript;
$attribs = $rc->getAttributes();
+ if ( $attribs['rc_type'] == RC_CATEGORIZE ) {
+ // Don't send RC_CATEGORIZE events to IRC feed (T127360)
+ return null;
+ }
+
if ( $attribs['rc_type'] == RC_LOG ) {
// Don't use SpecialPage::getTitleFor, backwards compatibility with
// IRC API which expects "Log".
? $info['ResourceFileModulePaths']
: false;
if ( isset( $defaultPaths['localBasePath'] ) ) {
- $defaultPaths['localBasePath'] = "$dir/{$defaultPaths['localBasePath']}";
+ if ( $defaultPaths['localBasePath'] === '' ) {
+ // Avoid double slashes (e.g. /extensions/Example//path)
+ $defaultPaths['localBasePath'] = $dir;
+ } else {
+ $defaultPaths['localBasePath'] = "$dir/{$defaultPaths['localBasePath']}";
+ }
}
foreach ( [ 'ResourceModules', 'ResourceModuleSkinStyles' ] as $setting ) {
if ( isset( $info[$setting] ) ) {
foreach ( $info[$setting] as $name => $data ) {
if ( isset( $data['localBasePath'] ) ) {
- $data['localBasePath'] = "$dir/{$data['localBasePath']}";
+ if ( $data['localBasePath'] === '' ) {
+ // Avoid double slashes (e.g. /extensions/Example//path)
+ $data['localBasePath'] = $dir;
+ } else {
+ $data['localBasePath'] = "$dir/{$data['localBasePath']}";
+ }
}
if ( $defaultPaths ) {
$data += $defaultPaths;
// Try the local user from the slave DB
$localId = User::idFromName( $user->getName() );
+ $flags = 0;
// Fetch the user ID from the master, so that we don't try to create the user
// when they already exist, due to replication lag
// @codeCoverageIgnoreStart
if ( !$localId && wfGetLB()->getReaderIndex() != 0 ) {
$localId = User::idFromName( $user->getName(), User::READ_LATEST );
+ $flags = User::READ_LATEST;
}
// @codeCoverageIgnoreEnd
if ( $localId ) {
// User exists after all.
$user->setId( $localId );
- $user->loadFromId();
+ $user->loadFromId( $flags );
return false;
}
$status = $user->addToDatabase();
if ( !$status->isOK() ) {
// @codeCoverageIgnoreStart
- $logger->error( __METHOD__ . ': failed with message ' . $status->getWikiText(),
- [
- 'username' => $userName,
- ] );
- $user->setId( 0 );
- $user->loadFromId();
+ // double-check for a race condition (T70012)
+ $id = User::idFromName( $user->getName(), User::READ_LATEST );
+ if ( $id ) {
+ $logger->info( __METHOD__ . ': tried to autocreate existing user',
+ [
+ 'username' => $userName,
+ ] );
+ } else {
+ $logger->error( __METHOD__ . ': failed with message ' . $status->getWikiText(),
+ [
+ 'username' => $userName,
+ ] );
+ }
+ $user->setId( $id );
+ $user->loadFromId( User::READ_LATEST );
return false;
// @codeCoverageIgnoreEnd
}
$out->addReturnTo( $this->getPageTitle() );
}
+ /**
+ * Return an array of subpages beginning with $search that this special page will accept.
+ *
+ * @param string $search Prefix to search for
+ * @param int $limit Maximum number of results to return (usually 10)
+ * @param int $offset Number of results to skip (usually 0)
+ * @return string[] Matching subpages
+ */
+ public function prefixSearchSubpages( $search, $limit, $offset ) {
+ $user = User::newFromName( $search );
+ if ( !$user ) {
+ // No prefix suggestion for invalid user
+ return [];
+ }
+ // Autocomplete subpage as user list - public to allow caching
+ return UserNamePrefixSearch::search( 'public', $search, $limit, $offset );
+ }
+
protected function getGroupName() {
return 'users';
}
"uncategorizedtemplates": "Uncategorised templates",
"sessionfailure": "There seems to be a problem with your login session;\nthis action has been cancelled as a precaution against session hijacking.\nGo back to the previous page, reload that page and then try again.",
"blockiptext": "Use the form below to block write access from a specific IP address or username.\nThis should be done only to prevent vandalism, and in accordance with [[{{MediaWiki:Policy-url}}|policy]].\nFill in a specific reason below (for example, citing particular pages that were vandalised).",
+ "blocklogentry": "blocked [[$1]] with an expiry time of $2 $3",
+ "blockedtext": "<strong>Your username or IP address has been blocked.</strong>\n\nThe block was made by $1.\nThe reason given is <em>$2</em>.\n\n* Start of block: $8\n* Expiry of block: $6\n* Intended blockee: $7\n\nYou can contact $1 or another [[{{MediaWiki:Grouppage-sysop}}|administrator]] to discuss the block.\nYou cannot use the \"email this user\" feature unless a valid email address is specified in your [[Special:Preferences|account preferences]] and you have not been blocked from using it.\nYour current IP address is $3, and the block ID is #$5.\nPlease include all above details in any queries you make.",
+ "autoblockedtext": "Your IP address has been automatically blocked because it was used by another user, who was blocked by $1.\nThe reason given is:\n\n:<em>$2</em>\n\n* Start of block: $8\n* Expiry of block: $6\n* Intended blockee: $7\n\nYou may contact $1 or one of the other [[{{MediaWiki:Grouppage-sysop}}|administrators]] to discuss the block.\n\nNote that you may not use the \"email this user\" feature unless you have a valid email address registered in your [[Special:Preferences|user preferences]] and you have not been blocked from using it.\n\nYour current IP address is $3, and the block ID is #$5.\nPlease include all above details in any queries you make.",
+ "reblock-logentry": "changed block settings for [[$1]] with an expiry time of $2 $3",
+ "ipbexpiry": "Expiry:",
"ipbreason-dropdown": "*Common block reasons\n** Inserting false information\n** Removing content from pages\n** Spamming links to external sites\n** Inserting nonsense/gibberish into pages\n** Intimidating behaviour/harassment\n** Abusing multiple accounts\n** Unacceptable username",
"proxyblockreason": "Your IP address has been blocked because it is an open proxy.\nPlease contact your Internet service provider or technical support of your organisation and inform them of this serious security problem.",
"movecategorypage-warning": "<strong>Warning:</strong> You are about to move a category page. Please note that only the page will be moved and any pages in the old category will <em>not</em> be recategorised into the new one.",
"version-license-not-found": "No detailed licence information was found for this extension.",
"version-credits-summary": "We would like to recognise the following persons for their contribution to [[Special:Version|MediaWiki]].",
"version-license-info": "MediaWiki is free software; you can redistribute it and/or modify it under the terms of the GNU General Public Licence as published by the Free Software Foundation; either version 2 of the Licence, or (at your option) any later version.\n\nMediaWiki 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 Licence for more details.\n\nYou should have received [{{SERVER}}{{SCRIPTPATH}}/COPYING a copy of the GNU General Public Licence] along with this programme; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA or [//www.gnu.org/licenses/old-licenses/gpl-2.0.html read it online].",
- "feedback-error1": "Error: Unrecognised result from API"
+ "feedback-error1": "Error: Unrecognised result from API",
+ "logentry-block-block": "$1 {{GENDER:$2|blocked}} {{GENDER:$4|$3}} with an expiry time of $5 $6",
+ "logentry-block-reblock": "$1 {{GENDER:$2|changed}} block settings for {{GENDER:$4|$3}} with an expiry time of $5 $6",
+ "logentry-suppress-block": "$1 {{GENDER:$2|blocked}} {{GENDER:$4|$3}} with an expiry time of $5 $6",
+ "logentry-suppress-reblock": "$1 {{GENDER:$2|changed}} block settings for {{GENDER:$4|$3}} with an expiry time of $5 $6",
+ "protect_expiry_invalid": "Expiry time is invalid.",
+ "protect_expiry_old": "Expiry time is in the past.",
+ "protect-existing-expiry": "Existing expiry time: $3, $2",
+ "protect-existing-expiry-infinity": "Existing expiry time: infinite"
}
"subject-preview": "Subject preview:",
"previewerrortext": "An error occurred while attempting to preview your changes.",
"blockedtitle": "User is blocked",
- "blockedtext": "<strong>Your username or IP address has been blocked.</strong>\n\nThe block was made by $1.\nThe reason given is <em>$2</em>.\n\n* Start of block: $8\n* Expiry of block: $6\n* Intended blockee: $7\n\nYou can contact $1 or another [[{{MediaWiki:Grouppage-sysop}}|administrator]] to discuss the block.\nYou cannot use the \"email this user\" feature unless a valid email address is specified in your [[Special:Preferences|account preferences]] and you have not been blocked from using it.\nYour current IP address is $3, and the block ID is #$5.\nPlease include all above details in any queries you make.",
- "autoblockedtext": "Your IP address has been automatically blocked because it was used by another user, who was blocked by $1.\nThe reason given is:\n\n:<em>$2</em>\n\n* Start of block: $8\n* Expiry of block: $6\n* Intended blockee: $7\n\nYou may contact $1 or one of the other [[{{MediaWiki:Grouppage-sysop}}|administrators]] to discuss the block.\n\nNote that you may not use the \"email this user\" feature unless you have a valid email address registered in your [[Special:Preferences|user preferences]] and you have not been blocked from using it.\n\nYour current IP address is $3, and the block ID is #$5.\nPlease include all above details in any queries you make.",
+ "blockedtext": "<strong>Your username or IP address has been blocked.</strong>\n\nThe block was made by $1.\nThe reason given is <em>$2</em>.\n\n* Start of block: $8\n* Expiration of block: $6\n* Intended blockee: $7\n\nYou can contact $1 or another [[{{MediaWiki:Grouppage-sysop}}|administrator]] to discuss the block.\nYou cannot use the \"email this user\" feature unless a valid email address is specified in your [[Special:Preferences|account preferences]] and you have not been blocked from using it.\nYour current IP address is $3, and the block ID is #$5.\nPlease include all above details in any queries you make.",
+ "autoblockedtext": "Your IP address has been automatically blocked because it was used by another user, who was blocked by $1.\nThe reason given is:\n\n:<em>$2</em>\n\n* Start of block: $8\n* Expiration of block: $6\n* Intended blockee: $7\n\nYou may contact $1 or one of the other [[{{MediaWiki:Grouppage-sysop}}|administrators]] to discuss the block.\n\nNote that you may not use the \"email this user\" feature unless you have a valid email address registered in your [[Special:Preferences|user preferences]] and you have not been blocked from using it.\n\nYour current IP address is $3, and the block ID is #$5.\nPlease include all above details in any queries you make.",
"blockednoreason": "no reason given",
"whitelistedittext": "Please $1 to edit pages.",
"confirmedittext": "You must confirm your email address before editing pages.\nPlease set and validate your email address through your [[Special:Preferences|user preferences]].",
"protect-legend": "Confirm protection",
"protectcomment": "Reason:",
"protectexpiry": "Expires:",
- "protect_expiry_invalid": "Expiry time is invalid.",
- "protect_expiry_old": "Expiry time is in the past.",
+ "protect_expiry_invalid": "Expiration time is invalid.",
+ "protect_expiry_old": "Expiration time is in the past.",
"protect-unchain-permissions": "Unlock further protect options",
"protect-text": "Here you may view and change the protection level for the page <strong>$1</strong>.",
"protect-locked-blocked": "You cannot change protection levels while blocked.\nHere are the current settings for the page <strong>$1</strong>:",
"protect-cantedit": "You cannot change the protection levels of this page because you do not have permission to edit it.",
"protect-othertime": "Other time:",
"protect-othertime-op": "other time",
- "protect-existing-expiry": "Existing expiry time: $3, $2",
- "protect-existing-expiry-infinity": "Existing expiry time: infinite",
+ "protect-existing-expiry": "Existing expiration time: $3, $2",
+ "protect-existing-expiry-infinity": "Existing expiration time: infinite",
"protect-otherreason": "Other/additional reason:",
"protect-otherreason-op": "Other reason",
"protect-dropdown": "*Common protection reasons\n** Excessive vandalism\n** Excessive spamming\n** Counter-productive edit warring\n** High traffic page",
"blockip-legend": "Block user",
"blockiptext": "Use the form below to block write access from a specific IP address or username.\nThis should be done only to prevent vandalism, and in accordance with [[{{MediaWiki:Policy-url}}|policy]].\nFill in a specific reason below (for example, citing particular pages that were vandalized).\nYou can block IP ranges using the [https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing CIDR] syntax; the largest allowed range is /$1 for IPv4 and /$2 for IPv6.",
"ipaddressorusername": "IP address or username:",
- "ipbexpiry": "Expiry:",
+ "ipbexpiry": "Expiration:",
"ipbreason": "Reason:",
"ipbreason-dropdown": "*Common block reasons\n** Inserting false information\n** Removing content from pages\n** Spamming links to external sites\n** Inserting nonsense/gibberish into pages\n** Intimidating behavior/harassment\n** Abusing multiple accounts\n** Unacceptable username",
"ipb-hardblock": "Prevent logged-in users from editing from this IP address",
"blocklogpage": "Block log",
"blocklog-showlog": "This user has been blocked previously.\nThe block log is provided below for reference:",
"blocklog-showsuppresslog": "This user has been blocked and hidden previously.\nThe suppress log is provided below for reference:",
- "blocklogentry": "blocked [[$1]] with an expiry time of $2 $3",
- "reblock-logentry": "changed block settings for [[$1]] with an expiry time of $2 $3",
+ "blocklogentry": "blocked [[$1]] with an expiration time of $2 $3",
+ "reblock-logentry": "changed block settings for [[$1]] with an expiration time of $2 $3",
"blocklogtext": "This is a log of user blocking and unblocking actions.\nAutomatically blocked IP addresses are not listed.\nSee the [[Special:BlockList|block list]] for the list of currently operational bans and blocks.",
"unblocklogentry": "unblocked $1",
"block-log-flags-anononly": "anonymous users only",
"revdelete-uname-unhid": "username unhidden",
"revdelete-restricted": "applied restrictions to administrators",
"revdelete-unrestricted": "removed restrictions for administrators",
- "logentry-block-block": "$1 {{GENDER:$2|blocked}} {{GENDER:$4|$3}} with an expiry time of $5 $6",
+ "logentry-block-block": "$1 {{GENDER:$2|blocked}} {{GENDER:$4|$3}} with an expiration time of $5 $6",
"logentry-block-unblock": "$1 {{GENDER:$2|unblocked}} {{GENDER:$4|$3}}",
- "logentry-block-reblock": "$1 {{GENDER:$2|changed}} block settings for {{GENDER:$4|$3}} with an expiry time of $5 $6",
- "logentry-suppress-block": "$1 {{GENDER:$2|blocked}} {{GENDER:$4|$3}} with an expiry time of $5 $6",
- "logentry-suppress-reblock": "$1 {{GENDER:$2|changed}} block settings for {{GENDER:$4|$3}} with an expiry time of $5 $6",
+ "logentry-block-reblock": "$1 {{GENDER:$2|changed}} block settings for {{GENDER:$4|$3}} with an expiration time of $5 $6",
+ "logentry-suppress-block": "$1 {{GENDER:$2|blocked}} {{GENDER:$4|$3}} with an expiration time of $5 $6",
+ "logentry-suppress-reblock": "$1 {{GENDER:$2|changed}} block settings for {{GENDER:$4|$3}} with an expiration time of $5 $6",
"logentry-import-upload": "$1 {{GENDER:$2|imported}} $3 by file upload",
"logentry-import-upload-details": "$1 {{GENDER:$2|imported}} $3 by file upload ($4 {{PLURAL:$4|revision|revisions}})",
"logentry-import-interwiki": "$1 {{GENDER:$2|imported}} $3 from another wiki",
$( '<label>' )
.text( mw.msg( 'powersearch-togglelabel' ) )
).append(
- $( '<input type="button" />' )
+ $( '<input>' ).attr( 'type', 'button' )
.attr( 'id', 'mw-search-toggleall' )
.prop( 'value', mw.msg( 'powersearch-toggleall' ) )
.click( function () {
$checkboxes.prop( 'checked', true );
} )
).append(
- $( '<input type="button" />' )
+ $( '<input>' ).attr( 'type', 'button' )
.attr( 'id', 'mw-search-togglenone' )
.prop( 'value', mw.msg( 'powersearch-togglenone' ) )
.click( function () {
background-position: center center;
background-origin: border-box;
background-repeat: no-repeat;
- .background-size( @checkboxSize - 0.2em, @checkboxSize - 0.2em );
- background-size: 0 0;
+ .background-size( 0, 0 );
.box-sizing( border-box );
position: absolute;
// align the checkbox to middle of the text
// when the input is checked, style the label pseudo before element that followed as a checked checkbox
&:checked + label::before {
- background-size: 100% 100%;
+ .background-size( 100%, 100% );
}
&:active + label::before {
background-origin: border-box;
background-position: center center;
background-repeat: no-repeat;
- .background-size( @radioSize, @radioSize );
- background-size: 0 0;
+ .background-size( 0, 0 );
.box-sizing( border-box );
position: absolute;
left: 0;
// when the input is checked, style the label pseudo before element that followed as a checked radio
&:checked + label::before {
- background-size: 100% 100%;
+ .background-size( 100%, 100% );
}
&:active + label::before {
if ( spec.intercalarySize ) {
$.each( spec.intercalarySize, reduceFunc );
}
- $field = $( '<input type="text">' )
+ $field = $( '<input>' ).attr( 'type', 'text' )
.attr( {
tabindex: disabled ? -1 : 0,
size: spec.size,
* @private
*/
mw.widgets.datetime.DateTimeInputWidget.prototype.getInputElement = function () {
- return $( '<input type="hidden" />' );
+ return $( '<input>' ).attr( 'type', 'hidden' );
};
/**
* @protected
*/
mw.widgets.DateInputWidget.prototype.getInputElement = function () {
- return $( '<input type="hidden">' );
+ return $( '<input>' ).attr( 'type', 'hidden' );
};
/**
* @return {jQuery}
*/
function getHiddenInput( name, val ) {
- return $( '<input type="hidden" />' )
+ return $( '<input>' ).attr( 'type', 'hidden' )
.attr( 'name', name )
.val( val );
}
* @cfg {string} [apiUrl] api.php URL if the feedback page is on another wiki
* @cfg {string} [dialogTitleMessageKey="feedback-dialog-title"] Message key for the
* title of the dialog box
- * @cfg {mw.Uri|string} [bugsLink="//phabricator.wikimedia.org/maniphest/task/create/"] URL where
+ * @cfg {mw.Uri|string} [bugsLink="//phabricator.wikimedia.org/maniphest/task/edit/form/1/"] URL where
* bugs can be posted
* @cfg {mw.Uri|string} [bugsListLink="//phabricator.wikimedia.org/maniphest/query/advanced"] URL
* where bugs can be listed
this.messagePosterPromise = mw.messagePoster.factory.create( this.feedbackPageTitle, config.apiUrl );
// Links
- this.bugsTaskSubmissionLink = config.bugsLink || '//phabricator.wikimedia.org/maniphest/task/create/';
+ this.bugsTaskSubmissionLink = config.bugsLink || '//phabricator.wikimedia.org/maniphest/task/edit/form/1/';
this.bugsTaskListLink = config.bugsListLink || '//phabricator.wikimedia.org/maniphest/query/advanced';
// Terms of use
* @cover CSSMin::isRemoteUrl
*/
public function testIsRemoteUrl( $expect, $url ) {
- $this->assertEquals( CSSMin::isRemoteUrl( $url ), $expect );
+ $this->assertEquals( CSSMinTestable::isRemoteUrl( $url ), $expect );
}
public static function provideIsLocalUrls() {
* @cover CSSMin::isLocalUrl
*/
public function testIsLocalUrl( $expect, $url ) {
- $this->assertEquals( CSSMin::isLocalUrl( $url ), $expect );
+ $this->assertEquals( CSSMinTestable::isLocalUrl( $url ), $expect );
}
public static function provideRemapRemappingCases() {
];
}
}
+
+class CSSMinTestable extends CSSMin {
+ // Make some protected methods public
+ public static function isRemoteUrl( $maybeUrl ) {
+ return parent::isRemoteUrl( $maybeUrl );
+ }
+ public static function isLocalUrl( $maybeUrl ) {
+ return parent::isLocalUrl( $maybeUrl );
+ }
+}
],
],
[
- 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite (anonymous users only)',
+ 'text' => 'Sysop blocked Logtestuser with an expiration time of indefinite'
+ . ' (anonymous users only)',
'api' => [
'duration' => 'infinite',
'flags' => [ 'anononly' ],
],
[
'legacy' => true,
- 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite (anonymous users only)',
+ 'text' => 'Sysop blocked Logtestuser with an expiration time of indefinite'
+ . ' (anonymous users only)',
'api' => [
'duration' => 'infinite',
'flags' => [ 'anononly' ],
],
[
'legacy' => true,
- 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite',
+ 'text' => 'Sysop blocked Logtestuser with an expiration time of indefinite',
'api' => [
'duration' => 'infinite',
'flags' => [],
],
[
'legacy' => true,
- 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite',
+ 'text' => 'Sysop blocked Logtestuser with an expiration time of indefinite',
'api' => [
'duration' => 'infinite',
'flags' => [],
],
],
[
- 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of'
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiration time of'
. ' indefinite (anonymous users only)',
'api' => [
'duration' => 'infinite',
],
[
'legacy' => true,
- 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of'
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiration time of'
. ' indefinite (anonymous users only)',
'api' => [
'duration' => 'infinite',
],
[
'legacy' => true,
- 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of indefinite',
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiration time of indefinite',
'api' => [
'duration' => 'infinite',
'flags' => [],
],
],
[
- 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite (anonymous users only)',
+ 'text' => 'Sysop blocked Logtestuser with an expiration time of indefinite'
+ . ' (anonymous users only)',
'api' => [
'duration' => 'infinite',
'flags' => [ 'anononly' ],
],
[
'legacy' => true,
- 'text' => 'Sysop blocked Logtestuser with an expiry time of indefinite (anonymous users only)',
+ 'text' => 'Sysop blocked Logtestuser with an expiration time of indefinite'
+ . ' (anonymous users only)',
'api' => [
'duration' => 'infinite',
'flags' => [ 'anononly' ],
],
],
[
- 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of'
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiration time of'
. ' indefinite (anonymous users only)',
'api' => [
'duration' => 'infinite',
],
[
'legacy' => true,
- 'text' => 'Sysop changed block settings for Logtestuser with an expiry time of'
+ 'text' => 'Sysop changed block settings for Logtestuser with an expiration time of'
. ' indefinite (anonymous users only)',
'api' => [
'duration' => 'infinite',
}
public static function provideExtractResourceLoaderModules() {
- $dir = __DIR__ . '/FooBar/';
+ $dir = __DIR__ . '/FooBar';
return [
// Generic module with localBasePath/remoteExtPath specified
[
],
'test.bar' => [
'styles' => 'bar.js',
- 'localBasePath' => $dir . 'subdir',
+ 'localBasePath' => "$dir/subdir",
'remoteExtPath' => 'FooBar/subdir',
],
'test.class' => [
byteLimitTest( {
description: 'Plain text input',
- $input: $( '<input type="text"/>' ),
+ $input: $( '<input>' ).attr( 'type', 'text' ),
sample: simpleSample,
expected: simpleSample
} );
byteLimitTest( {
description: 'Plain text input. Calling byteLimit with no parameters and no maxlength attribute (bug 36310)',
- $input: $( '<input type="text"/>' )
+ $input: $( '<input>' ).attr( 'type', 'text' )
.byteLimit(),
sample: simpleSample,
expected: simpleSample
byteLimitTest( {
description: 'Limit using the maxlength attribute',
- $input: $( '<input type="text"/>' )
+ $input: $( '<input>' ).attr( 'type', 'text' )
.attr( 'maxlength', '10' )
.byteLimit(),
sample: simpleSample,
byteLimitTest( {
description: 'Limit using a custom value',
- $input: $( '<input type="text"/>' )
+ $input: $( '<input>' ).attr( 'type', 'text' )
.byteLimit( 10 ),
sample: simpleSample,
expected: '1234567890'
byteLimitTest( {
description: 'Limit using a custom value, overriding maxlength attribute',
- $input: $( '<input type="text"/>' )
+ $input: $( '<input>' ).attr( 'type', 'text' )
.attr( 'maxlength', '10' )
.byteLimit( 15 ),
sample: simpleSample,
byteLimitTest( {
description: 'Limit using a custom value (multibyte)',
- $input: $( '<input type="text"/>' )
+ $input: $( '<input>' ).attr( 'type', 'text' )
.byteLimit( 14 ),
sample: mbSample,
expected: '1234567890' + U_20AC + '1'
byteLimitTest( {
description: 'Limit using a custom value (multibyte) overlapping a byte',
- $input: $( '<input type="text"/>' )
+ $input: $( '<input>' ).attr( 'type', 'text' )
.byteLimit( 12 ),
sample: mbSample,
expected: '1234567890' + '12'
byteLimitTest( {
description: 'Pass the limit and a callback as input filter',
- $input: $( '<input type="text"/>' )
+ $input: $( '<input>' ).attr( 'type', 'text' )
.byteLimit( 6, function ( val ) {
var title = mw.Title.newFromText( String( val ) );
// Return without namespace prefix
byteLimitTest( {
description: 'Limit using the maxlength attribute and pass a callback as input filter',
- $input: $( '<input type="text"/>' )
+ $input: $( '<input>' ).attr( 'type', 'text' )
.attr( 'maxlength', '6' )
.byteLimit( function ( val ) {
var title = mw.Title.newFromText( String( val ) );
byteLimitTest( {
description: 'Pass the limit and a callback as input filter',
- $input: $( '<input type="text"/>' )
+ $input: $( '<input>' ).attr( 'type', 'text' )
.byteLimit( 6, function ( val ) {
var title = mw.Title.newFromText( String( val ) );
// Return without namespace prefix
byteLimitTest( {
description: 'Input filter that increases the length',
- $input: $( '<input type="text"/>' )
+ $input: $( '<input>' ).attr( 'type', 'text' )
.byteLimit( 10, function ( text ) {
return 'prefix' + text;
} ),
// Regression tests for bug 41450
byteLimitTest( {
description: 'Input filter of which the base exceeds the limit',
- $input: $( '<input type="text"/>' )
+ $input: $( '<input>' ).attr( 'type', 'text' )
.byteLimit( 3, function ( text ) {
return 'prefix' + text;
} ),
QUnit.test( 'Confirm properties and attributes set', 4, function ( assert ) {
var $el, $elA, $elB;
- $el = $( '<input type="text"/>' )
+ $el = $( '<input>' ).attr( 'type', 'text' )
.attr( 'maxlength', '7' )
.appendTo( '#qunit-fixture' )
.byteLimit();
assert.strictEqual( $el.attr( 'maxlength' ), '7', 'maxlength attribute unchanged for simple limit' );
- $el = $( '<input type="text"/>' )
+ $el = $( '<input>' ).attr( 'type', 'text' )
.attr( 'maxlength', '7' )
.appendTo( '#qunit-fixture' )
.byteLimit( 12 );
assert.strictEqual( $el.attr( 'maxlength' ), '12', 'maxlength attribute updated for custom limit' );
- $el = $( '<input type="text"/>' )
+ $el = $( '<input>' ).attr( 'type', 'text' )
.attr( 'maxlength', '7' )
.appendTo( '#qunit-fixture' )
.byteLimit( 12, function ( val ) {
assert.strictEqual( $el.attr( 'maxlength' ), undefined, 'maxlength attribute removed for limit with callback' );
- $elA = $( '<input type="text"/>' )
+ $elA = $( '<input>' ).attr( 'type', 'text' )
.addClass( 'mw-test-byteLimit-foo' )
.attr( 'maxlength', '7' )
.appendTo( '#qunit-fixture' );
- $elB = $( '<input type="text"/>' )
+ $elB = $( '<input>' ).attr( 'type', 'text' )
.addClass( 'mw-test-byteLimit-foo' )
.attr( 'maxlength', '12' )
.appendTo( '#qunit-fixture' );
// Use a new <input /> because the bug only occurs on the first time
// the limit it reached (bug 40850)
- $el = $( '<input type="text"/>' )
+ $el = $( '<input>' ).attr( 'type', 'text' )
.appendTo( '#qunit-fixture' )
.byteLimit( 3 )
.val( 'abc' ).trigger( 'change' )
assert.strictEqual( $el.val(), 'abc', 'Trim from the insertion point (at 0), not the end' );
- $el = $( '<input type="text"/>' )
+ $el = $( '<input>' ).attr( 'type', 'text' )
.appendTo( '#qunit-fixture' )
.byteLimit( 3 )
.val( 'abc' ).trigger( 'change' )