r14586 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r14585‎ | r14586 | r14587 >
Date:06:27, 6 June 2006
Author:brion
Status:old
Tags:
Comment:
Backport fixes and bump to 1.6.7
* Fix oddity with open tag parameters getting stuck on </li>
* (bug 5384) Fix <!-- comments --> in <ref> extension
* Nesting of different tag extensions and comments should now work more
consistently and more safely. A cleaner, one-pass tag strip lets the
'outer' tag either take source (<nowiki>-style) or pass it down to
further parsing (<ref>-style). There should no longer be surprise
expansion of foreign extensions inside HTML output, or differences
in behavior based on the order tags are loaded.
* (bug 885) Pre-save transform no longer silently appends close tags
* Pre-save transform no longer changes the case of close tags
* Edit security precautions in raw HTML mode, etc
Modified paths:
  • /branches/REL1_6/phase3/RELEASE-NOTES (modified) (history)
  • /branches/REL1_6/phase3/includes/DefaultSettings.php (modified) (history)
  • /branches/REL1_6/phase3/includes/EditPage.php (modified) (history)
  • /branches/REL1_6/phase3/includes/Parser.php (modified) (history)
  • /branches/REL1_6/phase3/includes/Sanitizer.php (modified) (history)
  • /branches/REL1_6/phase3/languages/Messages.php (modified) (history)
  • /branches/REL1_6/phase3/maintenance/parserTests.txt (modified) (history)

Diff [purge]

Index: branches/REL1_6/phase3/maintenance/parserTests.txt
@@ -265,7 +265,15 @@
266266 </p>
267267 !! end
268268
 269+!! test
 270+Comment semantics: unclosed comment at end
 271+!! input
 272+<!--This comment will run out to the end of the document
 273+!! result
269274
 275+!! end
 276+
 277+
270278 ###
271279 ### Preformatted text
272280 ###
@@ -2337,7 +2345,36 @@
23382346 This template has <!-- a comment --> in it.
23392347 !! end
23402348
 2349+!! test
 2350+pre-save transform: unclosed tag
 2351+!! options
 2352+pst noxml
 2353+!! input
 2354+<nowiki>'''not wiki'''
 2355+!! result
 2356+<nowiki>'''not wiki'''
 2357+!! end
23412358
 2359+!! test
 2360+pre-save transform: mixed tag case
 2361+!! options
 2362+pst noxml
 2363+!! input
 2364+<NOwiki>'''not wiki'''</noWIKI>
 2365+!! result
 2366+<NOwiki>'''not wiki'''</noWIKI>
 2367+!! end
 2368+
 2369+!! test
 2370+pre-save transform: unclosed comment in <nowiki>
 2371+!! options
 2372+pst noxml
 2373+!! input
 2374+wiki<nowiki>nowiki<!--nowiki</nowiki>wiki
 2375+!! result
 2376+wiki<nowiki>nowiki<!--nowiki</nowiki>wiki
 2377+!!end
 2378+
23422379 !! article
23432380 Template:dangerous
23442381 !!text
Index: branches/REL1_6/phase3/includes/Parser.php
@@ -9,6 +9,7 @@
1010 /** */
1111 require_once( 'Sanitizer.php' );
1212 require_once( 'HttpFunctions.php' );
 13+require_once( 'ImageGallery.php' );
