Index: trunk/phase3/maintenance/parserTests.txt |
— | — | @@ -7359,9 +7359,29 @@ |
7360 | 7360 | !!end |
7361 | 7361 | |
7362 | 7362 | !! test |
| 7363 | +Edit comment with link and link text |
| 7364 | +!! options |
| 7365 | +comment |
| 7366 | +!! input |
| 7367 | +I like the [[Main Page|best pages]] a lot |
| 7368 | +!! result |
| 7369 | +I like the <a href="https://www.mediawiki.org/wiki/Main_Page" title="Main Page">best pages</a> a lot |
| 7370 | +!!end |
| 7371 | + |
| 7372 | +!! test |
| 7373 | +Edit comment with link and link text with suffix |
| 7374 | +!! options |
| 7375 | +comment |
| 7376 | +!! input |
| 7377 | +I like the [[Main Page|best page]]s a lot |
| 7378 | +!! result |
| 7379 | +I like the <a href="https://www.mediawiki.org/wiki/Main_Page" title="Main Page">best pages</a> a lot |
| 7380 | +!!end |
| 7381 | + |
| 7382 | +!! test |
7363 | 7383 | Edit comment with section link (non-local, eg in history list) |
7364 | 7384 | !! options |
7365 | | -comment,title=[[Main Page]] |
| 7385 | +comment title=[[Main Page]] |
7366 | 7386 | !! input |
7367 | 7387 | /* External links */ removed bogus entries |
7368 | 7388 | !! result |
— | — | @@ -7371,14 +7391,49 @@ |
7372 | 7392 | !! test |
7373 | 7393 | Edit comment with section link (local, eg in diff view) |
7374 | 7394 | !! options |
7375 | | -comment,local,title=[[Main Page]] |
| 7395 | +comment local title=[[Main Page]] |
7376 | 7396 | !! input |
7377 | 7397 | /* External links */ removed bogus entries |
7378 | 7398 | !! result |
7379 | 7399 | <span class="autocomment"><a href="#External_links">→</a>External links: </span> removed bogus entries |
7380 | 7400 | !!end |
7381 | 7401 | |
| 7402 | +!! test |
| 7403 | +Edit comment with subpage link (bug 14080) |
| 7404 | +!! options |
| 7405 | +comment |
| 7406 | +subpage |
| 7407 | +title=[[Subpage test]] |
| 7408 | +!! input |
| 7409 | +Poked at a [[/subpage]] here... |
| 7410 | +!! result |
| 7411 | +Poked at a <a href="https://www.mediawiki.org/wiki/Subpage_test/subpage" title="Subpage test/subpage">/subpage</a> here... |
| 7412 | +!!end |
7382 | 7413 | |
| 7414 | +!! test |
| 7415 | +Edit comment with subpage link and link text (bug 14080) |
| 7416 | +!! options |
| 7417 | +comment |
| 7418 | +subpage |
| 7419 | +title=[[Subpage test]] |
| 7420 | +!! input |
| 7421 | +Poked at a [[/subpage|neat little page]] here... |
| 7422 | +!! result |
| 7423 | +Poked at a <a href="https://www.mediawiki.org/wiki/Subpage_test/subpage" title="Subpage test/subpage">neat little page</a> here... |
| 7424 | +!!end |
| 7425 | + |
| 7426 | +!! test |
| 7427 | +Edit comment with bogus subpage link in non-subpage NS (bug 14080) |
| 7428 | +!! options |
| 7429 | +comment |
| 7430 | +title=[[Subpage test]] |
| 7431 | +!! input |
| 7432 | +Poked at a [[/subpage]] here... |
| 7433 | +!! result |
| 7434 | +Poked at a <a href="https://www.mediawiki.org/index.php?title=/subpage&action=edit&redlink=1" class="new" title="/subpage (page does not exist)">/subpage</a> here... |
| 7435 | +!!end |
| 7436 | + |
| 7437 | + |
7383 | 7438 | TODO: |
7384 | 7439 | more images |
7385 | 7440 | more tables |
Index: trunk/phase3/includes/parser/Parser.php |
— | — | @@ -1840,75 +1840,7 @@ |
1841 | 1841 | * @private |
1842 | 1842 | */ |
1843 | 1843 | function maybeDoSubpageLink($target, &$text) { |
1844 | | - # Valid link forms: |
1845 | | - # Foobar -- normal |
1846 | | - # :Foobar -- override special treatment of prefix (images, language links) |
1847 | | - # /Foobar -- convert to CurrentPage/Foobar |
1848 | | - # /Foobar/ -- convert to CurrentPage/Foobar, strip the initial / from text |
1849 | | - # ../ -- convert to CurrentPage, from CurrentPage/CurrentSubPage |
1850 | | - # ../Foobar -- convert to CurrentPage/Foobar, from CurrentPage/CurrentSubPage |
1851 | | - |
1852 | | - wfProfileIn( __METHOD__ ); |
1853 | | - $ret = $target; # default return value is no change |
1854 | | - |
1855 | | - # Some namespaces don't allow subpages, |
1856 | | - # so only perform processing if subpages are allowed |
1857 | | - if( $this->areSubpagesAllowed() ) { |
1858 | | - $hash = strpos( $target, '#' ); |
1859 | | - if( $hash !== false ) { |
1860 | | - $suffix = substr( $target, $hash ); |
1861 | | - $target = substr( $target, 0, $hash ); |
1862 | | - } else { |
1863 | | - $suffix = ''; |
1864 | | - } |
1865 | | - # bug 7425 |
1866 | | - $target = trim( $target ); |
1867 | | - # Look at the first character |
1868 | | - if( $target != '' && $target{0} === '/' ) { |
1869 | | - # / at end means we don't want the slash to be shown |
1870 | | - $m = array(); |
1871 | | - $trailingSlashes = preg_match_all( '%(/+)$%', $target, $m ); |
1872 | | - if( $trailingSlashes ) { |
1873 | | - $noslash = $target = substr( $target, 1, -strlen($m[0][0]) ); |
1874 | | - } else { |
1875 | | - $noslash = substr( $target, 1 ); |
1876 | | - } |
1877 | | - |
1878 | | - $ret = $this->mTitle->getPrefixedText(). '/' . trim($noslash) . $suffix; |
1879 | | - if( '' === $text ) { |
1880 | | - $text = $target . $suffix; |
1881 | | - } # this might be changed for ugliness reasons |
1882 | | - } else { |
1883 | | - # check for .. subpage backlinks |
1884 | | - $dotdotcount = 0; |
1885 | | - $nodotdot = $target; |
1886 | | - while( strncmp( $nodotdot, "../", 3 ) == 0 ) { |
1887 | | - ++$dotdotcount; |
1888 | | - $nodotdot = substr( $nodotdot, 3 ); |
1889 | | - } |
1890 | | - if($dotdotcount > 0) { |
1891 | | - $exploded = explode( '/', $this->mTitle->GetPrefixedText() ); |
1892 | | - if( count( $exploded ) > $dotdotcount ) { # not allowed to go below top level page |
1893 | | - $ret = implode( '/', array_slice( $exploded, 0, -$dotdotcount ) ); |
1894 | | - # / at the end means don't show full path |
1895 | | - if( substr( $nodotdot, -1, 1 ) === '/' ) { |
1896 | | - $nodotdot = substr( $nodotdot, 0, -1 ); |
1897 | | - if( '' === $text ) { |
1898 | | - $text = $nodotdot . $suffix; |
1899 | | - } |
1900 | | - } |
1901 | | - $nodotdot = trim( $nodotdot ); |
1902 | | - if( $nodotdot != '' ) { |
1903 | | - $ret .= '/' . $nodotdot; |
1904 | | - } |
1905 | | - $ret .= $suffix; |
1906 | | - } |
1907 | | - } |
1908 | | - } |
1909 | | - } |
1910 | | - |
1911 | | - wfProfileOut( __METHOD__ ); |
1912 | | - return $ret; |
| 1844 | + return Linker::normalizeSubpageLink( $this->mTitle, $target, $text ); |
1913 | 1845 | } |
1914 | 1846 | |
1915 | 1847 | /**#@+ |
Index: trunk/phase3/includes/Linker.php |
— | — | @@ -922,7 +922,7 @@ |
923 | 923 | |
924 | 924 | # Render autocomments and make links: |
925 | 925 | $comment = $this->formatAutoComments( $comment, $title, $local ); |
926 | | - $comment = $this->formatLinksInComment( $comment ); |
| 926 | + $comment = $this->formatLinksInComment( $comment, $title ); |
927 | 927 | |
928 | 928 | wfProfileOut( __METHOD__ ); |
929 | 929 | return $comment; |
— | — | @@ -1009,11 +1009,14 @@ |
1010 | 1010 | * @param string $comment Text to format links in |
1011 | 1011 | * @return string |
1012 | 1012 | */ |
1013 | | - public function formatLinksInComment( $comment ) { |
1014 | | - return preg_replace_callback( |
| 1013 | + public function formatLinksInComment( $comment, $title = null ) { |
| 1014 | + $this->commentContextTitle = $title; |
| 1015 | + $html = preg_replace_callback( |
1015 | 1016 | '/\[\[:?(.*?)(\|(.*?))*\]\]([^[]*)/', |
1016 | 1017 | array( $this, 'formatLinksInCommentCallback' ), |
1017 | 1018 | $comment ); |
| 1019 | + unset( $this->commentContextTitle ); |
| 1020 | + return $html; |
1018 | 1021 | } |
1019 | 1022 | |
1020 | 1023 | protected function formatLinksInCommentCallback( $match ) { |
— | — | @@ -1052,16 +1055,93 @@ |
1053 | 1056 | if (isset($match[1][0]) && $match[1][0] == ':') |
1054 | 1057 | $match[1] = substr($match[1], 1); |
1055 | 1058 | list( $inside, $trail ) = Linker::splitTrail( $trail ); |
| 1059 | + |
| 1060 | + $linkText = $text; |
| 1061 | + $linkTarget = Linker::normalizeSubpageLink( $this->commentContextTitle, |
| 1062 | + $match[1], $linkText ); |
| 1063 | + |
1056 | 1064 | $thelink = $this->link( |
1057 | | - Title::newFromText( $match[1] ), |
1058 | | - $text . $inside |
| 1065 | + Title::newFromText( $linkTarget ), |
| 1066 | + $linkText . $inside |
1059 | 1067 | ) . $trail; |
1060 | 1068 | } |
1061 | 1069 | $comment = preg_replace( $linkRegexp, StringUtils::escapeRegexReplacement( $thelink ), $comment, 1 ); |
1062 | 1070 | |
1063 | 1071 | return $comment; |
1064 | 1072 | } |
| 1073 | + |
| 1074 | + static function normalizeSubpageLink( $contextTitle, $target, &$text ) { |
| 1075 | + # Valid link forms: |
| 1076 | + # Foobar -- normal |
| 1077 | + # :Foobar -- override special treatment of prefix (images, language links) |
| 1078 | + # /Foobar -- convert to CurrentPage/Foobar |
| 1079 | + # /Foobar/ -- convert to CurrentPage/Foobar, strip the initial / from text |
| 1080 | + # ../ -- convert to CurrentPage, from CurrentPage/CurrentSubPage |
| 1081 | + # ../Foobar -- convert to CurrentPage/Foobar, from CurrentPage/CurrentSubPage |
1065 | 1082 | |
| 1083 | + wfProfileIn( __METHOD__ ); |
| 1084 | + $ret = $target; # default return value is no change |
| 1085 | + |
| 1086 | + # Some namespaces don't allow subpages, |
| 1087 | + # so only perform processing if subpages are allowed |
| 1088 | + if( $contextTitle && MWNamespace::hasSubpages( $contextTitle->getNamespace() ) ) { |
| 1089 | + $hash = strpos( $target, '#' ); |
| 1090 | + if( $hash !== false ) { |
| 1091 | + $suffix = substr( $target, $hash ); |
| 1092 | + $target = substr( $target, 0, $hash ); |
| 1093 | + } else { |
| 1094 | + $suffix = ''; |
| 1095 | + } |
| 1096 | + # bug 7425 |
| 1097 | + $target = trim( $target ); |
| 1098 | + # Look at the first character |
| 1099 | + if( $target != '' && $target{0} === '/' ) { |
| 1100 | + # / at end means we don't want the slash to be shown |
| 1101 | + $m = array(); |
| 1102 | + $trailingSlashes = preg_match_all( '%(/+)$%', $target, $m ); |
| 1103 | + if( $trailingSlashes ) { |
| 1104 | + $noslash = $target = substr( $target, 1, -strlen($m[0][0]) ); |
| 1105 | + } else { |
| 1106 | + $noslash = substr( $target, 1 ); |
| 1107 | + } |
| 1108 | + |
| 1109 | + $ret = $contextTitle->getPrefixedText(). '/' . trim($noslash) . $suffix; |
| 1110 | + if( '' === $text ) { |
| 1111 | + $text = $target . $suffix; |
| 1112 | + } # this might be changed for ugliness reasons |
| 1113 | + } else { |
| 1114 | + # check for .. subpage backlinks |
| 1115 | + $dotdotcount = 0; |
| 1116 | + $nodotdot = $target; |
| 1117 | + while( strncmp( $nodotdot, "../", 3 ) == 0 ) { |
| 1118 | + ++$dotdotcount; |
| 1119 | + $nodotdot = substr( $nodotdot, 3 ); |
| 1120 | + } |
| 1121 | + if($dotdotcount > 0) { |
| 1122 | + $exploded = explode( '/', $contextTitle->GetPrefixedText() ); |
| 1123 | + if( count( $exploded ) > $dotdotcount ) { # not allowed to go below top level page |
| 1124 | + $ret = implode( '/', array_slice( $exploded, 0, -$dotdotcount ) ); |
| 1125 | + # / at the end means don't show full path |
| 1126 | + if( substr( $nodotdot, -1, 1 ) === '/' ) { |
| 1127 | + $nodotdot = substr( $nodotdot, 0, -1 ); |
| 1128 | + if( '' === $text ) { |
| 1129 | + $text = $nodotdot . $suffix; |
| 1130 | + } |
| 1131 | + } |
| 1132 | + $nodotdot = trim( $nodotdot ); |
| 1133 | + if( $nodotdot != '' ) { |
| 1134 | + $ret .= '/' . $nodotdot; |
| 1135 | + } |
| 1136 | + $ret .= $suffix; |
| 1137 | + } |
| 1138 | + } |
| 1139 | + } |
| 1140 | + } |
| 1141 | + |
| 1142 | + wfProfileOut( __METHOD__ ); |
| 1143 | + return $ret; |
| 1144 | + } |
| 1145 | + |
1066 | 1146 | /** |
1067 | 1147 | * Wrap a comment in standard punctuation and formatting if |
1068 | 1148 | * it's non-empty, otherwise return empty string. |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -300,6 +300,7 @@ |
301 | 301 | * (bug 18751) Fix for buggage in profiling setup for some extensions on PHP 5.1 |
302 | 302 | * (bug 17139) ts_resortTable inconsistent trimming makes date sorting fragile |
303 | 303 | * (bug 19445) Change oldimage table to use ON UPDATE CASCADE for FK to image table. |
| 304 | +* (bug 14080) Short notation links to subpages didn't work in edit summaries |
304 | 305 | |
305 | 306 | == API changes in 1.16 == |
306 | 307 | |