return '<a href="' . htmlspecialchars( $href ) . '" class="new" title="' .
htmlspecialchars( $title->getPrefixedText(), ENT_QUOTES ) . '">' .
$encLabel . '</a>';
- } else {
- wfProfileOut( __METHOD__ );
- return self::linkKnown( $title, $encLabel, array(), wfCgiToArray( $query ) );
}
+
+ wfProfileOut( __METHOD__ );
+ return self::linkKnown( $title, $encLabel, array(), wfCgiToArray( $query ) );
}
/**
* @param $escape Boolean: do we escape the link text?
* @param $linktype String: type of external link. Gets added to the classes
* @param $attribs Array of extra attributes to <a>
+ * @param $title Title|null Title object used for title specific link attributes
* @return string
*/
- public static function makeExternalLink( $url, $text, $escape = true, $linktype = '', $attribs = array() ) {
+ public static function makeExternalLink( $url, $text, $escape = true, $linktype = '', $attribs = array(), $title = null ) {
+ global $wgTitle;
$class = "external";
if ( $linktype ) {
$class .= " $linktype";
if ( $escape ) {
$text = htmlspecialchars( $text );
}
+
+ if ( !$title ) {
+ $title = $wgTitle;
+ }
+ $attribs['rel'] = Parser::getExternalLinkRel( $url, $title );
$link = '';
$success = wfRunHooks( 'LinkerMakeExternalLink',
array( &$url, &$text, &$link, &$attribs, $linktype ) );
/**
* This function is called by all recent changes variants, by the page history,
* and by the user contributions list. It is responsible for formatting edit
- * comments. It escapes any HTML in the comment, but adds some CSS to format
+ * summaries. It escapes any HTML in the summary, but adds some CSS to format
* auto-generated comments (from section editing) and formats [[wikilinks]].
*
* @author Erik Moeller <moeller@scireview.de>
static $autocommentLocal;
/**
+ * Converts autogenerated comments in edit summaries into section links.
* The pattern for autogen comments is / * foo * /, which makes for
* some nasty regex.
* We look for all comments, match any text before and after the comment,
}
/**
+ * Helper function for Linker::formatAutocomments
* @param $match
* @return string
*/
* changes, so this allows sysops to combat a busy vandal without bothering
* other users.
*
+ * If the option verify is set this function will return the link only in case the
+ * revision can be reverted. Please note that due to performance limitations
+ * it might be assumed that a user isn't the only contributor of a page while
+ * (s)he is, which will lead to useless rollback links. Furthermore this wont
+ * work if $wgShowRollbackEditCount is disabled, so this can only function
+ * as an additional check.
+ *
+ * If the option noBrackets is set the rollback link wont be enclosed in []
+ *
* @param $rev Revision object
* @param $context IContextSource context to use or null for the main context.
+ * @param $options array
* @return string
*/
- public static function generateRollback( $rev, IContextSource $context = null ) {
+ public static function generateRollback( $rev, IContextSource $context = null, $options = array( 'verify' ) ) {
if ( $context === null ) {
$context = RequestContext::getMain();
}
+ $editCount = false;
+ if ( in_array( 'verify', $options ) ) {
+ $editCount = self::getRollbackEditCount( $rev, true );
+ if ( $editCount === false ) {
+ return '';
+ }
+ }
+
+ $inner = self::buildRollbackLink( $rev, $context, $editCount );
+
+ if ( !in_array( 'noBrackets', $options ) ) {
+ $inner = $context->msg( 'brackets' )->rawParams( $inner )->plain();
+ }
+
+ return '<span class="mw-rollback-link">' . $inner . '</span>';
+ }
+
+ /**
+ * This function will return the number of revisions which a rollback
+ * would revert and, if $verify is set it will verify that a revision
+ * can be reverted (that the user isn't the only contributor and the
+ * revision we might rollback to isn't deleted). These checks can only
+ * function as an additional check as this function only checks against
+ * the last $wgShowRollbackEditCount edits.
+ *
+ * Returns null if $wgShowRollbackEditCount is disabled or false if $verify
+ * is set and the user is the only contributor of the page.
+ *
+ * @param $rev Revision object
+ * @param $verify Bool Try to verfiy that this revision can really be rolled back
+ * @return integer|bool|null
+ */
+ public static function getRollbackEditCount( $rev, $verify ) {
+ global $wgShowRollbackEditCount;
+ if ( !is_int( $wgShowRollbackEditCount ) || !$wgShowRollbackEditCount > 0 ) {
+ // Nothing has happened, indicate this by returning 'null'
+ return null;
+ }
+
+ $dbr = wfGetDB( DB_SLAVE );
+
+ // Up to the value of $wgShowRollbackEditCount revisions are counted
+ $res = $dbr->select(
+ 'revision',
+ array( 'rev_user_text', 'rev_deleted' ),
+ // $rev->getPage() returns null sometimes
+ array( 'rev_page' => $rev->getTitle()->getArticleID() ),
+ __METHOD__,
+ array(
+ 'USE INDEX' => array( 'revision' => 'page_timestamp' ),
+ 'ORDER BY' => 'rev_timestamp DESC',
+ 'LIMIT' => $wgShowRollbackEditCount + 1
+ )
+ );
+
+ $editCount = 0;
+ $moreRevs = false;
+ foreach ( $res as $row ) {
+ if ( $rev->getRawUserText() != $row->rev_user_text ) {
+ if ( $verify && ( $row->rev_deleted & Revision::DELETED_TEXT || $row->rev_deleted & Revision::DELETED_USER ) ) {
+ // If the user or the text of the revision we might rollback to is deleted in some way we can't rollback
+ // Similar to the sanity checks in WikiPage::commitRollback
+ return false;
+ }
+ $moreRevs = true;
+ break;
+ }
+ $editCount++;
+ }
- return '<span class="mw-rollback-link">'
- . $context->msg( 'brackets' )->rawParams(
- self::buildRollbackLink( $rev, $context ) )->plain()
- . '</span>';
+ if ( $verify && $editCount <= $wgShowRollbackEditCount && !$moreRevs ) {
+ // We didn't find at least $wgShowRollbackEditCount revisions made by the current user
+ // and there weren't any other revisions. That means that the current user is the only
+ // editor, so we can't rollback
+ return false;
+ }
+ return $editCount;
}
/**
*
* @param $rev Revision object
* @param $context IContextSource context to use or null for the main context.
+ * @param $editCount integer Number of edits that would be reverted
* @return String: HTML fragment
*/
- public static function buildRollbackLink( $rev, IContextSource $context = null ) {
+ public static function buildRollbackLink( $rev, IContextSource $context = null, $editCount = false ) {
global $wgShowRollbackEditCount, $wgMiserMode;
// To config which pages are effected by miser mode
}
if( !$disableRollbackEditCount && is_int( $wgShowRollbackEditCount ) && $wgShowRollbackEditCount > 0 ) {
- $dbr = wfGetDB( DB_SLAVE );
-
- // Up to the value of $wgShowRollbackEditCount revisions are counted
- $res = $dbr->select( 'revision',
- array( 'rev_id', 'rev_user_text' ),
- // $rev->getPage() returns null sometimes
- array( 'rev_page' => $rev->getTitle()->getArticleID() ),
- __METHOD__,
- array( 'USE INDEX' => 'page_timestamp',
- 'ORDER BY' => 'rev_timestamp DESC',
- 'LIMIT' => $wgShowRollbackEditCount + 1 )
- );
-
- $editCount = 0;
- while( $row = $dbr->fetchObject( $res ) ) {
- if( $rev->getUserText() != $row->rev_user_text ) {
- break;
- }
- $editCount++;
+ if ( !is_numeric( $editCount ) ) {
+ $editCount = self::getRollbackEditCount( $rev, false );
}
if( $editCount > $wgShowRollbackEditCount ) {
/**
* Returns HTML for the "templates used on this page" list.
*
+ * Make an HTML list of templates, and then add a "More..." link at
+ * the bottom. If $more is null, do not add a "More..." link. If $more
+ * is a Title, make a link to that title and use it. If $more is a string,
+ * directly paste it in as the link.
+ *
* @param $templates Array of templates from Article::getUsedTemplate
* or similar
- * @param $preview Boolean: whether this is for a preview
- * @param $section Boolean: whether this is for a section edit
+ * @param bool $preview Whether this is for a preview
+ * @param bool $section Whether this is for a section edit
+ * @param Title|string|null $more A link for "More..." of the templates
* @return String: HTML output
*/
- public static function formatTemplates( $templates, $preview = false, $section = false ) {
+ public static function formatTemplates( $templates, $preview = false, $section = false, $more = null ) {
wfProfileIn( __METHOD__ );
$outText = '';
. wfMessage( 'word-separator' )->escaped()
. $protected . '</li>';
}
+
+ if ( $more instanceof Title ) {
+ $outText .= '<li>' . self::link( $more, wfMessage( 'moredotdotdot' ) ) . '</li>';
+ } elseif ( $more ) {
+ $outText .= "<li>$more</li>";
+ }
+
$outText .= '</ul>';
}
- wfProfileOut( __METHOD__ );
+ wfProfileOut( __METHOD__ );
return $outText;
}
}
$outText .= '</ul>';
}
- wfProfileOut( __METHOD__ );
+ wfProfileOut( __METHOD__ );
return $outText;
}
!! end
+!! test
+Empty lines between block tags to test open p-tags are closed between the block tags
+!! input
+<div></div>
+
+
+<div></div>a
+
+b
+!! result
+<div></div>
+<p><br />
+</p>
+<div></div>a
+<p>b
+</p>
+!! end
+
###
### Preformatted text
###
!!end
+!!test
+2c. Indent-Pre and tables (bug 42252)
+!!input
+{|
+ |+ foo
+ ! | bar
+|}
+!!result
+<table>
+<caption> foo
+</caption>
+<tr>
+<th> bar
+</th></tr></table>
+
+!!end
+
!!test
3a. Indent-Pre and block tags (single-line html)
!!input
!!end
+!! test
+5. White-space in indent-pre
+NOTE: the white-space char on 2nd line is significant
+!! input
+ a<br/>
+
+ b
+!! result
+<pre>a<br />
+
+b
+</pre>
+!! end
+
###
### HTML-pre (some to spec PHP parser behavior and some Parsoid-RT-centric)
###
!! end
+!! test
+A table with caption with default-spaced attributes and a table row
+!! input
+{|
+|+ style="color: red;" | caption1
+|-
+| foo
+|}
+!! result
+<table>
+<caption style="color: red;"> caption1
+</caption>
+<tr>
+<td> foo
+</td></tr></table>
+
+!! end
+
+!! test
+A table with captions with non-default spaced attributes and a table row
+!! input
+{|
+|+style="color: red;"|caption2
+|+ style="color: red;"| caption3
+|-
+| foo
+|}
+!! result
+<table>
+<caption style="color: red;">caption2
+</caption>
+<caption style="color: red;"> caption3
+</caption>
+<tr>
+<td> foo
+</td></tr></table>
+
+!! end
+
!! test
Table td-cell syntax variations
!! input
!! end
+!! test
+Wikitext table with a lot of comments
+!! input
+{|
+<!-- c0 -->
+| foo
+<!-- c1 -->
+|- <!-- c2 -->
+<!-- c3 -->
+|<!-- c4 -->
+<!-- c5 -->
+|}
+!! result
+<table>
+<tr>
+<td> foo
+</td></tr>
+<tr>
+<td>
+</td></tr></table>
+
+!! end
+
###
### Internal links
###
</p>
!! end
+!! article
+prefixed article
+!! text
+Some text
+!! endarticle
+
+!! test
+Bug 43661: Piped links with identical prefixes
+!! input
+[[prefixed article|prefixed articles with spaces]]
+
+[[prefixed article|prefixed articlesaoeu]]
+
+[[Main Page|Main Page test]]
+!! result
+<p><a href="/wiki/Prefixed_article" title="Prefixed article">prefixed articles with spaces</a>
+</p><p><a href="/wiki/Prefixed_article" title="Prefixed article">prefixed articlesaoeu</a>
+</p><p><a href="/wiki/Main_Page" title="Main Page">Main Page test</a>
+</p>
+!! end
+
+
!! test
Link with HTML entity in suffix / tail
!! input
</p>
!! end
+!! test
+Parsoid-centric test: Whitespace in ext- and wiki-links should be preserved
+!! input
+[[Foo| bar]]
+
+[[Foo| ''bar'']]
+
+[http://wp.org foo]
+
+[http://wp.org ''foo'']
+!! result
+<p><a href="/index.php?title=Foo&action=edit&redlink=1" class="new" title="Foo (page does not exist)"> bar</a>
+</p><p><a href="/index.php?title=Foo&action=edit&redlink=1" class="new" title="Foo (page does not exist)"> <i>bar</i></a>
+</p><p><a rel="nofollow" class="external text" href="http://wp.org">foo</a>
+</p><p><a rel="nofollow" class="external text" href="http://wp.org"><i>foo</i></a>
+</p>
+!! end
+
###
### Interwiki links (see maintenance/interwiki.sql)
###
!! end
+!! test
+Unbalanced closing block tags break a list
+(Disabled since php parser generates broken html -- relies on Tidy to fix up)
+!! options
+disabled
+!! input
+<div>
+*a</div><div>
+*b</div>
+!! result
+<div>
+<ul><li>a
+</li></ul></div><div>
+<ul><li>b
+</li></ul></div>
+!! end
+
+!! test
+Unbalanced closing non-block tags don't break a list
+(Disabled since php parser generates broken html -- relies on Tidy to fix up)
+!! options
+disabled
+!! input
+<span>
+*a</span><span>
+*b</span>
+!! result
+<p><span></span>
+</p>
+<ul><li>a<span></span>
+</li><li>b
+</li></ul>
+!! end
+
+!! test
+Unclosed formatting tags that straddle lists are closed and reopened
+(Disabled since php parser generates broken html -- relies on Tidy to fix up)
+!! options
+disabled
+!! input
+# <s> a
+# b </s>
+!! result
+<ol><li> <s> a </s>
+</li><li> <s> b </s>
+</li></ol>
+!! end
+
!! test
List items are not parsed correctly following a <pre> block (bug 785)
!! input
!! input
RFC 822
!! result
- <p><a class="external mw-magiclink-rfc" href="//tools.ietf.org/html/rfc822">RFC 822</a>
+ <p><a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc822">RFC 822</a>
</p>
!! end
!! input
PMID 1234
!! result
- <p><a class="external mw-magiclink-pmid" href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract">PMID 1234</a>
+ <p><a class="external mw-magiclink-pmid" rel="nofollow" href="//www.ncbi.nlm.nih.gov/pubmed/1234?dopt=Abstract">PMID 1234</a>
</p>
!! end
Template as link source
!! input
[[{{linktest2}}]]
+
+[[{{linktest2}}|Main Page]]
+
+[[{{linktest2}}]]Page
!! result
<p><a href="/wiki/Main_Page" title="Main Page">Main Page</a>
+</p><p><a href="/wiki/Main_Page" title="Main Page">Main Page</a>
+</p><p><a href="/wiki/Main_Page" title="Main Page">Main Page</a>Page
</p>
!! end
Templates: Links: 3. Generation of part of a link href
!!input
[[Fo{{echo|o}}|bar]]
+
+[[Foo{{echo|bar}}]]
+
+[[Foo{{echo|bar}}baz]]
+
+[[Foo{{echo|bar}}|bar]]
+
+[[:Foo{{echo|bar}}]]
+
+[[:Foo{{echo|bar}}|bar]]
!!result
<p><a href="/index.php?title=Foo&action=edit&redlink=1" class="new" title="Foo (page does not exist)">bar</a>
+</p><p><a href="/index.php?title=Foobar&action=edit&redlink=1" class="new" title="Foobar (page does not exist)">Foobar</a>
+</p><p><a href="/index.php?title=Foobarbaz&action=edit&redlink=1" class="new" title="Foobarbaz (page does not exist)">Foobarbaz</a>
+</p><p><a href="/index.php?title=Foobar&action=edit&redlink=1" class="new" title="Foobar (page does not exist)">bar</a>
+</p><p><a href="/index.php?title=Foobar&action=edit&redlink=1" class="new" title="Foobar (page does not exist)">Foobar</a>
+</p><p><a href="/index.php?title=Foobar&action=edit&redlink=1" class="new" title="Foobar (page does not exist)">bar</a>
</p>
!!end
|bar
|}
!!result
-<table data-parsoid="{"src":"{|\n|{{echo|foo</table>}}\n|bar\n|}"}" about="#mwt1" typeof="mw:Object/Template ">
+<table about="#mwt1" typeof="mw:Object/Template ">
<tbody><tr><td>foo</td></tr></tbody></table><span about="#mwt1">
bar</span><span about="#mwt1">
</span>
</tr>
</table>
!!result
-<table data-parsoid="{"src":"<table>\n <tr>\n <td>\n <table>\n <tr>\n <td>1. {{echo|foo </table>}}</td>\n <td> bar </td>\n <td>2. {{echo|baz </table>}}</td>\n </tr>\n <tr>\n <td>abc</td>\n </tr>\n </table>\n </td>\n </tr>\n <tr>\n <td>xyz</td>\n </tr>\n</table>"}" about="#mwt1" typeof="mw:Object/Template">
- <tbody><tr data-parsoid="{"stx":"html"}">
- <td data-parsoid="{"stx":"html"}">
- <table data-parsoid="{"stx":"html"}">
- <tbody><tr data-parsoid="{"stx":"html"}">
- <td data-parsoid="{"stx":"html"}">1. foo </td></tr></tbody></table></td>
- <td data-parsoid="{"stx":"html"}"> bar </td>
- <td data-parsoid="{"stx":"html"}">2. baz </td></tr></tbody></table><span about="#mwt1">
+<table about="#mwt1" typeof="mw:Object/Template">
+ <tbody><tr >
+ <td >
+ <table >
+ <tbody><tr >
+ <td >1. foo </td></tr></tbody></table></td>
+ <td > bar </td>
+ <td >2. baz </td></tr></tbody></table><span about="#mwt1">
</span><span about="#mwt1">
abc</span><span about="#mwt1">
</span>
!!end
+!! test
+Templates: Ugly templates: 3. newline-only template parameter
+!! input
+foo {{echo|
+}}
+!! result
+<p>foo
+</p>
+!! end
+
+# This looks like a bug: a single newline triggers p/br for some reason.
+!! test
+Templates: Ugly templates: 4. newline-only template parameter inconsistency
+!! input
+{{echo|
+}}
+!! result
+<p><br />
+</p>
+!! end
+
+
!!test
Parser Functions: 1. Simple example
!!input
!! input
[[Image:foobar.jpg|thumb|This is RFC 12354]]
!! result
- <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>This is <a class="external mw-magiclink-rfc" href="//tools.ietf.org/html/rfc12354">RFC 12354</a></div></div></div>
+ <div class="thumb tright"><div class="thumbinner" style="width:182px;"><a href="/wiki/File:Foobar.jpg" class="image"><img alt="" src="http://example.com/images/thumb/3/3a/Foobar.jpg/180px-Foobar.jpg" width="180" height="20" class="thumbimage" srcset="http://example.com/images/thumb/3/3a/Foobar.jpg/270px-Foobar.jpg 1.5x, http://example.com/images/thumb/3/3a/Foobar.jpg/360px-Foobar.jpg 2x" /></a> <div class="thumbcaption"><div class="magnify"><a href="/wiki/File:Foobar.jpg" class="internal" title="Enlarge"><img src="/skins/common/images/magnify-clip.png" width="15" height="11" alt="" /></a></div>This is <a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc12354">RFC 12354</a></div></div></div>
!! end
!!end
+###
+### HTML tags and HTML attributes
+###
+
!! test
div with no attributes
!! input
!! end
+# The PHP parser escapes the opening brace to { for some reason, so
+# disabled this test for it.
+!! test
+div with braces in attribute value
+!! options
+disabled
+!! input
+<div title="{}">Foo</div>
+!! result
+<div title="{}">Foo</div>
+!! end
+
# This it very inconsistent in the PHP parser: it returns
# class="class" if there is a space between the name and the equal sign (see
# 'div with empty attribute value, space before equals'), but strips the
</p>
!! end
+!! test
+text with entity-escaped character entity-like string: eacute
+!! input
+I always thought &eacute; was a cute letter.
+!! result
+<p>I always thought &eacute; was a cute letter.
+</p>
+!! end
+
!! test
text with undefined character entity: xacute
!! input
!! input
RFC RFC 1234
!! result
- <p>RFC <a class="external mw-magiclink-rfc" href="//tools.ietf.org/html/rfc1234">RFC 1234</a>
+ <p>RFC <a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc1234">RFC 1234</a>
</p>
!! end
!! input
RFC 983 987
!! result
- <p><a class="external mw-magiclink-rfc" href="//tools.ietf.org/html/rfc983">RFC 983</a> 987
+ <p><a class="external mw-magiclink-rfc" rel="nofollow" href="//tools.ietf.org/html/rfc983">RFC 983</a> 987
</p>
!! end
!! end
+!! article
+Category:分类
+!! text
+blah
+!! endarticle
+
+!! article
+Category:分類
+!! text
+blah
+!! endarticle
+
+!! test
+Don't convert blue categorylinks to another variant (bug 33210)
+!! options
+language=zh cat
+!! input
+[[A]][[Category:分类]]
+!! result
+<a href="/wiki/Category:%E5%88%86%E7%B1%BB" title="Category:分类">分类</a>
+!! end
+
+
!! test
Stripping -{}- tags (language variants)
!! options
!! end
+!! test
+Conversion around HTML tags
+!! options
+language=sr variant=sr-ec
+!! input
+-{H|span=>sr-ec:script;title=>sr-ec:src;}-
+<span title="La-{sr-el:L;sr-ec:C;}-tin">ski</span>
+!! result
+<p>
+<span title="ЛаCтин">ски</span>
+</p>
+!! end
+
+
!! test
Explicit session-wise language variant mapping (A flag and - flag)
!! options
</p>
!! end
+!! test
+Recursive conversion of alt and title attrs shouldn't clear converter state
+!! options
+language=zh variant=zh-cn showtitle
+!! input
+-{H|zh-cn:Exclamation;zh-tw:exclamation;}-
+Should be stripped-{T|zh-cn:China;zh-tw:Taiwan}-<span title="exclamation">!</span>
+!! result
+China
+<p>
+Should be stripped<span title="Exclamation">!</span>
+</p>
+!! end
+
!! test
Bug 24072: more test on conversion rule for title
!! options
</tbody></table>
!! end
+!! test
+Tables: 4d. No escaping needed
+!! input
+{|
+||+1
+||-2
+|}
+!! result
+<table>
+<tr>
+<td>+1
+</td>
+<td>-2
+</td></tr></table>
+
+!! end
+
#### --------------- Links ---------------
#### 1. Quote marks in link text
#### 2. Wikilinks: Escapes needed
!! input
[[Foo|<nowiki>Foo''boo''</nowiki>]]
!! result
-<a rel="mw:WikiLink" href="Foo" data-parsoid="{"tsr":[0,7],"contentPos":[5,5],"src":"[[Foo]]","bsp":[0,7],"stx":"simple"}">Foo''boo''</a>
+<a rel="mw:WikiLink" href="Foo">Foo''boo''</a>
!! end
!! test
</p>
!! end
+!! test
+HTML tag with necessary entities in attributes
+!! input
+<span title="&amp;">foo</span>
+!! result
+<p><span title="&amp;">foo</span>
+</p>
+!! end
+
+!! test
+HTML tag with 'unnecessary' entity encoding in attributes
+!! input
+<span title="&">foo</span>
+!! result
+<p><span title="&">foo</span>
+</p>
+!! end
TODO:
more images