if ( in_array( $element, self::$voidElements ) ) {
if ( $wgWellFormedXml ) {
// Silly XML.
- return substr( $start, 0, -1 ) . ' />';
+ return substr( $start, 0, -1 ) . '/>';
}
return $start;
} else {
/** @var string SQL WHERE condition that selects source revisions to insert into destination */
protected $timeWhere;
- /** @var MWTimestamp|boolean Timestamp upto which history from the source will be merged */
+ /** @var MWTimestamp|bool Timestamp upto which history from the source will be merged */
protected $timestampLimit;
/** @var integer Number of revisions merged (for Special:MergeHistory success message) */
* MergeHistory constructor.
* @param Title $source Page from which history will be merged
* @param Title $dest Page to which history will be merged
- * @param string|boolean $timestamp Timestamp up to which history from the source will be merged
+ * @param string|bool $timestamp Timestamp up to which history from the source will be merged
*/
public function __construct( Title $source, Title $dest, $timestamp = false ) {
// Save the parameters
throw new MWException(
"Seeking $tailLength bytes from EOF failed in " . __METHOD__ );
}
- $tail = fread( $f, $tailLength );
+ $tail = $tailLength ? fread( $f, $tailLength ) : '';
fclose( $f );
wfDebug( __METHOD__ . ": analyzing head and tail of $file for magic numbers.\n" );
* @param string $script Raw HTML
*/
function addScript( $script ) {
- $this->mScripts .= $script . "\n";
+ $this->mScripts .= $script;
}
/**
* @param string $script JavaScript text, no "<script>" tags
*/
public function addInlineScript( $script ) {
- $this->mScripts .= Html::inlineScript( "\n$script\n" ) . "\n";
+ $this->mScripts .= Html::inlineScript( $script );
}
/**
* @return string HTML fragment
*/
function getHeadScripts() {
- return $this->getInlineHeadScripts() . "\n" . $this->getExternalHeadScripts();
+ return $this->getInlineHeadScripts() . $this->getExternalHeadScripts();
}
/**
# If wanted, and the interface is right-to-left, flip the CSS
$style_css = CSSJanus::transform( $style_css, true, false );
}
- $this->mInlineStyles .= Html::inlineStyle( $style_css ) . "\n";
+ $this->mInlineStyles .= Html::inlineStyle( $style_css );
}
/**
if ( $this->getLanguage()->getDir() !== $wgContLang->getDir() ) {
$previewedCSS = CSSJanus::transform( $previewedCSS, true, false );
}
- $otherTags[] = Html::inlineStyle( $previewedCSS ) . "\n";
+ $otherTags[] = Html::inlineStyle( $previewedCSS );
} else {
// Load the user styles normally
$moduleStyles[] = 'user';
ResourceLoaderModule::TYPE_STYLES
);
// Add normal styles added through addStyle()/addInlineStyle() here
- $links[] = implode( "\n", $this->buildCssLinksArray() ) . $this->mInlineStyles;
+ $links[] = implode( '', $this->buildCssLinksArray() ) . $this->mInlineStyles;
// Add marker tag to mark the place where the client-side
// loader should inject dynamic styles
// We use a <meta> tag with a made-up name for this because that's valid HTML
/**
* @param string $templateDir
- * @param boolean $forceRecompile
+ * @param bool $forceRecompile
*/
public function __construct( $templateDir = null, $forceRecompile = false ) {
$this->templateDir = $templateDir ?: __DIR__ . '/templates';
/** @var bool The (string) language code of the page's language and content code. */
private $mPageLanguage = false;
- /** @var string|boolean|null The page language code from the database, null if not saved in
+ /** @var string|bool|null The page language code from the database, null if not saved in
* the database or false if not loaded, yet. */
private $mDbPageLanguage = false;
/**
* Can $user perform $action on this page? This is an internal function,
- * which checks ONLY that previously checked by userCan (i.e. it leaves out
- * checks on wfReadOnly() and blocks)
+ * with multiple levels of checks depending on performance needs; see $rigor below.
+ * It does not check wfReadOnly().
*
* @param string $action Action that permission needs to be checked for
* @param User $user User to check
* to true in LocalSettings.php, otherwise returns false. If there is no language saved in
* the db, it will return NULL.
*
- * @return string|null|boolean
+ * @return string|null|bool
*/
private function getDbPageLanguageCode() {
global $wgPageLanguageUseDB;
*/
class WatchedItemStore {
+ const SORT_DESC = 'DESC';
+ const SORT_ASC = 'ASC';
+
/**
* @var LoadBalancer
*/
* @param User $user
* @param array $options Allowed keys:
* 'forWrite' => bool defaults to false
+ * 'sort' => string optional sorting by namespace ID and title
+ * one of the self::SORT_* constants
*
* @return WatchedItem[]
*/
public function getWatchedItemsForUser( User $user, array $options = [] ) {
$options += [ 'forWrite' => false ];
+ $dbOptions = [];
+ if ( array_key_exists( 'sort', $options ) ) {
+ Assert::parameter(
+ ( in_array( $options['sort'], [ self::SORT_ASC, self::SORT_DESC ] ) ),
+ '$options[\'sort\']',
+ 'must be SORT_ASC or SORT_DESC'
+ );
+ $dbOptions['ORDER BY'] = [
+ "wl_namespace {$options['sort']}",
+ "wl_title {$options['sort']}"
+ ];
+ }
$db = $this->getConnection( $options['forWrite'] ? DB_MASTER : DB_SLAVE );
+
$res = $db->select(
'watchlist',
[ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
[ 'wl_user' => $user->getId() ],
- __METHOD__
+ __METHOD__,
+ $dbOptions
);
$this->reuseConnection( $db );
* RFC 7232 § 2.2 for semantics.
* - etag: Return an entity-tag representing the state of all resources involved
* in the request. Quotes must be included. See RFC 7232 § 2.3 for semantics.
- * @return string|boolean|null As described above, or null if no value is available.
+ * @return string|bool|null As described above, or null if no value is available.
*/
public function getConditionalRequestData( $condition ) {
return null;
/**
* Send caching headers
- * @param boolean $isError Whether an error response is being output
+ * @param bool $isError Whether an error response is being output
* @since 1.26 added $isError parameter
*/
protected function sendCacheHeaders( $isError ) {
* the API.
*
* @param array $vars
- * @param boolean $forceHash
+ * @param bool $forceHash
* @return array
*/
public static function addMetadataToResultVars( $vars, $forceHash = true ) {
/**
* Returns whether or not storage is SHA-1 based
- * @return boolean
+ * @return bool
*/
public function hasSha1Storage() {
return $this->hasSha1Storage;
/**
* Returns whether or not repo supports having originals SHA-1s in the thumb URLs
- * @return boolean
+ * @return bool
*/
public function supportsSha1URLs() {
return $this->supportsSha1URLs;
class VFormHTMLForm extends HTMLForm {
/**
* Wrapper and its legend are never generated in VForm mode.
- * @var boolean
+ * @var bool
*/
protected $mWrapperLegend = false;
* @file
*/
class MWMessagePack {
- /** @var boolean|null Whether current system is bigendian. **/
+ /** @var bool|null Whether current system is bigendian. **/
public static $bigendian = null;
/**
}
return [ 'pageCount' => $count, 'dimensionsByPage' => $dimsByPage ];
- }
+ },
+ [ 'pcTTL' => WANObjectCache::TTL_INDEFINITE ]
);
}
/**
* Decodes a lossy chunk header
* @param string $header Header string
- * @return boolean|array See WebPHandler::decodeHeader
+ * @return bool|array See WebPHandler::decodeHeader
*/
protected static function decodeLossyChunkHeader( $header ) {
// Bytes 0-3 are 'VP8 '
/**
* Decodes a lossless chunk header
* @param string $header Header string
- * @return boolean|array See WebPHandler::decodeHeader
+ * @return bool|array See WebPHandler::decodeHeader
*/
public static function decodeLosslessChunkHeader( $header ) {
// Bytes 0-3 are 'VP8L'
/**
* Decodes an extended chunk header
* @param string $header Header string
- * @return boolean|array See WebPHandler::decodeHeader
+ * @return bool|array See WebPHandler::decodeHeader
*/
public static function decodeExtendedChunkHeader( $header ) {
// Bytes 0-3 are 'VP8X'
[],
// Automatically append redirect=no to each link, since most of them are
// redirect pages themselves.
- [ 'redirect' => 'no' ],
+ $title->isRedirect() ? [ 'redirect' => 'no' ] : [],
( $forceKnown ? [ 'known', 'noclasses' ] : [] )
) . '</li>';
}
protected $timeout;
/**
- * @var boolean Whether the key is a "might wait" key
+ * @var bool Whether the key is a "might wait" key
*/
private $isMightWaitKey;
/**
- * @var boolean Whether this process holds a "might wait" lock key
+ * @var bool Whether this process holds a "might wait" lock key
*/
private static $acquiredMightWaitKey = 0;
private $logger;
/** @var string JavaScript / CSS pragma to disable minification. **/
- const FILTER_NOMIN = ' /* @nomin */ ';
+ const FILTER_NOMIN = '/*@nomin*/';
/**
* Load information stored in the database about modules.
* @return string
*/
public static function makeLoaderConditionalScript( $script ) {
- return "(window.RLQ = window.RLQ || []).push(function () {\n" .
- trim( $script ) . "\n} );";
+ return '(window.RLQ=window.RLQ||[]).push(function(){' .
+ trim( $script ) . '});';
}
/**
$js = self::makeLoaderConditionalScript( $script );
return new WrappedString(
Html::inlineScript( $js ),
- "<script>(window.RLQ = window.RLQ || []).push(function () {\n",
- "\n} );</script>"
+ '<script>(window.RLQ=window.RLQ||[]).push(function(){',
+ '});</script>'
);
}
'mw.config.set',
[ $configuration ],
ResourceLoader::inDebugMode()
- ) . ResourceLoader::FILTER_NOMIN;
+ );
}
/**
/**
* Enable raw mode to omit mw.loader.state() call as mw.loader
* does not yet exist when these modules execute.
- * @var boolean
+ * @var bool
*/
protected $raw = true;
/**
* Generate the JavaScript content of this module.
*
- * Add '@nomin' annotation to prevent the module's contents from getting
- * cached (T84960).
+ * Add FILTER_NOMIN annotation to prevent needless minification and caching (T84960).
*
* @param ResourceLoaderContext $context
* @return string
*
* @param Site $site
*
- * @return boolean Success indicator
+ * @return bool Success indicator
*/
public function saveSite( Site $site ) {
$this->sites[$site->getGlobalId()] = $site;
*
* @param Site[] $sites
*
- * @return boolean Success indicator
+ * @return bool Success indicator
*/
public function saveSites( array $sites ) {
foreach ( $sites as $site ) {
'user_name = qcc_title',
'rc_user_text = qcc_title',
'rc_type != ' . $dbr->addQuotes( RC_EXTERNAL ), // Don't count wikidata.
+ 'rc_type != ' . $dbr->addQuotes( RC_CATEGORIZE ), // Don't count categorization changes.
'rc_log_type IS NULL OR rc_log_type != ' . $dbr->addQuotes( 'newusers' ),
'rc_timestamp >= ' . $dbr->addQuotes( $timestamp ),
];
*/
protected function getWatchlistInfo() {
$titles = [];
- $dbr = wfGetDB( DB_SLAVE );
- $res = $dbr->select(
- [ 'watchlist' ],
- [ 'wl_namespace', 'wl_title' ],
- [ 'wl_user' => $this->getUser()->getId() ],
- __METHOD__,
- [ 'ORDER BY' => [ 'wl_namespace', 'wl_title' ] ]
- );
+ $watchedItems = WatchedItemStore::getDefaultInstance()
+ ->getWatchedItemsForUser( $this->getUser(), [ 'sort' => WatchedItemStore::SORT_ASC ] );
$lb = new LinkBatch();
- foreach ( $res as $row ) {
- $lb->add( $row->wl_namespace, $row->wl_title );
- if ( !MWNamespace::isTalk( $row->wl_namespace ) ) {
- $titles[$row->wl_namespace][$row->wl_title] = 1;
+ foreach ( $watchedItems as $watchedItem ) {
+ $namespace = $watchedItem->getLinkTarget()->getNamespace();
+ $dbKey = $watchedItem->getLinkTarget()->getDBkey();
+ $lb->add( $namespace, $dbKey );
+ if ( !MWNamespace::isTalk( $namespace ) ) {
+ $titles[$namespace][$dbKey] = 1;
}
}
}
if ( isset( $watchedItemStore ) ) {
- $rcTitleValue = new TitleValue( $obj->rc_namespace, $obj->rc_title );
+ $rcTitleValue = new TitleValue( (int)$obj->rc_namespace, $obj->rc_title );
$rc->numberofWatchingusers = $watchedItemStore->countWatchers( $rcTitleValue );
} else {
$rc->numberofWatchingusers = 0;
}
/**
- * @return boolean True when the iterator is in a valid state
+ * @return bool True when the iterator is in a valid state
*/
public function valid() {
return (bool)$this->current;
}
/**
- * @return boolean True when this result set has rows
+ * @return bool True when this result set has rows
*/
public function hasChildren() {
return $this->current && count( $this->current );
* Return the byte-length output of the hash algorithm we are
* using in self::hash and self::hmac.
*
- * @param boolean $raw True to return the length for binary data, false to
+ * @param bool $raw True to return the length for binary data, false to
* return for hex-encoded
* @return int Number of bytes the hash outputs
*/
* making use of the best hash algorithm that we have available.
*
* @param string $data
- * @param boolean $raw True to return binary data, false to return it hex-encoded
+ * @param bool $raw True to return binary data, false to return it hex-encoded
* @return string A hash of the data
*/
public static function hash( $data, $raw = true ) {
*
* @param string $data
* @param string $key
- * @param boolean $raw True to return binary data, false to return it hex-encoded
+ * @param bool $raw True to return binary data, false to return it hex-encoded
* @return string An hmac hash of the data + key
*/
public static function hmac( $data, $key, $raw = true ) {
$startPos = 0;
}
+ if ( $this->getFileLength() === 0 ) {
+ $this->error( 'zip-wrong-format', "The file is empty." );
+ }
+
$block = $this->getBlock( $startPos );
$sigPos = strrpos( $block, "PK\x05\x06" );
if ( $sigPos === false ) {
*
* $( '#textbox' ).suggestions();
*
- * Uses jQuery.suggestions singleteon internally.
+ * Uses jQuery.suggestions singleton internally.
*
* @class jQuery.plugin.suggestions
*/
-/* Styles for user login and signup forms */
-.mw-form-related-link-container {
+/* User login and signup forms */
+.mw-ui-vform .mw-form-related-link-container {
margin-bottom: 0.5em;
text-align: center;
}
background: url( images/glyph-people-large.png ) no-repeat 50%;
margin: 0 auto;
padding-top: 7.8em;
+ font-weight: bold;
+}
+
+/* Login Button, following `ButtonWidget (progressive)` from OOjs UI */
+#mw-createaccount-join {
+ color: #347bff;
+}
+#mw-createaccount-join:hover {
+ background-color: #ebf2ff; /* rgba(52, 123, 255, 0.1); */
+ border-color: #859ecc;
+ box-shadow: none;
+}
+#mw-createaccount-join:active {
+ background-color: #ebf2ff;
+ color: #1f4999;
+ border-color: #1f4999;
+}
+#mw-createaccount-join:focus {
+ background-color: #fff;
+ color: #1f4999;
+ border-color: #1f4999;
+ box-shadow: inset 0 0 0 1px #1f4999;
+}
+#mw-createaccount-join:active:focus {
+ background-color: #ebf2ff;
}
*/
( function ( $, mw ) {
+ var interwikiPrefixes = [],
+ interwikiPrefixesPromise = new mw.Api().get( {
+ action: 'query',
+ meta: 'siteinfo',
+ siprop: 'interwikimap'
+ } ).done( function ( data ) {
+ $.each( data.query.interwikimap, function ( index, interwiki ) {
+ interwikiPrefixes.push( interwiki.prefix );
+ } );
+ } );
+
/**
* Mixin for title widgets
*
* @cfg {Object} [cache] Result cache which implements a 'set' method, taking keyed values as an argument
*/
mw.widgets.TitleWidget = function MwWidgetsTitleWidget( config ) {
- var widget = this;
-
// Config initialization
config = $.extend( {
maxLength: 255,
// Initialization
this.$element.addClass( 'mw-widget-titleWidget' );
- this.interwikiPrefixes = [];
- this.interwikiPrefixesPromise = new mw.Api().get( {
- action: 'query',
- meta: 'siteinfo',
- siprop: 'interwikimap'
- } ).done( function ( data ) {
- $.each( data.query.interwikimap, function ( index, interwiki ) {
- widget.interwikiPrefixes.push( interwiki.prefix );
- } );
- } );
};
/* Setup */
} };
if ( mw.Title.newFromText( query ) ) {
- return this.interwikiPrefixesPromise.then( function () {
+ return interwikiPrefixesPromise.then( function () {
var params,
interwiki = query.substring( 0, query.indexOf( ':' ) );
if (
interwiki && interwiki !== '' &&
- widget.interwikiPrefixes.indexOf( interwiki ) !== -1
+ interwikiPrefixes.indexOf( interwiki ) !== -1
) {
return $.Deferred().resolve( { query: {
pages: [ {
!! wikitext
External image: http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png
!! html
-<p>External image: <img src="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png" />
+<p>External image: <img src="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png"/>
</p>
!! end
!! wikitext
External image from https: https://meta.wikimedia.org/upload/f/f1/Ncwikicol.png
!! html
-<p>External image from https: <img src="https://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png" />
+<p>External image from https: <img src="https://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png"/>
</p>
!! end
!! wikitext
ja-style clickable images: [http://example.com http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png]
!! html/php
-<p>ja-style clickable images: <a rel="nofollow" class="external text" href="http://example.com"><img src="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png" /></a>
+<p>ja-style clickable images: <a rel="nofollow" class="external text" href="http://example.com"><img src="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png"/></a>
</p>
!! html/parsoid
<p>ja-style clickable images: <a rel="mw:ExtLink" href="http://example.com"><img src="http://meta.wikimedia.org/upload/f/f1/Ncwikicol.png" alt="Ncwikicol.png" data-parsoid='{"type":"extlink"}'/></a></p>
!! test
Table attributes with empty value
+!! options
+parsoid=wt2html,html2html
!! wikitext
{|
| style=| hello
!! html/parsoid
<table>
-<tbody>
-<tr>
-<td style=""> hello
-</td></tr></tbody></table>
-
+<tbody><tr><td style=""> hello</td></tr>
+</tbody></table>
!! end
!! test
{|
| testing [[one|two]] | three || four
| testing one two | three || four
+| testing="[[one|two]]" | three || four
|}
!! html/php
<table>
</td>
<td> three </td>
<td> four
+</td>
+<td> testing="<a href="/index.php?title=One&action=edit&redlink=1" class="new" title="One (page does not exist)">two</a>" | three </td>
+<td> four
</td></tr></table>
!! html/parsoid
<table>
<tbody><tr data-parsoid='{"autoInsertedEnd":true,"autoInsertedStart":true}'><td data-parsoid='{"autoInsertedEnd":true}'> testing <a rel="mw:WikiLink" href="./One" title="One" data-parsoid='{"stx":"piped","a":{"href":"./One"},"sa":{"href":"one"}}'>two</a> | three </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'> four</td>
-<td data-parsoid='{"a":{"testing":null,"one":null,"two":null},"sa":{"testing":"","one":"","two":""},"autoInsertedEnd":true}'> three </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'> four</td></tr>
+<td data-parsoid='{"a":{"testing":null,"one":null,"two":null},"sa":{"testing":"","one":"","two":""},"autoInsertedEnd":true}'> three </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'> four</td>
+<td> testing="<a rel="mw:WikiLink" href="./One" title="One" data-parsoid='{"stx":"piped","a":{"href":"./One"},"sa":{"href":"one"}}'>two</a>" | three </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'> four</td></tr>
</tbody></table>
!! end
!! test
div with empty attribute value, space before equals
+!! options
+parsoid=wt2html,html2html
!! wikitext
<div class =>HTML rocks</div>
-!! html
+!! html/php
<div class="">HTML rocks</div>
+!! html/parsoid
+<div class="" data-parsoid='{"stx":"html"}'>HTML rocks</div>
!! end
-# FIXME: Parsoid doesn't match the html5 spec
!! test
div with multiple empty attribute values
!! options
<div id="title.3D">HTML rocks</div>
!! html/parsoid
-<div id="" title="">HTML rocks</div>
+<div id="title=" data-parsoid='{"stx":"html"}'>HTML rocks</div>
!! end
-# FIXME: Parsoid doesn't match the html5 spec
!! test
table with multiple empty attribute values
!! options
</td></tr></table>
!! html/parsoid
-<table title="" id="">
+<table title="id=">
<tbody><tr><td> hi</td></tr>
</tbody></table>
!! end
!! test
Attribute test: equals, then nothing
+!! options
+parsoid=wt2html,html2html
!! wikitext
<font color=>foo</font>
-!! html
+!! html/php
<p><font color="">foo</font>
</p>
+!! html/parsoid
+<p><font color="" data-parsoid='{"stx":"html"}'>foo</font></p>
!! end
!! test
Attribute test: unquoted value
+!! options
+parsoid=wt2html,html2html
!! wikitext
<font color=x>foo</font>
-!! html
+!! html/php
<p><font color="x">foo</font>
</p>
+!! html/parsoid
+<p><font color="x" data-parsoid='{"stx":"html"}'>foo</font></p>
!! end
!! test
!! test
Fuzz testing: Parser14-table
+!! options
+parsoid=wt2html,html2html
!! wikitext
==a==
{| STYLE=__TOC__
<td></td>
</tr>
</table>
+!! html/parsoid
+<h2>a</h2>
+<table style="__TOC__"></table>
!! end
# Known to produce bogus xml (extra </td>)
!! wikitext
http://www.example.org/pic.png <-- U+3000 (vim: ^Vu3000)
!! html
-<p><img src="http://www.example.org/pic.png" alt="pic.png" /> <-- U+3000 (vim: ^Vu3000)
+<p><img src="http://www.example.org/pic.png" alt="pic.png"/> <-- U+3000 (vim: ^Vu3000)
</p>
!! end
}
/**
- * @return boolean
+ * @return bool
*/
private function oncePerClass() {
// Remember current test class in the database connection,
$this->setMwGlobals( 'wgWellFormedXml', true );
$this->assertEquals(
- '<img />',
+ '<img/>',
Html::element( 'img', null, '' ),
'Self-closing tag for short-tag elements (wgWellFormedXml = true)'
);
// Load module script only
array(
array( 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS ),
- "<script>(window.RLQ = window.RLQ || []).push(function () {\n"
+ "<script>(window.RLQ=window.RLQ||[]).push(function(){"
. 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.foo\u0026only=scripts\u0026skin=fallback");'
- . "\n} );</script>"
+ . "});</script>"
),
array(
// Don't condition wrap raw modules (like the startup module)
// Load private module (only=scripts)
array(
array( 'test.quux', ResourceLoaderModule::TYPE_SCRIPTS ),
- "<script>(window.RLQ = window.RLQ || []).push(function () {\n"
- . "mw.test.baz({token:123});mw.loader.state({\"test.quux\":\"ready\"});\n"
- . "} );</script>"
+ "<script>(window.RLQ=window.RLQ||[]).push(function(){"
+ . "mw.test.baz({token:123});mw.loader.state({\"test.quux\":\"ready\"});"
+ . "});</script>"
),
// Load private module (combined)
array(
array( 'test.quux', ResourceLoaderModule::TYPE_COMBINED ),
- "<script>(window.RLQ = window.RLQ || []).push(function () {\n"
+ "<script>(window.RLQ=window.RLQ||[]).push(function(){"
. "mw.loader.implement(\"test.quux\",function($,jQuery){"
. "mw.test.baz({token:123});},{\"css\":[\".mw-icon{transition:none}"
- . "\"]});\n} );</script>"
+ . "\"]});});</script>"
),
// Load no modules
array(
// Load two modules in separate groups
array(
array( array( 'test.group.foo', 'test.group.bar' ), ResourceLoaderModule::TYPE_COMBINED ),
- "<script>(window.RLQ = window.RLQ || []).push(function () {\n"
+ "<script>(window.RLQ=window.RLQ||[]).push(function(){"
. 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.group.bar\u0026skin=fallback");'
- . "\n} );</script>\n"
- . "<script>(window.RLQ = window.RLQ || []).push(function () {\n"
+ . "});</script>\n"
+ . "<script>(window.RLQ=window.RLQ||[]).push(function(){"
. 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.group.foo\u0026skin=fallback");'
- . "\n} );</script>"
+ . "});</script>"
),
);
// @codingStandardsIgnoreEnd
->with(
'watchlist',
[ 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ],
- [ 'wl_user' => 1 ]
+ [ 'wl_user' => 1 ],
+ $this->isType( 'string' ),
+ [ 'ORDER BY' => [ 'wl_namespace ASC', 'wl_title ASC' ] ]
)
->will( $this->returnValue( [] ) );
$watchedItems = $store->getWatchedItemsForUser(
$user,
- [ 'forWrite' => $forWrite ]
+ [ 'forWrite' => $forWrite, 'sort' => WatchedItemStore::SORT_ASC ]
);
$this->assertEquals( [], $watchedItems );
}
+ public function testGetWatchedItemsForUser_badSortOptionThrowsException() {
+ $store = new WatchedItemStore(
+ $this->getMockLoadBalancer( $this->getMockDb() ),
+ $this->getMockCache()
+ );
+
+ $this->setExpectedException( 'InvalidArgumentException' );
+ $store->getWatchedItemsForUser(
+ $this->getMockNonAnonUserWithId( 1 ),
+ [ 'sort' => 'foo' ]
+ );
+ }
+
public function testIsWatchedItem_existingItem() {
$mockDb = $this->getMockDb();
$mockDb->expects( $this->once() )
$this->assertEquals(
'<label for="year">From year (and earlier):</label> ' .
- '<input id="year" maxlength="4" size="7" type="number" value="2011" name="year" /> ' .
+ '<input id="year" maxlength="4" size="7" type="number" value="2011" name="year"/> ' .
'<label for="month">From month (and earlier):</label> ' .
'<select name="month" id="month" class="mw-month-selector">' .
'<option value="-1">all</option>' . "\n" .
);
$this->assertEquals(
'<label for="year">From year (and earlier):</label> ' .
- '<input id="year" maxlength="4" size="7" type="number" value="2011" name="year" /> ' .
+ '<input id="year" maxlength="4" size="7" type="number" value="2011" name="year"/> ' .
'<label for="month">From month (and earlier):</label> ' .
'<select name="month" id="month" class="mw-month-selector">' .
'<option value="-1">all</option>' . "\n" .
$this->assertEquals(
'<label for="year">From year (and earlier):</label> ' .
- '<input id="year" maxlength="4" size="7" type="number" name="year" /> ' .
+ '<input id="year" maxlength="4" size="7" type="number" name="year"/> ' .
'<label for="month">From month (and earlier):</label> ' .
'<select name="month" id="month" class="mw-month-selector">' .
'<option value="-1">all</option>' . "\n" .
--- /dev/null
+<?php
+
+/**
+ * @author Addshore
+ *
+ * @group Database
+ *
+ * @covers SpecialEditWatchlist
+ */
+class SpecialEditWatchlistTest extends SpecialPageTestBase {
+
+ /**
+ * Returns a new instance of the special page under test.
+ *
+ * @return SpecialPage
+ */
+ protected function newSpecialPage() {
+ return new SpecialEditWatchlist();
+ }
+
+ public function testNotLoggedIn_throwsException() {
+ $this->setExpectedException( 'UserNotLoggedIn' );
+ $this->executeSpecialPage();
+ }
+
+ public function testRootPage_displaysExplanationMessage() {
+ $user = new TestUser( __METHOD__ );
+ list( $html, ) = $this->executeSpecialPage( '', null, 'qqx', $user->getUser() );
+ $this->assertContains( '(watchlistedit-normal-explain)', $html );
+ }
+
+ public function testClearPage_hasClearButtonForm() {
+ $user = new TestUser( __METHOD__ );
+ list( $html, ) = $this->executeSpecialPage( 'clear', null, 'qqx', $user->getUser() );
+ $this->assertRegExp(
+ '/<form action=".*?Special:EditWatchlist\/clear" method="post" class="visualClear">/',
+ $html
+ );
+ }
+
+ public function testEditRawPage_hasTitlesBox() {
+ $user = new TestUser( __METHOD__ );
+ list( $html, ) = $this->executeSpecialPage( 'raw', null, 'qqx', $user->getUser() );
+ $this->assertContains(
+ '<textarea id="mw-input-wpTitles"',
+ $html
+ );
+ }
+
+}
--- /dev/null
+<?php
+
+/**
+ * @author Addshore
+ *
+ * @group Database
+ *
+ * @covers SpecialWatchlist
+ */
+class SpecialWatchlistTest extends SpecialPageTestBase {
+
+ /**
+ * Returns a new instance of the special page under test.
+ *
+ * @return SpecialPage
+ */
+ protected function newSpecialPage() {
+ return new SpecialWatchlist();
+ }
+
+ public function testNotLoggedIn_throwsException() {
+ $this->setExpectedException( 'UserNotLoggedIn' );
+ $this->executeSpecialPage();
+ }
+
+ public function testUserWithNoWatchedItems_displaysNoWatchlistMessage() {
+ $user = new TestUser( __METHOD__ );
+ list( $html, ) = $this->executeSpecialPage( '', null, 'qqx', $user->getUser() );
+ $this->assertContains( '(nowatchlist)', $html );
+ }
+
+}