1314
1415 /**
1516 * Update this version number when the ParserOutput format
@@ -304,100 +305,87 @@
305306 function getOptions() { return $this->mOptions; }
306307
307308 /**
308 - * Replaces all occurrences of <$tag>content</$tag> in the text
309 - * with a random marker and returns the new text. the output parameter
310 - * $content will be an associative array filled with data on the form
311 - * $unique_marker => content.
 309+ * Replaces all occurrences of HTML-style comments and the given tags
 310+ * in the text with a random marker and returns teh next text. The output
 311+ * parameter $matches will be an associative array filled with data in
 312+ * the form:
 313+ * 'UNIQ-xxxxx' => array(
 314+ * 'element',
 315+ * 'tag content',
 316+ * array( 'param' => 'x' ),
 317+ * '<element param="x">tag content</element>' ) )
312318 *
313 - * If $content is already set, the additional entries will be appended
314 - * If $tag is set to STRIP_COMMENTS, the function will extract
315 - * <!-- HTML comments -->
 319+ * @param $elements list of element names. Comments are always extracted.
 320+ * @param $text Source text string.
 321+ * @param $uniq_prefix
316322 *
317 - * @access private
 323+ * @private
318324 * @static
319325 */
320 - function extractTagsAndParams($tag, $text, &$content, &$tags, &$params, $uniq_prefix = ''){
321 - $rnd = $uniq_prefix . '-' . $tag . Parser::getRandomString();
322 - if ( !$content ) {
323 - $content = array( );
324 - }
 326+ function extractTagsAndParams($elements, $text, &$matches, $uniq_prefix = ''){
 327+ $rand = Parser::getRandomString();
325328 $n = 1;
326329 $stripped = '';
 330+ $matches = array();
327331
328 - if ( !$tags ) {
329 - $tags = array( );
330 - }
 332+ $taglist = implode( '|', $elements );
 333+ $start = "/<($taglist)(\\s+[^>]*?|\\s*?)(\/?>)|<(!--)/i";
331334
332 - if ( !$params ) {
333 - $params = array( );
334 - }
335 -
336 - if( $tag == STRIP_COMMENTS ) {
337 - $start = '/<!--()/';
338 - $end = '/-->/';
339 - } else {
340 - $start = "/<$tag(\\s+[^>]*|\\s*\/?)>/i";
341 - $end = "/<\\/$tag\\s*>/i";
342 - }
343 -
344335 while ( '' != $text ) {
345336 $p = preg_split( $start, $text, 2, PREG_SPLIT_DELIM_CAPTURE );
346337 $stripped .= $p[0];
347 - if( count( $p ) < 3 ) {
 338+ if( count( $p ) < 5 ) {
348339 break;
349340 }
350 - $attributes = $p[1];
351 - $inside = $p[2];
352 -
353 - // If $attributes ends with '/', we have an empty element tag, <tag />
354 - if( $tag != STRIP_COMMENTS && substr( $attributes, -1 ) == '/' ) {
355 - $attributes = substr( $attributes, 0, -1);
356 - $empty = '/';
 341+ if( count( $p ) > 5 ) {
 342+ // comment
 343+ $element = $p[4];
 344+ $attributes = '';
 345+ $close = '';
 346+ $inside = $p[5];
357347 } else {
358 - $empty = '';
 348+ // tag
 349+ $element = $p[1];
 350+ $attributes = $p[2];
 351+ $close = $p[3];
 352+ $inside = $p[4];
359353 }
360354
361 - $marker = $rnd . sprintf('%08X', $n++);
 355+ $marker = "$uniq_prefix-$element-$rand" . sprintf('%08X', $n++) . '-QINU';
362356 $stripped .= $marker;
363357
364 - $tags[$marker] = "<$tag$attributes$empty>";
365 - $params[$marker] = Sanitizer::decodeTagAttributes( $attributes );
366 -
367 - if ( $empty === '/' ) {
 358+ if ( $close === '/>' ) {
368359 // Empty element tag, <tag />
369 - $content[$marker] = null;
 360+ $content = null;
370361 $text = $inside;
 362+ $tail = null;
371363 } else {
372 - $q = preg_split( $end, $inside, 2 );
373 - $content[$marker] = $q[0];
374 - if( count( $q ) < 2 ) {
 364+ if( $element == '!--' ) {
 365+ $end = '/(-->)/';
 366+ } else {
 367+ $end = "/(<\\/$element\\s*>)/i";
 368+ }
 369+ $q = preg_split( $end, $inside, 2, PREG_SPLIT_DELIM_CAPTURE );
 370+ $content = $q[0];
 371+ if( count( $q ) < 3 ) {
375372 # No end tag -- let it run out to the end of the text.
376 - break;
 373+ $tail = '';
 374+ $text = '';
377375 } else {
378 - $text = $q[1];
 376+ $tail = $q[1];
 377+ $text = $q[2];
379378 }
380379 }
 380+
 381+ $matches[$marker] = array( $element,
 382+ $content,
 383+ Sanitizer::decodeTagAttributes( $attributes ),
 384+ "<$element$attributes$close$content$tail" );
381385 }
382386 return $stripped;
383387 }
384388
385389 /**
386 - * Wrapper function for extractTagsAndParams
387 - * for cases where $tags and $params isn't needed
388 - * i.e. where tags will never have params, like <nowiki>
389 - *
390 - * @access private
391 - * @static
392 - */
393 - function extractTags( $tag, $text, &$content, $uniq_prefix = '' ) {
394 - $dummy_tags = array();
395 - $dummy_params = array();
396 -
397 - return Parser::extractTagsAndParams( $tag, $text, $content,
398 - $dummy_tags, $dummy_params, $uniq_prefix );
399 - }
400 -
401 - /**
402390 * Strips and renders nowiki, pre, math, hiero
403391 * If $render is set, performs necessary rendering operations on plugins
404392 * Returns the text, and fills an array with data needed in unstrip()
@@ -408,145 +396,98 @@
409397 * for section editing, where these comments cause confusion when
410398 * counting the sections in the wikisource
411399 *
412 - * @access private
 400+ * @private
413401 */
414402 function strip( $text, &$state, $stripcomments = false ) {
415403 $render = ($this->mOutputType == OT_HTML);
416 - $html_content = array();
417 - $nowiki_content = array();
418 - $math_content = array();
419 - $pre_content = array();
420 - $comment_content = array();
421 - $ext_content = array();
422 - $ext_tags = array();
423 - $ext_params = array();
424 - $gallery_content = array();
425404
426405 # Replace any instances of the placeholders
427406 $uniq_prefix = $this->mUniqPrefix;
428407 #$text = str_replace( $uniq_prefix, wfHtmlEscapeFirst( $uniq_prefix ), $text );
429 -
430 - # html
 408+ $commentState = array();
 409+
 410+ $elements = array_merge(
 411+ array( 'nowiki', 'pre', 'gallery' ),
 412+ array_keys( $this->mTagHooks ) );
431413 global $wgRawHtml;
432414 if( $wgRawHtml ) {
433 - $text = Parser::extractTags('html', $text, $html_content, $uniq_prefix);
434 - foreach( $html_content as $marker => $content ) {
435 - if ($render ) {
436 - # Raw and unchecked for validity.
437 - $html_content[$marker] = $content;
438 - } else {
439 - $html_content[$marker] = '<html>'.$content.'</html>';
440 - }
441 - }
 415+ $elements[] = 'html';
442416 }
443 -
444 - # nowiki
445 - $text = Parser::extractTags('nowiki', $text, $nowiki_content, $uniq_prefix);
446 - foreach( $nowiki_content as $marker => $content ) {
447 - if( $render ){
448 - $nowiki_content[$marker] = wfEscapeHTMLTagsOnly( $content );
449 - } else {
450 - $nowiki_content[$marker] = '<nowiki>'.$content.'</nowiki>';
451 - }
452 - }
453 -
454 - # math
455417 if( $this->mOptions->getUseTeX() ) {
456 - $text = Parser::extractTags('math', $text, $math_content, $uniq_prefix);
457 - foreach( $math_content as $marker => $content ){
458 - if( $render ) {
459 - $math_content[$marker] = renderMath( $content );
460 - } else {
461 - $math_content[$marker] = '<math>'.$content.'</math>';
462 - }
463 - }
 418+ $elements[] = 'math';
464419 }
 420+
465421
466 - # pre
467 - $text = Parser::extractTags('pre', $text, $pre_content, $uniq_prefix);
468 - foreach( $pre_content as $marker => $content ){
469 - if( $render ){
470 - $pre_content[$marker] = '<pre>' . wfEscapeHTMLTagsOnly( $content ) . '</pre>';
 422+ $matches = array();
 423+ $text = Parser::extractTagsAndParams( $elements, $text, $matches, $uniq_prefix );
 424+
 425+ foreach( $matches as $marker => $data ) {
 426+ list( $element, $content, $params, $tag ) = $data;
 427+ if( $render ) {
 428+ $tagName = strtolower( $element );
 429+ switch( $tagName ) {
 430+ case '!--':
 431+ // Comment
 432+ if( substr( $tag, -3 ) == '-->' ) {
 433+ $output = $tag;
 434+ } else {
 435+ // Unclosed comment in input.
 436+ // Close it so later stripping can remove it
 437+ $output = "$tag-->";
 438+ }
 439+ break;
 440+ case 'html':
 441+ if( $wgRawHtml ) {
 442+ $output = $content;
 443+ break;
 444+ }
 445+ // Shouldn't happen otherwise. :)
 446+ case 'nowiki':
 447+ $output = wfEscapeHTMLTagsOnly( $content );
 448+ break;
 449+ case 'math':
 450+ $output = renderMath( $content );
 451+ break;
 452+ case 'pre':
 453+ // Backwards-compatibility hack
 454+ $content = preg_replace( '!<nowiki>(.*?)</nowiki>!is', '\\1', $content );
 455+ $output = '<pre>' . wfEscapeHTMLTagsOnly( $content ) . '</pre>';
 456+ break;
 457+ case 'gallery':
 458+ $output = $this->renderImageGallery( $content );
 459+ break;
 460+ default:
 461+ if( isset( $this->mTagHooks[$tagName] ) ) {
 462+ $output = call_user_func_array( $this->mTagHooks[$tagName],
 463+ array( $content, $params, &$this ) );
 464+ } else {
 465+ wfDebugDieBacktrace( "Invalid call hook $element" );
 466+ }
 467+ }
471468 } else {
472 - $pre_content[$marker] = '<pre>'.$content.'</pre>';
 469+ // Just stripping tags; keep the source
 470+ $output = $tag;
473471 }
474 - }
475 -
476 - # gallery
477 - $text = Parser::extractTags('gallery', $text, $gallery_content, $uniq_prefix);
478 - foreach( $gallery_content as $marker => $content ) {
479 - require_once( 'ImageGallery.php' );
480 - if ( $render ) {
481 - $gallery_content[$marker] = $this->renderImageGallery( $content );
 472+ if( !$stripcomments && $element == '!--' ) {
 473+ $commentState[$marker] = $output;
482474 } else {
483 - $gallery_content[$marker] = '<gallery>'.$content.'</gallery>';
 475+ $state[$element][$marker] = $output;
484476 }
485477 }
486478
487 - # Comments
488 - $text = Parser::extractTags(STRIP_COMMENTS, $text, $comment_content, $uniq_prefix);
489 - foreach( $comment_content as $marker => $content ){
490 - $comment_content[$marker] = '<!--'.$content.'-->';
491 - }
492 -
493 - # Extensions
494 - foreach ( $this->mTagHooks as $tag => $callback ) {
495 - $ext_content[$tag] = array();
496 - $text = Parser::extractTagsAndParams( $tag, $text, $ext_content[$tag],
497 - $ext_tags[$tag], $ext_params[$tag], $uniq_prefix );
498 - foreach( $ext_content[$tag] as $marker => $content ) {
499 - $full_tag = $ext_tags[$tag][$marker];
500 - $params = $ext_params[$tag][$marker];
501 - if ( $render )
502 - $ext_content[$tag][$marker] = call_user_func_array( $callback, array( $content, $params, &$this ) );
503 - else {
504 - if ( is_null( $content ) ) {
505 - // Empty element tag
506 - $ext_content[$tag][$marker] = $full_tag;
507 - } else {
508 - $ext_content[$tag][$marker] = "$full_tag$content</$tag>";
509 - }
510 - }
511 - }
512 - }
513 -
514479 # Unstrip comments unless explicitly told otherwise.
515480 # (The comments are always stripped prior to this point, so as to
516481 # not invoke any extension tags / parser hooks contained within
517482 # a comment.)
518483 if ( !$stripcomments ) {
519 - $tempstate = array( 'comment' => $comment_content );
520 - $text = $this->unstrip( $text, $tempstate );
521 - $comment_content = array();
 484+ // Put them all back and forget them
 485+ $text = strtr( $text, $commentState );
522486 }
523487
524 - # Merge state with the pre-existing state, if there is one
525 - if ( $state ) {
526 - $state['html'] = $state['html'] + $html_content;
527 - $state['nowiki'] = $state['nowiki'] + $nowiki_content;
528 - $state['math'] = $state['math'] + $math_content;
529 - $state['pre'] = $state['pre'] + $pre_content;
530 - $state['gallery'] = $state['gallery'] + $gallery_content;
531 - $state['comment'] = $state['comment'] + $comment_content;
532 -
533 - foreach( $ext_content as $tag => $array ) {
534 - if ( array_key_exists( $tag, $state ) ) {
535 - $state[$tag] = $state[$tag] + $array;
536 - }
537 - }
538 - } else {
539 - $state = array(
540 - 'html' => $html_content,
541 - 'nowiki' => $nowiki_content,
542 - 'math' => $math_content,
543 - 'pre' => $pre_content,
544 - 'gallery' => $gallery_content,
545 - 'comment' => $comment_content,
546 - ) + $ext_content;
547 - }
548488 return $text;
549489 }
550490
 491+
551492 /**
552493 * restores pre, math, and hiero removed by strip()
553494 *
@@ -558,20 +499,21 @@
559500 return $text;
560501 }
561502
562 - # Must expand in reverse order, otherwise nested tags will be corrupted
563 - foreach( array_reverse( $state, true ) as $tag => $contentDict ) {
 503+ $replacements = array();
 504+ foreach( $state as $tag => $contentDict ) {
564505 if( $tag != 'nowiki' && $tag != 'html' ) {
565 - foreach( array_reverse( $contentDict, true ) as $uniq => $content ) {
566 - $text = str_replace( $uniq, $content, $text );
 506+ foreach( $contentDict as $uniq => $content ) {
 507+ $replacements[$uniq] = $content;
567508 }
568509 }
569510 }
 511+ $text = strtr( $text, $replacements );
570512
571513 return $text;
572514 }
573515
574516 /**
575 - * always call this after unstrip() to preserve the order
 517+ * Always call this after unstrip() to preserve the order
576518 *
577519 * @access private
578520 */
@@ -580,17 +522,15 @@
581523 return $text;
582524 }
583525
584 - # Must expand in reverse order, otherwise nested tags will be corrupted
585 - for ( $content = end($state['nowiki']); $content !== false; $content = prev( $state['nowiki'] ) ) {
586 - $text = str_replace( key( $state['nowiki'] ), $content, $text );
587 - }
588 -
589 - global $wgRawHtml;
590 - if ($wgRawHtml) {
591 - for ( $content = end($state['html']); $content !== false; $content = prev( $state['html'] ) ) {
592 - $text = str_replace( key( $state['html'] ), $content, $text );
 526+ $replacements = array();
 527+ foreach( $state as $tag => $contentDict ) {
 528+ if( $tag == 'nowiki' || $tag == 'html' ) {
 529+ foreach( $contentDict as $uniq => $content ) {
 530+ $replacements[$uniq] = $content;
 531+ }
593532 }
594533 }
 534+ $text = strtr( $text, $replacements );
595535
596536 return $text;
597537 }
@@ -605,14 +545,7 @@
606546 function insertStripItem( $text, &$state ) {
607547 $rnd = $this->mUniqPrefix . '-item' . Parser::getRandomString();
608548 if ( !$state ) {
609 - $state = array(
610 - 'html' => array(),
611 - 'nowiki' => array(),
612 - 'math' => array(),
613 - 'pre' => array(),
614 - 'comment' => array(),
615 - 'gallery' => array(),
616 - );
 549+ $state = array();
617550 }
618551 $state['item'][$rnd] = $text;
619552 return $rnd;
@@ -3588,6 +3521,7 @@
35893522 * @return The old value of the mTagHooks array associated with the hook
35903523 */
35913524 function setHook( $tag, $callback ) {
 3525+ $tag = strtolower( $tag );
35923526 $oldVal = @$this->mTagHooks[$tag];
35933527 $this->mTagHooks[$tag] = $callback;
35943528
Index: branches/REL1_6/phase3/includes/EditPage.php
@@ -23,7 +23,7 @@
2424 var $formtype;
2525 var $firsttime;
2626 var $lastDelete;
27 - var $mTokenOk = true;
 27+ var $mTokenOk = false;
2828 var $tooBig = false;
2929 var $kblength = false;
3030 var $missingComment = false;
@@ -356,19 +356,17 @@
357357 $this->preview = $request->getCheck( 'wpPreview' ) || $request->getCheck( 'wpLivePreview' );
358358 $this->diff = $request->getCheck( 'wpDiff' );
359359
360 - if( !$this->preview ) {
361 - if ( $this->tokenOk( $request ) ) {
362 - # Some browsers will not report any submit button
363 - # if the user hits enter in the comment box.
364 - # The unmarked state will be assumed to be a save,
365 - # if the form seems otherwise complete.
366 - wfDebug( "$fname: Passed token check.\n" );
367 - } else {
368 - # Page might be a hack attempt posted from
369 - # an external site. Preview instead of saving.
370 - wfDebug( "$fname: Failed token check; forcing preview\n" );
371 - $this->preview = true;
372 - }
 360+ if ( $this->tokenOk( $request ) ) {
 361+ # Some browsers will not report any submit button
 362+ # if the user hits enter in the comment box.
 363+ # The unmarked state will be assumed to be a save,
 364+ # if the form seems otherwise complete.
 365+ wfDebug( "$fname: Passed token check.\n" );
 366+ } else {
 367+ # Page might be a hack attempt posted from
 368+ # an external site. Preview instead of saving.
 369+ wfDebug( "$fname: Failed token check; forcing preview\n" );
 370+ $this->preview = true;
373371 }
374372 }
375373 $this->save = ! ( $this->preview OR $this->diff );
@@ -1084,7 +1082,7 @@
10851083 # For a bit more sophisticated detection of blank summaries, hash the
10861084 # automatic one and pass that in a hidden field.
10871085 $autosumm = $this->autoSumm ? $this->autoSumm : md5( $this->summary );
1088 - $wgOut->addHTML( "<input type=\"hidden\" name=\"wpAutoSummary\" value=\"$autosumm\" />\n" );
 1086+ $wgOut->addHtml( wfHidden( 'wpAutoSummary', $autosumm ) );
10891087
10901088 if ( $this->isConflict ) {
10911089 require_once( "DifferenceEngine.php" );
@@ -1245,9 +1243,17 @@
12461244 $parserOptions = ParserOptions::newFromUser( $wgUser );
12471245 $parserOptions->setEditSection( false );
12481246
 1247+ global $wgRawHtml;
 1248+ if( $wgRawHtml && !$this->mTokenOk ) {
 1249+ // Could be an offsite preview attempt. This is very unsafe if
 1250+ // HTML is enabled, as it could be an attack.
 1251+ return $wgOut->parse( "<div class='previewnote'>" .
 1252+ wfMsg( 'session_fail_preview_html' ) . "</div>" );
 1253+ }
 1254+
12491255 # don't parse user css/js, show message about preview
12501256 # XXX: stupid php bug won't let us use $wgTitle->isCssJsSubpage() here
1251 -
 1257+
12521258 if ( $this->isCssJsSubpage ) {
12531259 if(preg_match("/\\.css$/", $wgTitle->getText() ) ) {
12541260 $previewtext = wfMsg('usercsspreview');
Index: branches/REL1_6/phase3/includes/Sanitizer.php
@@ -391,8 +391,8 @@
392392 if ( $t == 'table' ) {
393393 $tagstack = array_pop( $tablestack );
394394 }
395 - $newparams = '';
396395 }
 396+ $newparams = '';
397397 } else {
398398 # Keep track for later
399399 if ( in_array( $t, $tabletags ) &&
Index: branches/REL1_6/phase3/includes/DefaultSettings.php
@@ -32,7 +32,7 @@
3333 $wgConf = new SiteConfiguration;
3434
3535 /** MediaWiki version number */
36 -$wgVersion = '1.6.6';
 36+$wgVersion = '1.6.7';
3737
3838 /** Name of the site. It must be changed in LocalSettings.php */
3939 $wgSitename = 'MediaWiki';
Index: branches/REL1_6/phase3/RELEASE-NOTES
@@ -5,11 +5,41 @@
66
77 == Mediawiki 1.6.7 ==
88
 9+June 6, 2006
 10+
 11+MediaWiki 1.6.7 is a security and bugfix maintenance release of the
 12+Spring 2006 snapshot:
 13+
 14+An HTML/JavaScript-injection vulnerability in the edit form has been closed.
 15+This vulnerability was new in 1.6.0; MediaWiki versions 1.5.x or earlier are
 16+not affected.
 17+
 18+Extensions, comments, and <nowiki> sections are now handled in a one-pass
 19+way which is more reliable and safer. Under earlier versions of MediaWiki,
 20+certain extensions could be abused to inject HTML/JavaScript into the page.
 21+
 22+Additional precautions are made against offsite form submissions when
 23+the restricted raw HTML mode is enabled.
 24+
 25+Some small localization and user interface updates are also included.
 26+
927 * (bug 6051) Improvement to German localisation (de)
1028 * (bug 6017) Update bookstore list for German language (de)
1129 * (bug 6138) Minor grammar tweak in "loginreqlink"
1230 * (bug 5957) Update for Hebrew language (he)
 31+* Fix oddity with open tag parameters getting stuck on </li>
 32+* (bug 5384) Fix <!-- comments --> in <ref> extension
 33+* Nesting of different tag extensions and comments should now work more
 34+ consistently and more safely. A cleaner, one-pass tag strip lets the
 35+ 'outer' tag either take source (<nowiki>-style) or pass it down to
 36+ further parsing (<ref>-style). There should no longer be surprise
 37+ expansion of foreign extensions inside HTML output, or differences
 38+ in behavior based on the order tags are loaded.
 39+* (bug 885) Pre-save transform no longer silently appends close tags
 40+* Pre-save transform no longer changes the case of close tags
 41+* Edit security precautions in raw HTML mode, etc
1342
 43+
1444 == MediaWiki 1.6.6 ==
1545
1646 May 23, 2006
Index: branches/REL1_6/phase3/languages/Messages.php
@@ -511,6 +511,13 @@
512512 Please try again. If it still doesn\'t work, try logging out and logging back in.</strong>',
513513 'previewconflict' => 'This preview reflects the text in the upper
514514 text editing area as it will appear if you choose to save.',
 515+'session_fail_preview_html' => '<strong>Sorry! We could not process your edit due to a loss of session data.</strong>
 516+
 517+\'\'Because this wiki has raw HTML enabled, the preview is hidden as a precaution against JavaScript attacks.\'\'
 518+
 519+<strong>If this is a legitimate edit attempt, please try again. If it still doesn\'t work, try logging out and logging back in.</strong>',
 520+'previewconflict' => 'This preview reflects the text in the upper
 521+text editing area as it will appear if you choose to save.',
515522 'importing' => 'Importing $1',
516523 'editing' => 'Editing $1',
517524 'editingsection' => 'Editing $1 (section)',

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r14511* (bug 5384) Fix <!-- comments --> in <ref> extension...brion06:16, 1 June 2006
r14530Fix regressions in parser with incomplete tag stripping, plus some old bugs:...brion19:38, 1 June 2006

Status & tagging log