return $items;
}
+ /**
+ * More or less "markup-safe" str_replace()
+ * Ignores any instances of the separator inside `<...>`
+ * @param string $search
+ * @param string $replace
+ * @param string $text
+ * @return string
+ */
+ static function replaceMarkup( $search, $replace, $text ) {
+ $placeholder = "\x00";
+
+ // Remove placeholder instances
+ $text = str_replace( $placeholder, '', $text );
+
+ // Replace instances of the separator inside HTML-like tags with the placeholder
+ $replacer = new DoubleReplacer( $search, $placeholder );
+ $cleaned = StringUtils::delimiterReplaceCallback( '<', '>', $replacer->cb(), $text );
+
+ // Explode, then put the replaced separators back in
+ $cleaned = str_replace( $search, $replace, $cleaned );
+ $text = str_replace( $placeholder, $search, $cleaned );
+
+ return $text;
+ }
+
/**
* Escape a string to make it suitable for inclusion in a preg_replace()
* replacement parameter.
// Implies both are valid for table headings.
if ( $first_character === '!' ) {
- $line = str_replace( '!!', '||', $line );
+ $line = StringUtils::replaceMarkup( '!!', '||', $line );
}
# Split up multiple cells on the same line.
"api-error-unknownerror": "Unknown error: \"$1\".",
"api-error-uploaddisabled": "Uploading is disabled on this wiki.",
"api-error-verification-error": "This file might be corrupt, or have the wrong extension.",
+ "api-error-was-deleted": "A file of this name has been previously uploaded and subsequently deleted.",
"duration-seconds": "$1 {{PLURAL:$1|second|seconds}}",
"duration-minutes": "$1 {{PLURAL:$1|minute|minutes}}",
"duration-hours": "$1 {{PLURAL:$1|hour|hours}}",
"api-error-unknownerror": "API error message that can be used for client side localisation of API errors.\n\nParameters:\n* $1 - an unknown error message\n{{Identical|Unknown error}}",
"api-error-uploaddisabled": "API error message that can be used for client side localisation of API errors.",
"api-error-verification-error": "The word \"extension\" refers to the part behind the last dot in a file name, that by convention gives a hint about the kind of data format which a files contents are in.",
+ "api-error-was-deleted": "API error message that can be used for client side localisation of API errors.",
"duration-seconds": "Used as duration. Parameters:\n* $1 - number of seconds\n{{Related|Duration}}\n{{Identical|Second}}",
"duration-minutes": "Used as duration. Parameters:\n* $1 - number of minutes\n{{Related|Duration}}\n{{Identical|Minute}}",
"duration-hours": "Used as duration. Parameters:\n* $1 - number of hours\n{{Related|Duration}}",
'api-error-unknown-error',
'api-error-uploaddisabled',
'api-error-verification-error',
+ 'api-error-was-deleted',
'fileexists',
'filepageexists',
'filename-bad-prefix',
'filename-thumb-name',
'badfilename',
+ 'protectedpagetext',
'api-error-blacklisted', // HACK
],
],
);
}
- message = mw.message( 'api-error-' + error.code );
- if ( !message.exists() ) {
- message = mw.message( 'api-error-unknownerror', JSON.stringify( stateDetails ) );
+ if ( error.code === 'protectedpage' ) {
+ message = mw.message( 'protectedpagetext' );
+ } else {
+ message = mw.message( 'api-error-' + error.code );
+ if ( !message.exists() ) {
+ message = mw.message( 'api-error-unknownerror', JSON.stringify( stateDetails ) );
+ }
}
return new OO.ui.Error(
$( '<p>' ).append( message.parseDom() ),
$( '<p>' ).msg( 'fileexists', 'File:' + warnings.exists ),
{ recoverable: false }
);
+ } else if ( warnings[ 'exists-normalized' ] !== undefined ) {
+ return new OO.ui.Error(
+ $( '<p>' ).msg( 'fileexists', 'File:' + warnings[ 'exists-normalized' ] ),
+ { recoverable: false }
+ );
} else if ( warnings[ 'page-exists' ] !== undefined ) {
return new OO.ui.Error(
$( '<p>' ).msg( 'filepageexists', 'File:' + warnings[ 'page-exists' ] ),
$( '<p>' ).msg( 'api-error-duplicate-archive', 1 ),
{ recoverable: false }
);
+ } else if ( warnings[ 'was-deleted' ] !== undefined ) {
+ return new OO.ui.Error(
+ $( '<p>' ).msg( 'api-error-was-deleted' ),
+ { recoverable: false }
+ );
} else if ( warnings.badfilename !== undefined ) {
// Change the name if the current name isn't acceptable
// TODO This might not really be the best place to do this
<td data-parsoid='{"startTagSrc":"| ","attrSepSrc":"|","autoInsertedEnd":true}'><a rel="mw:ExtLink" href="ftp://|x||"></a>" onmouseover="alert(document.cookie)">test</td></tr></tbody></table>
!! end
+!! test
+Element attributes with double ! should not be broken up by <th>
+!! wikitext
+{|
+! hi <div class="!!">ha</div> ho
+|}
+!! html/php
+<table>
+<tr>
+<th> hi <div class="!!">ha</div> ho
+</th></tr></table>
+
+!! html/parsoid
+<table>
+<tbody><tr><th> hi <div class="!!" data-parsoid='{"stx":"html"}'>ha</div> ho</th></tr>
+</tbody></table>
+!! end
+
!! test
! and || in element attributes should not be parsed as <th>/<td>
!! wikitext