Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -423,7 +423,8 @@ |
424 | 424 | 'SpecialMostlinkedtemplates' => 'includes/specials/SpecialMostlinkedtemplates.php', |
425 | 425 | 'SpecialPrefixindex' => 'includes/specials/SpecialPrefixindex.php', |
426 | 426 | 'SpecialRandomredirect' => 'includes/specials/SpecialRandomredirect.php', |
427 | | - 'SpecialRecentChanges' => 'includes/specials/SpecialRecentchanges.php', |
| 427 | + 'SpecialRecentchanges' => 'includes/specials/SpecialRecentchanges.php', |
| 428 | + 'SpecialRecentchangeslinked' => 'includes/specials/SpecialRecentchangeslinked.php', |
428 | 429 | 'SpecialSearch' => 'includes/specials/SpecialSearch.php', |
429 | 430 | 'SpecialVersion' => 'includes/specials/SpecialVersion.php', |
430 | 431 | 'UncategorizedCategoriesPage' => 'includes/specials/SpecialUncategorizedcategories.php', |
Index: trunk/phase3/includes/specials/SpecialRecentchangeslinked.php |
— | — | @@ -1,191 +1,130 @@ |
2 | 2 | <?php |
| 3 | + |
3 | 4 | /** |
4 | 5 | * This is to display changes made to all articles linked in an article. |
5 | | - * @file |
6 | 6 | * @ingroup SpecialPage |
7 | 7 | */ |
| 8 | +class SpecialRecentchangeslinked extends SpecialRecentchanges { |
8 | 9 | |
9 | | -require_once( 'SpecialRecentchanges.php' ); |
| 10 | + function __construct(){ |
| 11 | + SpecialPage::SpecialPage( 'Recentchangeslinked' ); |
| 12 | + } |
10 | 13 | |
11 | | -/** |
12 | | - * Entrypoint |
13 | | - * @param string $par parent page we will look at |
14 | | - */ |
15 | | -function wfSpecialRecentchangeslinked( $par = NULL ) { |
16 | | - global $wgUser, $wgOut, $wgLang, $wgContLang, $wgRequest, $wgTitle, $wgScript; |
| 14 | + public function getDefaultOptions() { |
| 15 | + $opts = parent::getDefaultOptions(); |
| 16 | + $opts->add( 'target', '' ); |
| 17 | + $opts->add( 'showlinkedto', false ); |
| 18 | + return $opts; |
| 19 | + } |
17 | 20 | |
18 | | - $days = $wgRequest->getInt( 'days' ); |
19 | | - $target = isset($par) ? $par : $wgRequest->getVal( 'target' ); |
20 | | - $hideminor = $wgRequest->getBool( 'hideminor' ) ? 1 : 0; |
21 | | - $showlinkedto = $wgRequest->getBool( 'showlinkedto' ) ? 1 : 0; |
22 | | - |
23 | | - $title = Title::newFromURL( $target ); |
24 | | - $target = $title ? $title->getPrefixedText() : ''; |
25 | | - |
26 | | - $wgOut->setPagetitle( wfMsg( 'recentchangeslinked' ) ); |
27 | | - $sk = $wgUser->getSkin(); |
28 | | - |
29 | | - $wgOut->addHTML( |
30 | | - Xml::openElement( 'form', array( 'method' => 'get', 'action' => $wgScript ) ) . |
31 | | - Xml::openElement( 'fieldset' ) . |
32 | | - Xml::element( 'legend', array(), wfMsg( 'recentchangeslinked' ) ) . "\n" . |
33 | | - Xml::inputLabel( wfMsg( 'recentchangeslinked-page' ), 'target', 'recentchangeslinked-target', 40, $target ) . |
34 | | - " <span style='white-space: nowrap'>" . |
35 | | - Xml::check( 'showlinkedto', $showlinkedto, array('id' => 'showlinkedto') ) . ' ' . |
36 | | - Xml::label( wfMsg("recentchangeslinked-to"), 'showlinkedto' ) . |
37 | | - "</span><br/>\n" . |
38 | | - Xml::hidden( 'title', $wgTitle->getPrefixedText() ). "\n" . |
39 | | - Xml::submitButton( wfMsg( 'allpagessubmit' ) ) . "\n" . |
40 | | - Xml::closeElement( 'fieldset' ) . |
41 | | - Xml::closeElement( 'form' ) . "\n" |
42 | | - ); |
43 | | - |
44 | | - if ( !$target ) { |
45 | | - return; |
| 21 | + public function parseParameters( $par, FormOptions $opts ) { |
| 22 | + $opts['target'] = $par; |
46 | 23 | } |
47 | | - $nt = Title::newFromURL( $target ); |
48 | | - if( !$nt ) { |
49 | | - $wgOut->showErrorPage( 'notargettitle', 'notargettext' ); |
50 | | - return; |
51 | | - } |
52 | | - $id = $nt->getArticleId(); |
53 | 24 | |
54 | | - $wgOut->setPageTitle( wfMsg( 'recentchangeslinked-title', $nt->getPrefixedText() ) ); |
55 | | - $wgOut->setSyndicated(); |
56 | | - $wgOut->setFeedAppendQuery( "target=" . urlencode( $target ) ); |
57 | | - |
58 | | - if ( !$days ) { |
59 | | - $days = (int)$wgUser->getOption( 'rcdays', 7 ); |
| 25 | + public function feedSetup(){ |
| 26 | + global $wgRequest; |
| 27 | + $opts = parent::feedSetup(); |
| 28 | + $opts['target'] = $wgRequest->getVal( 'target' ); |
| 29 | + return $opts; |
60 | 30 | } |
61 | | - list( $limit, /* offset */ ) = wfCheckLimits( 100, 'rclimit' ); |
62 | 31 | |
63 | | - $dbr = wfGetDB( DB_SLAVE,'recentchangeslinked' ); |
64 | | - $cutoff = $dbr->timestamp( time() - ( $days * 86400 ) ); |
65 | | - |
66 | | - $hideminor = ($hideminor ? 1 : 0); |
67 | | - if ( $hideminor ) { |
68 | | - $mlink = $sk->makeKnownLink( $wgContLang->specialPage( 'Recentchangeslinked' ), |
69 | | - wfMsg( 'show' ), 'target=' . htmlspecialchars( $nt->getPrefixedURL() ) . |
70 | | - "&days={$days}&limit={$limit}&hideminor=0&showlinkedto={$showlinkedto}" ); |
71 | | - } else { |
72 | | - $mlink = $sk->makeKnownLink( $wgContLang->specialPage( "Recentchangeslinked" ), |
73 | | - wfMsg( "hide" ), "target=" . htmlspecialchars( $nt->getPrefixedURL() ) . |
74 | | - "&days={$days}&limit={$limit}&hideminor=1&showlinkedto={$showlinkedto}" ); |
| 32 | + public function getFeedObject( $feedFormat ){ |
| 33 | + $feed = new ChangesFeed( $feedFormat, false ); |
| 34 | + $feedObj = $feed->getFeedObject( |
| 35 | + wfMsgForContent( 'recentchangeslinked-title', $this->mTargetTitle->getPrefixedText() ), |
| 36 | + wfMsgForContent( 'recentchangeslinked' ) |
| 37 | + ); |
| 38 | + return array( $feed, $feedObj ); |
75 | 39 | } |
76 | | - if ( $hideminor ) { |
77 | | - $cmq = 'AND rc_minor=0'; |
78 | | - } else { $cmq = ''; } |
79 | 40 | |
80 | | - list($recentchanges, $categorylinks, $pagelinks, $watchlist) = |
81 | | - $dbr->tableNamesN( 'recentchanges', 'categorylinks', 'pagelinks', "watchlist" ); |
| 41 | + public function doMainQuery( $conds, $opts ) { |
| 42 | + global $wgUser, $wgOut; |
82 | 43 | |
83 | | - $uid = $wgUser->getId(); |
84 | | - // The fields we are selecting |
85 | | - $fields = "rc_cur_id,rc_namespace,rc_title, |
86 | | - rc_user,rc_comment,rc_user_text,rc_timestamp,rc_minor,rc_log_type,rc_log_action,rc_params,rc_deleted, |
87 | | - rc_new, rc_id, rc_this_oldid, rc_last_oldid, rc_bot, rc_patrolled, rc_type, rc_old_len, rc_new_len"; |
88 | | - $fields .= $uid ? ",wl_user" : ""; |
| 44 | + $title = Title::newFromURL( $opts['target'] ); |
| 45 | + $showlinkedto = $opts['showlinkedto']; |
| 46 | + $limit = $opts['limit']; |
89 | 47 | |
90 | | - // Check if this should be a feed |
91 | | - |
92 | | - $feed = false; |
93 | | - global $wgFeedLimit; |
94 | | - $feedFormat = $wgRequest->getVal( 'feed' ); |
95 | | - if( $feedFormat ) { |
96 | | - $feed = new ChangesFeed( $feedFormat, false ); |
97 | | - # Sanity check |
98 | | - if( $limit > $wgFeedLimit ) { |
99 | | - $limit = $wgFeedLimit; |
| 48 | + $target = $title ? $title->getPrefixedText() : ''; |
| 49 | + if ( $target === '' ) { |
| 50 | + return false; |
100 | 51 | } |
101 | | - } |
| 52 | + if( !$title ){ |
| 53 | + global $wgOut; |
| 54 | + $wgOut->showErrorPage( 'notargettitle', 'notargettext' ); |
| 55 | + return false; |
| 56 | + } |
102 | 57 | |
103 | | - // If target is a Category, use categorylinks and invert from and to |
104 | | - if( $nt->getNamespace() == NS_CATEGORY ) { |
105 | | - $catkey = $dbr->addQuotes( $nt->getDBkey() ); |
106 | | - # The table clauses |
107 | | - $tables = "$categorylinks, $recentchanges"; |
108 | | - $tables .= $uid ? " LEFT JOIN $watchlist ON wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace " : ""; |
| 58 | + $wgOut->setPageTitle( wfMsg( 'recentchangeslinked-title', $target ) ); |
| 59 | + $this->mTargetTitle = $title; |
109 | 60 | |
110 | | - $sql = "SELECT /* wfSpecialRecentchangeslinked */ $fields FROM $tables |
111 | | - WHERE rc_timestamp > '{$cutoff}' {$cmq} |
112 | | - AND cl_from=rc_cur_id |
113 | | - AND cl_to=$catkey |
114 | | - GROUP BY $fields ORDER BY rc_timestamp DESC LIMIT {$limit}"; // Shitty-ass GROUP BY by for postgres apparently |
115 | | - } else { |
116 | | - if( $showlinkedto ) { |
117 | | - $ns = $dbr->addQuotes( $nt->getNamespace() ); |
118 | | - $dbkey = $dbr->addQuotes( $nt->getDBkey() ); |
119 | | - $joinConds = "AND pl_namespace={$ns} AND pl_title={$dbkey} AND pl_from=rc_cur_id"; |
| 61 | + $dbr = wfGetDB( DB_SLAVE, 'recentchangeslinked' ); |
| 62 | + $id = $title->getArticleId(); |
| 63 | + |
| 64 | + $tables = array( 'recentchanges' ); |
| 65 | + $select = array( $dbr->tableName( 'recentchanges' ) . '.*' ); |
| 66 | + $join_conds = array(); |
| 67 | + |
| 68 | + if( $title->getNamespace() == NS_CATEGORY ) { |
| 69 | + $tables[] = 'categorylinks'; |
| 70 | + $conds['cl_to'] = $title->getDBkey(); |
| 71 | + $join_conds['categorylinks'] = array( 'LEFT JOIN', 'cl_from=rc_cur_id' ); |
120 | 72 | } else { |
121 | | - $joinConds = "AND pl_namespace=rc_namespace AND pl_title=rc_title AND pl_from=$id"; |
| 73 | + if( $showlinkedto ) { |
| 74 | + if( $title->getNamespace() == NS_TEMPLATE ){ |
| 75 | + $tables[] = 'templatelinks'; |
| 76 | + $conds['tl_namespace'] = $title->getNamespace(); |
| 77 | + $conds['tl_title'] = $title->getDBkey(); |
| 78 | + $join_conds['templatelinks'] = array( 'LEFT JOIN', 'tl_from=rc_cur_id' ); |
| 79 | + } else { |
| 80 | + $tables[] = 'pagelinks'; |
| 81 | + $conds['pl_namespace'] = $title->getNamespace(); |
| 82 | + $conds['pl_title'] = $title->getDBkey(); |
| 83 | + $join_conds['pagelinks'] = array( 'LEFT JOIN', 'pl_from=rc_cur_id' ); |
| 84 | + } |
| 85 | + } else { |
| 86 | + $tables[] = 'pagelinks'; |
| 87 | + $conds['pl_from'] = $id; |
| 88 | + $join_conds['pagelinks'] = array( 'LEFT JOIN', 'pl_namespace = rc_namespace AND pl_title = rc_title' ); |
| 89 | + } |
122 | 90 | } |
123 | | - # The table clauses |
124 | | - $tables = "$pagelinks, $recentchanges"; |
125 | | - $tables .= $uid ? " LEFT JOIN $watchlist ON wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace " : ""; |
126 | 91 | |
127 | | - $sql = "SELECT /* wfSpecialRecentchangeslinked */ $fields FROM $tables |
128 | | - WHERE rc_timestamp > '{$cutoff}' {$cmq} |
129 | | - {$joinConds} |
130 | | - GROUP BY $fields ORDER BY rc_timestamp DESC LIMIT {$limit}"; // Shitty-ass GROUP BY by for postgres apparently |
131 | | - } |
132 | | - # Actually do the query |
133 | | - $res = $dbr->query( $sql, __METHOD__ ); |
134 | | - $count = $dbr->numRows( $res ); |
135 | | - $rchanges = array(); |
136 | | - # Output feeds now and be done with it! |
137 | | - if( $feed ) { |
138 | | - if( $count ) { |
139 | | - $counter = 1; |
140 | | - while ( $limit ) { |
141 | | - if ( 0 == $count ) { break; } |
142 | | - $obj = $dbr->fetchObject( $res ); |
143 | | - --$count; |
144 | | - $rc = RecentChange::newFromRow( $obj ); |
145 | | - $rc->counter = $counter++; |
146 | | - --$limit; |
147 | | - $rchanges[] = $obj; |
148 | | - } |
| 92 | + if( $uid = $wgUser->getId() ) { |
| 93 | + $tables[] = 'watchlist'; |
| 94 | + $join_conds['watchlist'] = array( 'LEFT JOIN', "wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace" ); |
| 95 | + $select[] = 'wl_user'; |
149 | 96 | } |
150 | | - $wgOut->disable(); |
151 | 97 | |
152 | | - $feedObj = $feed->getFeedObject( |
153 | | - wfMsgForContent( 'recentchangeslinked-title', $nt->getPrefixedText() ), |
154 | | - wfMsgForContent( 'recentchangeslinked' ) |
155 | | - ); |
156 | | - ChangesFeed::generateFeed( $rchanges, $feedObj ); |
157 | | - return; |
158 | | - } |
159 | | - |
160 | | - # Otherwise, carry on with regular output... |
161 | | - $wgOut->addHTML("< ".$sk->makeLinkObj($nt, "", "redirect=no" )."<br />\n"); |
162 | | - $note = wfMsgExt( "rcnote", array ( 'parseinline' ), $limit, $days, $wgLang->timeAndDate( wfTimestampNow(), true ) ); |
163 | | - $wgOut->addHTML( "<hr />\n{$note}\n<br />" ); |
| 98 | + $res = $dbr->select( $tables, $select, $conds, __METHOD__, |
| 99 | + array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit ), $join_conds ); |
164 | 100 | |
165 | | - $note = rcDayLimitlinks( $days, $limit, "Recentchangeslinked", |
166 | | - "target=" . $nt->getPrefixedURL() . "&hideminor={$hideminor}&showlinkedto={$showlinkedto}", |
167 | | - false, $mlink ); |
| 101 | + if( $dbr->numRows( $res ) == 0 ) |
| 102 | + $this->mResultEmpty = true; |
168 | 103 | |
169 | | - $wgOut->addHTML( $note."\n" ); |
170 | | - |
171 | | - $list = ChangesList::newFromUser( $wgUser ); |
172 | | - $s = $list->beginRecentChangesList(); |
173 | | - |
174 | | - if ( $count ) { |
175 | | - $counter = 1; |
176 | | - while ( $limit ) { |
177 | | - if ( 0 == $count ) { break; } |
178 | | - $obj = $dbr->fetchObject( $res ); |
179 | | - --$count; |
180 | | - $rc = RecentChange::newFromRow( $obj ); |
181 | | - $rc->counter = $counter++; |
182 | | - $s .= $list->recentChangesLine( $rc , !empty( $obj->wl_user) ); |
183 | | - --$limit; |
| 104 | + return $res; |
| 105 | + } |
| 106 | + |
| 107 | + function getExtraOptions( $opts ){ |
| 108 | + $opts->consumeValues( array( 'showlinkedto', 'target' ) ); |
| 109 | + $extraOpts = array(); |
| 110 | + $extraOpts['namespace'] = $this->namespaceFilterForm( $opts ); |
| 111 | + $extraOpts['target'] = array( wfMsg( 'recentchangeslinked-page' ), |
| 112 | + Xml::input( 'target', 40, $opts['target'] ) . |
| 113 | + Xml::check( 'showlinkedto', $opts['showlinkedto'], array('id' => 'showlinkedto') ) . ' ' . |
| 114 | + Xml::label( wfMsg("recentchangeslinked-to"), 'showlinkedto' ) ); |
| 115 | + $extraOpts['submit'] = Xml::submitbutton( wfMsg('allpagessubmit') ); |
| 116 | + return $extraOpts; |
| 117 | + } |
| 118 | + |
| 119 | + function setTopText( &$out, $opts ){} |
| 120 | + |
| 121 | + function setBottomText( &$out, $opts ){ |
| 122 | + if( $target = $opts['target'] ){ |
| 123 | + global $wgUser; |
| 124 | + $out->setFeedAppendQuery( "target=" . urlencode( $target ) ); |
| 125 | + $out->addHTML("< ".$wgUser->getSkin()->makeLinkObj( Title::newFromUrl( $target ), "", "redirect=no" )."<hr />\n"); |
184 | 126 | } |
185 | | - } else { |
186 | | - $wgOut->addWikiMsg('recentchangeslinked-noresult'); |
| 127 | + if( isset( $this->mResultEmpty ) && $this->mResultEmpty ){ |
| 128 | + $out->addWikiMsg( 'recentchangeslinked-noresult' ); |
| 129 | + } |
187 | 130 | } |
188 | | - $s .= $list->endRecentChangesList(); |
189 | | - |
190 | | - $dbr->freeResult( $res ); |
191 | | - $wgOut->addHTML( $s ); |
192 | 131 | } |
Index: trunk/phase3/includes/specials/SpecialRecentchanges.php |
— | — | @@ -1,15 +1,20 @@ |
2 | 2 | <?php |
| 3 | + |
3 | 4 | /** |
4 | | - * @file |
| 5 | + * Implements Special:Recentchanges |
5 | 6 | * @ingroup SpecialPage |
6 | 7 | */ |
7 | | - |
8 | 8 | class SpecialRecentChanges extends SpecialPage { |
9 | 9 | public function __construct() { |
10 | | - SpecialPage::SpecialPage( 'Recentchanges' ); |
| 10 | + SpecialPage::SpecialPage( 'Recentchanges' ); |
11 | 11 | $this->includable( true ); |
12 | 12 | } |
13 | 13 | |
| 14 | + /** |
| 15 | + * Get a FormOptions object containing the default options |
| 16 | + * |
| 17 | + * @return FormOptions |
| 18 | + */ |
14 | 19 | public function getDefaultOptions() { |
15 | 20 | $opts = new FormOptions(); |
16 | 21 | |
— | — | @@ -31,8 +36,13 @@ |
32 | 37 | $opts->add( 'categories_any', false ); |
33 | 38 | |
34 | 39 | return $opts; |
35 | | -} |
| 40 | + } |
36 | 41 | |
| 42 | + /** |
| 43 | + * Get a FormOptions object with options as specified by the user |
| 44 | + * |
| 45 | + * @return FormOptions |
| 46 | + */ |
37 | 47 | public function setup( $parameters ) { |
38 | 48 | global $wgUser, $wgRequest; |
39 | 49 | |
— | — | @@ -51,6 +61,11 @@ |
52 | 62 | return $opts; |
53 | 63 | } |
54 | 64 | |
| 65 | + /** |
| 66 | + * Get a FormOptions object sepcific for feed requests |
| 67 | + * |
| 68 | + * @return FormOptions |
| 69 | + */ |
55 | 70 | public function feedSetup() { |
56 | 71 | global $wgFeedLimit, $wgRequest; |
57 | 72 | $opts = $this->getDefaultOptions(); |
— | — | @@ -59,6 +74,11 @@ |
60 | 75 | return $opts; |
61 | 76 | } |
62 | 77 | |
| 78 | + /** |
| 79 | + * Main execution point |
| 80 | + * |
| 81 | + * @param $parameters string |
| 82 | + */ |
63 | 83 | public function execute( $parameters ) { |
64 | 84 | global $wgRequest, $wgOut; |
65 | 85 | $feedFormat = $wgRequest->getVal( 'feed' ); |
— | — | @@ -73,12 +93,17 @@ |
74 | 94 | |
75 | 95 | $opts = $feedFormat ? $this->feedSetup() : $this->setup( $parameters ); |
76 | 96 | $this->setHeaders(); |
| 97 | + $this->outputHeader(); |
77 | 98 | |
78 | 99 | // Fetch results, prepare a batch link existence check query |
79 | 100 | $rows = array(); |
80 | 101 | $batch = new LinkBatch; |
81 | 102 | $conds = $this->buildMainQueryConds( $opts ); |
82 | 103 | $res = $this->doMainQuery( $conds, $opts ); |
| 104 | + if( $res === false ){ |
| 105 | + $this->doHeader( $opts ); |
| 106 | + return; |
| 107 | + } |
83 | 108 | $dbr = wfGetDB( DB_SLAVE ); |
84 | 109 | while( $row = $dbr->fetchObject( $res ) ){ |
85 | 110 | $rows[] = $row; |
— | — | @@ -92,11 +117,7 @@ |
93 | 118 | $dbr->freeResult( $res ); |
94 | 119 | |
95 | 120 | if ( $feedFormat ) { |
96 | | - $feed = new ChangesFeed( $feedFormat, 'rcfeed' ); |
97 | | - $feedObj = $feed->getFeedObject( |
98 | | - wfMsgForContent( 'recentchanges' ), |
99 | | - wfMsgForContent( 'recentchanges-feed-description' ) |
100 | | - ); |
| 121 | + list( $feed, $feedObj ) = $this->getFeedObject( $feedFormat ); |
101 | 122 | $feed->execute( $feedObj, $rows, $opts['limit'], $opts['hideminor'], $lastmod ); |
102 | 123 | } else { |
103 | 124 | $batch->execute(); |
— | — | @@ -104,6 +125,27 @@ |
105 | 126 | } |
106 | 127 | } |
107 | 128 | |
| 129 | + /** |
| 130 | + * Return an array with a ChangesFeed object and ChannelFeed object |
| 131 | + * |
| 132 | + * @return array |
| 133 | + */ |
| 134 | + public function getFeedObject( $feedFormat ){ |
| 135 | + $feed = new ChangesFeed( $feedFormat, 'rcfeed' ); |
| 136 | + $feedObj = $feed->getFeedObject( |
| 137 | + wfMsgForContent( 'recentchanges' ), |
| 138 | + wfMsgForContent( 'recentchanges-feed-description' ) |
| 139 | + ); |
| 140 | + return array( $feed, $feedObj ); |
| 141 | + } |
| 142 | + |
| 143 | + /** |
| 144 | + * Process $par and put options found if $opts |
| 145 | + * Mainly used when including the page |
| 146 | + * |
| 147 | + * @param $par String |
| 148 | + * @param $opts FormOptions |
| 149 | + */ |
108 | 150 | public function parseParameters( $par, FormOptions $opts ) { |
109 | 151 | $bits = preg_split( '/\s*,\s*/', trim( $par ) ); |
110 | 152 | foreach ( $bits as $bit ) { |
— | — | @@ -124,8 +166,14 @@ |
125 | 167 | } |
126 | 168 | } |
127 | 169 | |
128 | | - # Get last modified date, for client caching |
129 | | - # Don't use this if we are using the patrol feature, patrol changes don't update the timestamp |
| 170 | + /** |
| 171 | + * Get last modified date, for client caching |
| 172 | + * Don't use this if we are using the patrol feature, patrol changes don't |
| 173 | + * update the timestamp |
| 174 | + * |
| 175 | + * @param $feedFormat String |
| 176 | + * @return int or false |
| 177 | + */ |
130 | 178 | public function checkLastModified( $feedFormat ) { |
131 | 179 | global $wgUseRCPatrol, $wgOut; |
132 | 180 | $dbr = wfGetDB( DB_SLAVE ); |
— | — | @@ -139,6 +187,12 @@ |
140 | 188 | return $lastmod; |
141 | 189 | } |
142 | 190 | |
| 191 | + /** |
| 192 | + * Return an array of conditions depending of options set in $opts |
| 193 | + * |
| 194 | + * @param $opts FormOptions |
| 195 | + * @return array |
| 196 | + */ |
143 | 197 | public function buildMainQueryConds( FormOptions $opts ) { |
144 | 198 | global $wgUser; |
145 | 199 | |
— | — | @@ -191,7 +245,7 @@ |
192 | 246 | $conds[] = 'rc_user_text != ' . $dbr->addQuotes( $wgUser->getName() ); |
193 | 247 | } |
194 | 248 | } |
195 | | - |
| 249 | + |
196 | 250 | # Namespace filtering |
197 | 251 | if ( $opts['namespace'] !== '' ) { |
198 | 252 | if ( !$opts['invert'] ) { |
— | — | @@ -204,6 +258,13 @@ |
205 | 259 | return $conds; |
206 | 260 | } |
207 | 261 | |
| 262 | + /** |
| 263 | + * Process the query |
| 264 | + * |
| 265 | + * @param $conds array |
| 266 | + * @param $opts FormOptions |
| 267 | + * @return database result or false (for Recentchangeslinked only) |
| 268 | + */ |
208 | 269 | public function doMainQuery( $conds, $opts ) { |
209 | 270 | global $wgUser; |
210 | 271 | |
— | — | @@ -217,7 +278,7 @@ |
218 | 279 | $invert = $opts['invert']; |
219 | 280 | |
220 | 281 | // JOIN on watchlist for users |
221 | | - if( $wgUser->getId() ) { |
| 282 | + if( $uid ) { |
222 | 283 | $tables[] = 'watchlist'; |
223 | 284 | $join_conds = array( 'watchlist' => array('LEFT JOIN',"wl_user={$uid} AND wl_title=rc_title AND wl_namespace=rc_namespace") ); |
224 | 285 | } |
— | — | @@ -228,7 +289,7 @@ |
229 | 290 | // Also, if this is "all" or main namespace, just use timestamp index. |
230 | 291 | if( is_null($namespace) || $invert || $namespace == NS_MAIN ) { |
231 | 292 | $res = $dbr->select( $tables, '*', $conds, __METHOD__, |
232 | | - array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit, |
| 293 | + array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit, |
233 | 294 | 'USE INDEX' => array('recentchanges' => 'rc_timestamp') ), |
234 | 295 | $join_conds ); |
235 | 296 | // We have a new_namespace_time index! UNION over new=(0,1) and sort result set! |
— | — | @@ -237,14 +298,14 @@ |
238 | 299 | $sqlNew = $dbr->selectSQLText( $tables, '*', |
239 | 300 | array( 'rc_new' => 1 ) + $conds, |
240 | 301 | __METHOD__, |
241 | | - array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit, |
| 302 | + array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit, |
242 | 303 | 'USE INDEX' => array('recentchanges' => 'new_name_timestamp') ), |
243 | 304 | $join_conds ); |
244 | 305 | // Old pages |
245 | 306 | $sqlOld = $dbr->selectSQLText( $tables, '*', |
246 | 307 | array( 'rc_new' => 0 ) + $conds, |
247 | 308 | __METHOD__, |
248 | | - array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit, |
| 309 | + array( 'ORDER BY' => 'rc_timestamp DESC', 'LIMIT' => $limit, |
249 | 310 | 'USE INDEX' => array('recentchanges' => 'new_name_timestamp') ), |
250 | 311 | $join_conds ); |
251 | 312 | # Join the two fast queries, and sort the result set |
— | — | @@ -255,6 +316,12 @@ |
256 | 317 | return $res; |
257 | 318 | } |
258 | 319 | |
| 320 | + /** |
| 321 | + * Send output to $wgOut, only called if not used feeds |
| 322 | + * |
| 323 | + * @param $rows array of database rows |
| 324 | + * @param $opts FormOptions |
| 325 | + */ |
259 | 326 | public function webOutput( $rows, $opts ) { |
260 | 327 | global $wgOut, $wgUser, $wgRCShowWatchingUsers, $wgShowUpdatedMarker; |
261 | 328 | global $wgAllowCategorizedRecentChanges; |
— | — | @@ -272,7 +339,7 @@ |
273 | 340 | $list = ChangesList::newFromUser( $wgUser ); |
274 | 341 | |
275 | 342 | if ( $wgAllowCategorizedRecentChanges ) { |
276 | | - rcFilterByCategories( $rows, $opts ); |
| 343 | + $this->filterByCategories( $rows, $opts ); |
277 | 344 | } |
278 | 345 | |
279 | 346 | $s = $list->beginRecentChangesList(); |
— | — | @@ -323,28 +390,26 @@ |
324 | 391 | $wgOut->addHTML( $s ); |
325 | 392 | } |
326 | 393 | |
| 394 | + /** |
| 395 | + * Return the text to be displayed above the changes |
| 396 | + * |
| 397 | + * @param $opts FormOptions |
| 398 | + * @return String: XHTML |
| 399 | + */ |
327 | 400 | public function doHeader( $opts ) { |
328 | 401 | global $wgScript, $wgOut; |
329 | | - $wgOut->addWikiText( wfMsgForContentNoTrans( 'recentchangestext' ) ); |
330 | 402 | |
| 403 | + $this->setTopText( $wgOut, $opts ); |
| 404 | + |
331 | 405 | $defaults = $opts->getAllValues(); |
332 | 406 | $nondefaults = $opts->getChangedValues(); |
333 | 407 | $opts->consumeValues( array( 'namespace', 'invert' ) ); |
334 | 408 | |
335 | 409 | $panel = array(); |
336 | | - $panel[] = rcOptionsPanel( $defaults, $nondefaults ); |
| 410 | + $panel[] = $this->optionsPanel( $defaults, $nondefaults ); |
337 | 411 | |
338 | | - $extraOpts = array(); |
339 | | - $extraOpts['namespace'] = $this->namespaceFilterForm( $opts ); |
| 412 | + $extraOpts = $this->getExtraOptions( $opts ); |
340 | 413 | |
341 | | - global $wgAllowCategorizedRecentChanges; |
342 | | - if ( $wgAllowCategorizedRecentChanges ) { |
343 | | - $extraOpts['category'] = $this->categoryFilterForm( $opts ); |
344 | | - } |
345 | | - |
346 | | - wfRunHooks( 'SpecialRecentChangesPanel', array( &$extraOpts, $opts ) ); |
347 | | - $extraOpts['submit'] = Xml::submitbutton( wfMsg('allpagessubmit') ); |
348 | | - |
349 | 414 | $out = Xml::openElement( 'table' ); |
350 | 415 | foreach ( $extraOpts as $optionRow ) { |
351 | 416 | $out .= Xml::openElement( 'tr' ); |
— | — | @@ -370,13 +435,55 @@ |
371 | 436 | $panelString = implode( "\n", $panel ); |
372 | 437 | |
373 | 438 | $wgOut->addHTML( '<div class="rcoptions">' . $panelString . '</div>' ); |
| 439 | + |
| 440 | + $this->setBottomText( $wgOut, $opts ); |
374 | 441 | } |
375 | 442 | |
376 | 443 | /** |
377 | | - * Creates the choose namespace selection |
378 | | - * |
379 | | - * @return string |
380 | | - */ |
| 444 | + * Get options to be displayed in a form |
| 445 | + * |
| 446 | + * @param $opts FormOptions |
| 447 | + * @return array |
| 448 | + */ |
| 449 | + function getExtraOptions( $opts ){ |
| 450 | + $extraOpts = array(); |
| 451 | + $extraOpts['namespace'] = $this->namespaceFilterForm( $opts ); |
| 452 | + |
| 453 | + global $wgAllowCategorizedRecentChanges; |
| 454 | + if ( $wgAllowCategorizedRecentChanges ) { |
| 455 | + $extraOpts['category'] = $this->categoryFilterForm( $opts ); |
| 456 | + } |
| 457 | + |
| 458 | + wfRunHooks( 'SpecialRecentChangesPanel', array( &$extraOpts, $opts ) ); |
| 459 | + $extraOpts['submit'] = Xml::submitbutton( wfMsg('allpagessubmit') ); |
| 460 | + return $extraOpts; |
| 461 | + } |
| 462 | + |
| 463 | + /** |
| 464 | + * Send the text to be displayed above the options |
| 465 | + * |
| 466 | + * @param $out OutputPage |
| 467 | + * @param $opts FormOptions |
| 468 | + */ |
| 469 | + function setTopText( &$out, $opts ){ |
| 470 | + $out->addWikiText( wfMsgForContentNoTrans( 'recentchangestext' ) ); |
| 471 | + } |
| 472 | + |
| 473 | + /** |
| 474 | + * Send the text to be displayed after the options, for use in |
| 475 | + * Recentchangeslinked |
| 476 | + * |
| 477 | + * @param $out OutputPage |
| 478 | + * @param $opts FormOptions |
| 479 | + */ |
| 480 | + function setBottomText( &$out, $opts ){} |
| 481 | + |
| 482 | + /** |
| 483 | + * Creates the choose namespace selection |
| 484 | + * |
| 485 | + * @param $opts FormOptions |
| 486 | + * @return string |
| 487 | + */ |
381 | 488 | protected function namespaceFilterForm( FormOptions $opts ) { |
382 | 489 | $nsSelect = HTMLnamespaceselector( $opts['namespace'], '' ); |
383 | 490 | $nsLabel = Xml::label( wfMsg('namespace'), 'namespace' ); |
— | — | @@ -384,6 +491,12 @@ |
385 | 492 | return array( $nsLabel, "$nsSelect $invert" ); |
386 | 493 | } |
387 | 494 | |
| 495 | + /** |
| 496 | + * Create a input to filter changes by categories |
| 497 | + * |
| 498 | + * @param $opts FormOptions |
| 499 | + * @return array |
| 500 | + */ |
388 | 501 | protected function categoryFilterForm( FormOptions $opts ) { |
389 | 502 | list( $label, $input ) = Xml::inputLabelSep( wfMsg('rc_categories'), |
390 | 503 | 'categories', 'mw-categories', false, $opts['categories'] ); |
— | — | @@ -394,216 +507,151 @@ |
395 | 508 | return array( $label, $input ); |
396 | 509 | } |
397 | 510 | |
398 | | -} |
| 511 | + /** |
| 512 | + * Filter $rows by categories set in $opts |
| 513 | + * |
| 514 | + * @param $rows array of database rows |
| 515 | + * @param $opts FormOptions |
| 516 | + */ |
| 517 | + function filterByCategories( &$rows, FormOptions $opts ) { |
| 518 | + $categories = array_map( 'trim', explode( "|" , $opts['categories'] ) ); |
399 | 519 | |
400 | | -function rcFilterByCategories ( &$rows, FormOptions $opts ) { |
401 | | - $categories = array_map( 'trim', explode( "|" , $opts['categories'] ) ); |
| 520 | + if( empty($categories) ) { |
| 521 | + return; |
| 522 | + } |
402 | 523 | |
403 | | - if( empty($categories) ) { |
404 | | - return; |
405 | | - } |
| 524 | + # Filter categories |
| 525 | + $cats = array(); |
| 526 | + foreach ( $categories as $cat ) { |
| 527 | + $cat = trim( $cat ); |
| 528 | + if ( $cat == "" ) continue; |
| 529 | + $cats[] = $cat; |
| 530 | + } |
406 | 531 | |
407 | | - # Filter categories |
408 | | - $cats = array(); |
409 | | - foreach ( $categories as $cat ) { |
410 | | - $cat = trim( $cat ); |
411 | | - if ( $cat == "" ) continue; |
412 | | - $cats[] = $cat; |
413 | | - } |
414 | | - |
415 | | - # Filter articles |
416 | | - $articles = array(); |
417 | | - $a2r = array(); |
418 | | - foreach ( $rows AS $k => $r ) { |
419 | | - $nt = Title::makeTitle( $r->rc_namespace, $r->rc_title ); |
420 | | - $id = $nt->getArticleID(); |
421 | | - if ( $id == 0 ) continue; # Page might have been deleted... |
422 | | - if ( !in_array($id, $articles) ) { |
423 | | - $articles[] = $id; |
| 532 | + # Filter articles |
| 533 | + $articles = array(); |
| 534 | + $a2r = array(); |
| 535 | + foreach ( $rows AS $k => $r ) { |
| 536 | + $nt = Title::makeTitle( $r->rc_namespace, $r->rc_title ); |
| 537 | + $id = $nt->getArticleID(); |
| 538 | + if ( $id == 0 ) continue; # Page might have been deleted... |
| 539 | + if ( !in_array($id, $articles) ) { |
| 540 | + $articles[] = $id; |
| 541 | + } |
| 542 | + if ( !isset($a2r[$id]) ) { |
| 543 | + $a2r[$id] = array(); |
| 544 | + } |
| 545 | + $a2r[$id][] = $k; |
424 | 546 | } |
425 | | - if ( !isset($a2r[$id]) ) { |
426 | | - $a2r[$id] = array(); |
427 | | - } |
428 | | - $a2r[$id][] = $k; |
429 | | - } |
430 | 547 | |
431 | | - # Shortcut? |
432 | | - if ( !count($articles) || !count($cats) ) |
433 | | - return ; |
| 548 | + # Shortcut? |
| 549 | + if ( !count($articles) || !count($cats) ) |
| 550 | + return ; |
434 | 551 | |
435 | | - # Look up |
436 | | - $c = new Categoryfinder ; |
437 | | - $c->seed( $articles, $cats, $opts['categories_any'] ? "OR" : "AND" ) ; |
438 | | - $match = $c->run(); |
| 552 | + # Look up |
| 553 | + $c = new Categoryfinder ; |
| 554 | + $c->seed( $articles, $cats, $opts['categories_any'] ? "OR" : "AND" ) ; |
| 555 | + $match = $c->run(); |
439 | 556 | |
440 | | - # Filter |
441 | | - $newrows = array(); |
442 | | - foreach ( $match AS $id ) { |
443 | | - foreach ( $a2r[$id] AS $rev ) { |
444 | | - $k = $rev; |
445 | | - $newrows[$k] = $rows[$k]; |
| 557 | + # Filter |
| 558 | + $newrows = array(); |
| 559 | + foreach ( $match AS $id ) { |
| 560 | + foreach ( $a2r[$id] AS $rev ) { |
| 561 | + $k = $rev; |
| 562 | + $newrows[$k] = $rows[$k]; |
| 563 | + } |
446 | 564 | } |
| 565 | + $rows = $newrows; |
447 | 566 | } |
448 | | - $rows = $newrows; |
449 | | -} |
450 | 567 | |
451 | | -/** |
452 | | - * |
453 | | - */ |
454 | | -function rcCountLink( $lim, $d, $page='Recentchanges', $more='', $active = false ) { |
455 | | - global $wgUser, $wgLang, $wgContLang; |
456 | | - $sk = $wgUser->getSkin(); |
457 | | - $s = $sk->makeKnownLink( $wgContLang->specialPage( $page ), |
458 | | - ($lim ? $wgLang->formatNum( "{$lim}" ) : wfMsg( 'recentchangesall' ) ), "{$more}" . |
459 | | - ($d ? "days={$d}&" : '') . 'limit='.$lim, '', '', |
460 | | - $active ? 'style="font-weight: bold;"' : '' ); |
461 | | - return $s; |
462 | | -} |
463 | | - |
464 | | -/** |
465 | | - * |
466 | | - */ |
467 | | -function rcDaysLink( $lim, $d, $page='Recentchanges', $more='', $active = false ) { |
468 | | - global $wgUser, $wgLang, $wgContLang; |
469 | | - $sk = $wgUser->getSkin(); |
470 | | - $s = $sk->makeKnownLink( $wgContLang->specialPage( $page ), |
471 | | - ($d ? $wgLang->formatNum( "{$d}" ) : wfMsg( 'recentchangesall' ) ), $more.'days='.$d . |
472 | | - ($lim ? '&limit='.$lim : ''), '', '', |
473 | | - $active ? 'style="font-weight: bold;"' : '' ); |
474 | | - return $s; |
475 | | -} |
476 | | - |
477 | | -/** |
478 | | - * Used by Recentchangeslinked |
479 | | - */ |
480 | | -function rcDayLimitLinks( $days, $limit, $page='Recentchanges', $more='', $doall = false, $minorLink = '', |
481 | | - $botLink = '', $liuLink = '', $patrLink = '', $myselfLink = '' ) { |
482 | | - global $wgRCLinkLimits, $wgRCLinkDays; |
483 | | - if ($more != '') $more .= '&'; |
484 | | - |
485 | | - # Sort data for display and make sure it's unique after we've added user data. |
486 | | - # FIXME: why does this piss around with globals like this? Why is $limit added on globally? |
487 | | - $wgRCLinkLimits[] = $limit; |
488 | | - $wgRCLinkDays[] = $days; |
489 | | - sort($wgRCLinkLimits); |
490 | | - sort($wgRCLinkDays); |
491 | | - $wgRCLinkLimits = array_unique($wgRCLinkLimits); |
492 | | - $wgRCLinkDays = array_unique($wgRCLinkDays); |
493 | | - |
494 | | - $cl = array(); |
495 | | - foreach( $wgRCLinkLimits as $countLink ) { |
496 | | - $cl[] = rcCountLink( $countLink, $days, $page, $more, $countLink == $limit ); |
| 568 | + /** |
| 569 | + * Makes change an option link which carries all the other options |
| 570 | + * @param $title see Title |
| 571 | + * @param $override |
| 572 | + * @param $options |
| 573 | + */ |
| 574 | + function makeOptionsLink( $title, $override, $options, $active = false ) { |
| 575 | + global $wgUser, $wgContLang; |
| 576 | + $sk = $wgUser->getSkin(); |
| 577 | + return $sk->makeKnownLinkObj( $this->getTitle(), |
| 578 | + htmlspecialchars( $title ), wfArrayToCGI( $override, $options ), '', '', |
| 579 | + $active ? 'style="font-weight: bold;"' : '' ); |
497 | 580 | } |
498 | | - if( $doall ) $cl[] = rcCountLink( 0, $days, $page, $more ); |
499 | | - $cl = implode( ' | ', $cl); |
500 | | - |
501 | | - $dl = array(); |
502 | | - foreach( $wgRCLinkDays as $daysLink ) { |
503 | | - $dl[] = rcDaysLink( $limit, $daysLink, $page, $more, $daysLink == $days ); |
504 | | - } |
505 | | - if( $doall ) $dl[] = rcDaysLink( $limit, 0, $page, $more ); |
506 | | - $dl = implode( ' | ', $dl); |
507 | | - |
508 | | - $linkParts = array( 'minorLink' => 'minor', 'botLink' => 'bots', 'liuLink' => 'liu', 'patrLink' => 'patr', 'myselfLink' => 'mine' ); |
509 | | - foreach( $linkParts as $linkVar => $linkMsg ) { |
510 | | - if( $$linkVar != '' ) |
511 | | - $links[] = wfMsgHtml( 'rcshowhide' . $linkMsg, $$linkVar ); |
512 | | - } |
513 | 581 | |
514 | | - $shm = implode( ' | ', $links ); |
515 | | - $note = wfMsg( 'rclinks', $cl, $dl, $shm ); |
516 | | - return $note; |
517 | | -} |
| 582 | + /** |
| 583 | + * Creates the options panel. |
| 584 | + * @param $defaults array |
| 585 | + * @param $nondefaults array |
| 586 | + */ |
| 587 | + function optionsPanel( $defaults, $nondefaults ) { |
| 588 | + global $wgLang, $wgUser, $wgRCLinkLimits, $wgRCLinkDays; |
518 | 589 | |
| 590 | + $options = $nondefaults + $defaults; |
519 | 591 | |
520 | | -/** |
521 | | - * Makes change an option link which carries all the other options |
522 | | - * @param $title see Title |
523 | | - * @param $override |
524 | | - * @param $options |
525 | | - */ |
526 | | -function makeOptionsLink( $title, $override, $options, $active = false ) { |
527 | | - global $wgUser, $wgContLang; |
528 | | - $sk = $wgUser->getSkin(); |
529 | | - return $sk->makeKnownLink( $wgContLang->specialPage( 'Recentchanges' ), |
530 | | - htmlspecialchars( $title ), wfArrayToCGI( $override, $options ), '', '', |
531 | | - $active ? 'style="font-weight: bold;"' : '' ); |
532 | | -} |
| 592 | + if( $options['from'] ) |
| 593 | + $note = wfMsgExt( 'rcnotefrom', array( 'parseinline' ), |
| 594 | + $wgLang->formatNum( $options['limit'] ), |
| 595 | + $wgLang->timeanddate( $options['from'], true ) ); |
| 596 | + else |
| 597 | + $note = wfMsgExt( 'rcnote', array( 'parseinline' ), |
| 598 | + $wgLang->formatNum( $options['limit'] ), |
| 599 | + $wgLang->formatNum( $options['days'] ), |
| 600 | + $wgLang->timeAndDate( wfTimestampNow(), true ) ); |
533 | 601 | |
534 | | -/** |
535 | | - * Creates the options panel. |
536 | | - * @param $defaults |
537 | | - * @param $nondefaults |
538 | | - */ |
539 | | -function rcOptionsPanel( $defaults, $nondefaults ) { |
540 | | - global $wgLang, $wgUser, $wgRCLinkLimits, $wgRCLinkDays; |
| 602 | + # Sort data for display and make sure it's unique after we've added user data. |
| 603 | + $wgRCLinkLimits[] = $options['limit']; |
| 604 | + $wgRCLinkDays[] = $options['days']; |
| 605 | + sort($wgRCLinkLimits); |
| 606 | + sort($wgRCLinkDays); |
| 607 | + $wgRCLinkLimits = array_unique($wgRCLinkLimits); |
| 608 | + $wgRCLinkDays = array_unique($wgRCLinkDays); |
541 | 609 | |
542 | | - $options = $nondefaults + $defaults; |
| 610 | + // limit links |
| 611 | + foreach( $wgRCLinkLimits as $value ) { |
| 612 | + $cl[] = $this->makeOptionsLink( $wgLang->formatNum( $value ), |
| 613 | + array( 'limit' => $value ), $nondefaults, $value == $options['limit'] ) ; |
| 614 | + } |
| 615 | + $cl = implode( ' | ', $cl); |
543 | 616 | |
544 | | - if( $options['from'] ) |
545 | | - $note = wfMsgExt( 'rcnotefrom', array( 'parseinline' ), |
546 | | - $wgLang->formatNum( $options['limit'] ), |
547 | | - $wgLang->timeanddate( $options['from'], true ) ); |
548 | | - else |
549 | | - $note = wfMsgExt( 'rcnote', array( 'parseinline' ), |
550 | | - $wgLang->formatNum( $options['limit'] ), |
551 | | - $wgLang->formatNum( $options['days'] ), |
552 | | - $wgLang->timeAndDate( wfTimestampNow(), true ) ); |
| 617 | + // day links, reset 'from' to none |
| 618 | + foreach( $wgRCLinkDays as $value ) { |
| 619 | + $dl[] = $this->makeOptionsLink( $wgLang->formatNum( $value ), |
| 620 | + array( 'days' => $value, 'from' => '' ), $nondefaults, $value == $options['days'] ) ; |
| 621 | + } |
| 622 | + $dl = implode( ' | ', $dl); |
553 | 623 | |
554 | | - # Sort data for display and make sure it's unique after we've added user data. |
555 | | - $wgRCLinkLimits[] = $options['limit']; |
556 | | - $wgRCLinkDays[] = $options['days']; |
557 | | - sort($wgRCLinkLimits); |
558 | | - sort($wgRCLinkDays); |
559 | | - $wgRCLinkLimits = array_unique($wgRCLinkLimits); |
560 | | - $wgRCLinkDays = array_unique($wgRCLinkDays); |
561 | | - |
562 | | - // limit links |
563 | | - foreach( $wgRCLinkLimits as $value ) { |
564 | | - $cl[] = makeOptionsLink( $wgLang->formatNum( $value ), |
565 | | - array( 'limit' => $value ), $nondefaults, $value == $options['limit'] ) ; |
566 | | - } |
567 | | - $cl = implode( ' | ', $cl); |
568 | 624 | |
569 | | - // day links, reset 'from' to none |
570 | | - foreach( $wgRCLinkDays as $value ) { |
571 | | - $dl[] = makeOptionsLink( $wgLang->formatNum( $value ), |
572 | | - array( 'days' => $value, 'from' => '' ), $nondefaults, $value == $options['days'] ) ; |
573 | | - } |
574 | | - $dl = implode( ' | ', $dl); |
| 625 | + // show/hide links |
| 626 | + $showhide = array( wfMsg( 'show' ), wfMsg( 'hide' )); |
| 627 | + $minorLink = $this->makeOptionsLink( $showhide[1-$options['hideminor']], |
| 628 | + array( 'hideminor' => 1-$options['hideminor'] ), $nondefaults); |
| 629 | + $botLink = $this->makeOptionsLink( $showhide[1-$options['hidebots']], |
| 630 | + array( 'hidebots' => 1-$options['hidebots'] ), $nondefaults); |
| 631 | + $anonsLink = $this->makeOptionsLink( $showhide[ 1 - $options['hideanons'] ], |
| 632 | + array( 'hideanons' => 1 - $options['hideanons'] ), $nondefaults ); |
| 633 | + $liuLink = $this->makeOptionsLink( $showhide[1-$options['hideliu']], |
| 634 | + array( 'hideliu' => 1-$options['hideliu'] ), $nondefaults); |
| 635 | + $patrLink = $this->makeOptionsLink( $showhide[1-$options['hidepatrolled']], |
| 636 | + array( 'hidepatrolled' => 1-$options['hidepatrolled'] ), $nondefaults); |
| 637 | + $myselfLink = $this->makeOptionsLink( $showhide[1-$options['hidemyself']], |
| 638 | + array( 'hidemyself' => 1-$options['hidemyself'] ), $nondefaults); |
575 | 639 | |
| 640 | + $links[] = wfMsgHtml( 'rcshowhideminor', $minorLink ); |
| 641 | + $links[] = wfMsgHtml( 'rcshowhidebots', $botLink ); |
| 642 | + $links[] = wfMsgHtml( 'rcshowhideanons', $anonsLink ); |
| 643 | + $links[] = wfMsgHtml( 'rcshowhideliu', $liuLink ); |
| 644 | + if( $wgUser->useRCPatrol() ) |
| 645 | + $links[] = wfMsgHtml( 'rcshowhidepatr', $patrLink ); |
| 646 | + $links[] = wfMsgHtml( 'rcshowhidemine', $myselfLink ); |
| 647 | + $hl = implode( ' | ', $links ); |
576 | 648 | |
577 | | - // show/hide links |
578 | | - $showhide = array( wfMsg( 'show' ), wfMsg( 'hide' )); |
579 | | - $minorLink = makeOptionsLink( $showhide[1-$options['hideminor']], |
580 | | - array( 'hideminor' => 1-$options['hideminor'] ), $nondefaults); |
581 | | - $botLink = makeOptionsLink( $showhide[1-$options['hidebots']], |
582 | | - array( 'hidebots' => 1-$options['hidebots'] ), $nondefaults); |
583 | | - $anonsLink = makeOptionsLink( $showhide[ 1 - $options['hideanons'] ], |
584 | | - array( 'hideanons' => 1 - $options['hideanons'] ), $nondefaults ); |
585 | | - $liuLink = makeOptionsLink( $showhide[1-$options['hideliu']], |
586 | | - array( 'hideliu' => 1-$options['hideliu'] ), $nondefaults); |
587 | | - $patrLink = makeOptionsLink( $showhide[1-$options['hidepatrolled']], |
588 | | - array( 'hidepatrolled' => 1-$options['hidepatrolled'] ), $nondefaults); |
589 | | - $myselfLink = makeOptionsLink( $showhide[1-$options['hidemyself']], |
590 | | - array( 'hidemyself' => 1-$options['hidemyself'] ), $nondefaults); |
| 649 | + // show from this onward link |
| 650 | + $now = $wgLang->timeanddate( wfTimestampNow(), true ); |
| 651 | + $tl = $this->makeOptionsLink( $now, array( 'from' => wfTimestampNow()), $nondefaults ); |
591 | 652 | |
592 | | - $links[] = wfMsgHtml( 'rcshowhideminor', $minorLink ); |
593 | | - $links[] = wfMsgHtml( 'rcshowhidebots', $botLink ); |
594 | | - $links[] = wfMsgHtml( 'rcshowhideanons', $anonsLink ); |
595 | | - $links[] = wfMsgHtml( 'rcshowhideliu', $liuLink ); |
596 | | - if( $wgUser->useRCPatrol() ) |
597 | | - $links[] = wfMsgHtml( 'rcshowhidepatr', $patrLink ); |
598 | | - $links[] = wfMsgHtml( 'rcshowhidemine', $myselfLink ); |
599 | | - $hl = implode( ' | ', $links ); |
600 | | - |
601 | | - // show from this onward link |
602 | | - $now = $wgLang->timeanddate( wfTimestampNow(), true ); |
603 | | - $tl = makeOptionsLink( $now, array( 'from' => wfTimestampNow()), $nondefaults ); |
604 | | - |
605 | | - $rclinks = wfMsgExt( 'rclinks', array( 'parseinline', 'replaceafter'), |
606 | | - $cl, $dl, $hl ); |
607 | | - $rclistfrom = wfMsgExt( 'rclistfrom', array( 'parseinline', 'replaceafter'), $tl ); |
608 | | - return "$note<br />$rclinks<br />$rclistfrom"; |
609 | | - |
610 | | -} |
\ No newline at end of file |
| 653 | + $rclinks = wfMsgExt( 'rclinks', array( 'parseinline', 'replaceafter'), |
| 654 | + $cl, $dl, $hl ); |
| 655 | + $rclistfrom = wfMsgExt( 'rclistfrom', array( 'parseinline', 'replaceafter'), $tl ); |
| 656 | + return "$note<br />$rclinks<br />$rclistfrom"; |
| 657 | + } |
| 658 | +} |
Index: trunk/phase3/includes/SpecialPage.php |
— | — | @@ -128,7 +128,7 @@ |
129 | 129 | 'Contributions' => array( 'SpecialPage', 'Contributions' ), |
130 | 130 | 'Emailuser' => array( 'UnlistedSpecialPage', 'Emailuser' ), |
131 | 131 | 'Whatlinkshere' => array( 'SpecialPage', 'Whatlinkshere' ), |
132 | | - 'Recentchangeslinked' => array( 'SpecialPage', 'Recentchangeslinked' ), |
| 132 | + 'Recentchangeslinked' => 'SpecialRecentchangeslinked', |
133 | 133 | 'Movepage' => array( 'UnlistedSpecialPage', 'Movepage' ), |
134 | 134 | 'Blockme' => array( 'UnlistedSpecialPage', 'Blockme' ), |
135 | 135 | 'Resetpass' => array( 'UnlistedSpecialPage', 'Resetpass' ), |
Index: trunk/phase3/RELEASE-NOTES |
— | — | @@ -162,10 +162,14 @@ |
163 | 163 | * (bug 14558) New system message (emailuserfooter) is now added to the footer of |
164 | 164 | e-mails sent with Special:Emailuser |
165 | 165 | * Add support for Hijri (Islamic) calendar |
166 | | -* Add a new hook LinkerMakeExternalImage to allow extensions to modify the output of |
167 | | - external (hotlinked) images. |
168 | | -* (bug 14604) Introduced the following features for the LanguageConverter: Multi-tag support, single conversion flag, remove conversion flag on a single page, description flag, variant name, multi-variant fallbacks. |
| 166 | +* Add a new hook LinkerMakeExternalImage to allow extensions to modify the output |
| 167 | + of external (hotlinked) images. |
| 168 | +* (bug 14604) Introduced the following features for the LanguageConverter: |
| 169 | + Multi-tag support, single conversion flag, remove conversion flag on a single |
| 170 | + page, description flag, variant name, multi-variant fallbacks. |
169 | 171 | * Add zh-mo and zh-my variants for the zh language |
| 172 | +* (bugs 4832, 9481, 12890) Special:Recentchangeslinked now has all options that |
| 173 | + are in Special:Recentchanges |
170 | 174 | |
171 | 175 | === Bug fixes in 1.13 === |
172 | 176 | |