}
/**
- * Get the list of method names that have pending write queries or that
- * have transaction callbacks that have yet to run
+ * List the methods that have write queries or callbacks for the current transaction
*
- * @return array
+ * This method should not be used outside of Database/LoadBalancer
+ *
+ * @return string[]
+ * @since 1.32
*/
- protected function pendingWriteAndCallbackCallers() {
+ public function pendingWriteAndCallbackCallers() {
$fnames = $this->pendingWriteCallers();
foreach ( [
$this->trxIdleCallbacks,
if ( $conn->writesPending() ) {
// A callback from another handle wrote to this one and DBO_TRX is set
$this->queryLogger->warning( __METHOD__ . ": found writes pending." );
+ $fnames = implode( ', ', $conn->pendingWriteAndCallbackCallers() );
+ $this->queryLogger->warning(
+ __METHOD__ . ": found writes pending ($fnames).",
+ [
+ 'db_server' => $conn->getServer(),
+ 'db_name' => $conn->getDBname()
+ ]
+ );
} elseif ( $conn->trxLevel() ) {
// A callback from another handle read from this one and DBO_TRX is set,
// which can easily happen if there is only one DB (no replicas)
*/
private $linkRenderer;
+ /**
+ * @see LogFormatter::getMessageParameters
+ * @var array
+ */
+ protected $parsedParameters;
+
protected function __construct( LogEntry $entry ) {
$this->entry = $entry;
$this->context = RequestContext::getMain();
if ( 0 == $prefixLength ) {
# No prefix (not in list)--go to paragraph mode
# @todo consider using a stack for nestable elements like span, table and div
+
+ // P-wrapping and indent-pre are suppressed inside, not outside
+ $blockElems = 'table|h1|h2|h3|h4|h5|h6|pre|p|ul|ol|dl|li';
+ // P-wrapping and indent-pre are suppressed outside, not inside
+ $antiBlockElems = 'td|th';
+
$openMatch = preg_match(
- '/(?:<table|<h1|<h2|<h3|<h4|<h5|<h6|<pre|<tr|'
- . '<p|<ul|<ol|<dl|<li|<\\/tr|<\\/td|<\\/th)\\b/iS',
+ '/<('
+ . "({$blockElems})|\\/({$antiBlockElems})|"
+ // Always suppresses
+ . '\\/?(tr)'
+ . ')\\b/iS',
$t
);
$closeMatch = preg_match(
- '/(?:<\\/table|<\\/h1|<\\/h2|<\\/h3|<\\/h4|<\\/h5|<\\/h6|'
- . '<td|<th|<\\/?blockquote|<\\/?div|<hr|<\\/pre|<\\/p|<\\/mw:|'
- . Parser::MARKER_PREFIX
- . '-pre|<\\/li|<\\/ul|<\\/ol|<\\/dl|<\\/?center)\\b/iS',
+ '/<('
+ . "\\/({$blockElems})|({$antiBlockElems})|"
+ // Never suppresses
+ . '\\/?(center|blockquote|div|hr|mw:)'
+ . ')\\b/iS',
$t
);
+ // Any match closes the paragraph, but only when `!$closeMatch`
+ // do we enter block mode. The oddities with table rows and
+ // cells are to avoid paragraph wrapping in interstitial spaces
+ // leading to fostered content.
+
if ( $openMatch || $closeMatch ) {
$pendingPTag = false;
// Only close the paragraph if we're not inside a <pre> tag, or if
];
$context = new DerivativeContext( $this->getContext() );
$context->setTitle( $this->getPageTitle( 'raw' ) ); // Reset subpage
- $form = new HTMLForm( $fields, $context );
+ $form = new OOUIHTMLForm( $fields, $context );
$form->setSubmitTextMsg( 'watchlistedit-raw-submit' );
# Used message keys: 'accesskey-watchlistedit-raw-submit', 'tooltip-watchlistedit-raw-submit'
$form->setSubmitTooltip( 'watchlistedit-raw-submit' );
protected function getClearForm() {
$context = new DerivativeContext( $this->getContext() );
$context->setTitle( $this->getPageTitle( 'clear' ) ); // Reset subpage
- $form = new HTMLForm( [], $context );
+ $form = new OOUIHTMLForm( [], $context );
$form->setSubmitTextMsg( 'watchlistedit-clear-submit' );
# Used message keys: 'accesskey-watchlistedit-clear-submit', 'tooltip-watchlistedit-clear-submit'
$form->setSubmitTooltip( 'watchlistedit-clear-submit' );
* @return {jQuery.Promise} Received token.
*/
getToken: function ( type, assert ) {
- var apiPromise, promiseGroup, d;
+ var apiPromise, promiseGroup, d, reject;
type = mapLegacyToken( type );
promiseGroup = promises[ this.defaults.ajax.url ];
d = promiseGroup && promiseGroup[ type + 'Token' ];
type: type,
assert: assert
} );
+ reject = function () {
+ // Clear promise. Do not cache errors.
+ delete promiseGroup[ type + 'Token' ];
+
+ // Let caller handle the error code
+ return $.Deferred().rejectWith( this, arguments );
+ };
d = apiPromise
.then( function ( res ) {
+ if ( !res.query ) {
+ return reject( 'query-missing', res );
+ }
// If token type is unknown, it is omitted from the response
if ( !res.query.tokens[ type + 'token' ] ) {
return $.Deferred().reject( 'token-missing', res );
}
-
return res.query.tokens[ type + 'token' ];
- }, function () {
- // Clear promise. Do not cache errors.
- delete promiseGroup[ type + 'Token' ];
-
- // Let caller handle the error code
- return $.Deferred().rejectWith( this, arguments );
- } )
+ }, reject )
// Attach abort handler
.promise( { abort: apiPromise.abort } );
$formatter->setShowUserToolLinks( false );
$paramsWithoutTools = $formatter->getMessageParametersForTesting();
- unset( $formatter->parsedParameters );
- $formatter->setShowUserToolLinks( true );
- $paramsWithTools = $formatter->getMessageParametersForTesting();
+ $formatter2 = LogFormatter::newFromEntry( $entry );
+ $formatter2->setContext( $this->context );
+ $formatter2->setShowUserToolLinks( true );
+ $paramsWithTools = $formatter2->getMessageParametersForTesting();
$userLink = Linker::userLink(
$this->user->getId(),
$user = new TestUser( __METHOD__ );
list( $html, ) = $this->executeSpecialPage( 'clear', null, 'qqx', $user->getUser() );
$this->assertRegExp(
- '/<form class="mw-htmlform" action=".*?Special:EditWatchlist\/clear" method="post">/',
+ '/<form action=\'.*?Special:EditWatchlist\/clear\'/',
$html
);
}
$user = new TestUser( __METHOD__ );
list( $html, ) = $this->executeSpecialPage( 'raw', null, 'qqx', $user->getUser() );
$this->assertContains(
- '<textarea id="mw-input-wpTitles"',
+ '<div id=\'mw-input-wpTitles\'',
$html
);
}
} );
} );
+ QUnit.test( 'getToken() - no query', function ( assert ) {
+ var api = new mw.Api(),
+ // Same-origin warning and missing query in response.
+ serverRsp = {
+ warnings: {
+ tokens: {
+ '*': 'Tokens may not be obtained when the same-origin policy is not applied.'
+ }
+ }
+ };
+
+ this.server.respondWith( /type=testnoquery/, [ 200, { 'Content-Type': 'application/json' },
+ JSON.stringify( serverRsp )
+ ] );
+
+ return api.getToken( 'testnoquery' )
+ .then( function () { assert.fail( 'Expected response missing a query to be rejected' ); } )
+ .catch( function ( err, rsp ) {
+ assert.equal( err, 'query-missing', 'Expected no query error code' );
+ assert.deepEqual( rsp, serverRsp );
+ } );
+ } );
+
QUnit.test( 'getToken() - deprecated', function ( assert ) {
// Cache API endpoint from default to avoid cachehit in mw.user.tokens
var api = new mw.Api( { ajax: { url: '/postWithToken/api.php' } } ),
// See the full list at http://mochajs.org/
mochaOpts: {
ui: 'bdd',
- timeout: 20000
+ timeout: 60000
},
// =====