Create ChangesListSpecialPage as a base class for Watchlist and RC
[lhc/web/wiklou.git] / includes / specialpage / ChangesListSpecialPage.php
1 <?php
2 /**
3 * Special page which uses a ChangesList to show query results.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup SpecialPage
22 */
23
24 /**
25 * Special page which uses a ChangesList to show query results.
26 * @todo Way too many public functions, most of them should be protected
27 *
28 * @ingroup SpecialPage
29 */
30 abstract class ChangesListSpecialPage extends SpecialPage {
31 var $rcSubpage, $rcOptions; // @todo Rename these, make protected
32 protected $customFilters;
33
34 /**
35 * Get a FormOptions object containing the default options. By default returns some basic options,
36 * you might not call parent method and discard them.
37 *
38 * @return FormOptions
39 */
40 public function getDefaultOptions() {
41 $opts = new FormOptions();
42
43 $opts->add( 'namespace', '', FormOptions::INTNULL );
44 $opts->add( 'invert', false );
45 $opts->add( 'associated', false );
46
47 return $opts;
48 }
49
50 /**
51 * Create a FormOptions object with options as specified by the user
52 *
53 * @param array $parameters
54 *
55 * @return FormOptions
56 */
57 public function setup( $parameters ) {
58 $opts = $this->getDefaultOptions();
59 foreach ( $this->getCustomFilters() as $key => $params ) {
60 $opts->add( $key, $params['default'] );
61 }
62
63 $opts = $this->fetchOptionsFromRequest( $opts );
64
65 // Give precedence to subpage syntax
66 if ( $parameters !== null ) {
67 $this->parseParameters( $parameters, $opts );
68 }
69
70 $this->validateOptions( $opts );
71
72 return $opts;
73 }
74
75 /**
76 * Validate a FormOptions object generated by getDefaultOptions() with values already populated.
77 *
78 * @param FormOptions $opts
79 */
80 public function validateOptions( FormOptions $opts ) {
81 // nothing by default
82 }
83
84 /**
85 * Fetch values for a FormOptions object from the WebRequest associated with this instance.
86 *
87 * Intended for subclassing, e.g. to add a backwards-compatibility layer.
88 *
89 * @param FormOptions $parameters
90 * @return FormOptions
91 */
92 protected function fetchOptionsFromRequest( $opts ) {
93 $opts->fetchValuesFromRequest( $this->getRequest() );
94 return $opts;
95 }
96
97 /**
98 * Get custom show/hide filters
99 *
100 * @return array Map of filter URL param names to properties (msg/default)
101 */
102 protected function getCustomFilters() {
103 // @todo Fire a Special{$this->getName()}Filters hook here
104 return array();
105 }
106
107 /**
108 * Process $par and put options found in $opts. Used when including the page.
109 *
110 * @param string $par
111 * @param FormOptions $opts
112 */
113 public function parseParameters( $par, FormOptions $opts ) {
114 // nothing by default
115 }
116
117 /**
118 * Get the current FormOptions for this request
119 * @todo Not called by anything, should be called by execute()
120 *
121 * @return FormOptions
122 */
123 public function getOptions() {
124 if ( $this->rcOptions === null ) {
125 $this->rcOptions = $this->setup( $this->rcSubpage );
126 }
127
128 return $this->rcOptions;
129 }
130
131 /**
132 * Main execution point
133 * @todo This should totally do things
134 *
135 * @param string $subpage
136 */
137 public function execute( $subpage ) {
138 $this->rcSubpage = $subpage;
139 throw new MWException( "Not implemented" );
140 }
141
142 /**
143 * Return an array of conditions depending of options set in $opts
144 * @todo This should build some basic conditions here…
145 * @todo Not called by anything, should be called by execute()
146 *
147 * @param FormOptions $opts
148 * @return array
149 */
150 abstract public function buildMainQueryConds( FormOptions $opts );
151
152 /**
153 * Process the query
154 * @todo This should build some basic processing here…
155 * @todo Not called by anything, should be called by execute()
156 *
157 * @param array $conds
158 * @param FormOptions $opts
159 * @return bool|ResultWrapper Result or false (for Recentchangeslinked only)
160 */
161 abstract public function doMainQuery( $conds, $opts );
162
163 /**
164 * Send output to the OutputPage object, only called if not used feeds
165 * @todo This should do most, if not all, of the outputting now done by subclasses
166 * @todo Not called by anything, should be called by execute()
167 *
168 * @param array $rows Database rows
169 * @param FormOptions $opts
170 */
171 abstract public function webOutput( $rows, $opts );
172
173 /**
174 * Return the text to be displayed above the changes
175 * @todo Not called by anything, should be called by webOutput()
176 *
177 * @param FormOptions $opts
178 * @return string XHTML
179 */
180 public function doHeader( $opts ) {
181 $this->setTopText( $opts );
182
183 // @todo Lots of stuff should be done here.
184
185 $this->setBottomText( $opts );
186 }
187
188 /**
189 * Get options to be displayed in a form
190 * @todo This should handle options returned by getDefaultOptions().
191 * @todo Not called by anything, should be called by something… doHeader() maybe?
192 *
193 * @param FormOptions $opts
194 * @return array
195 */
196 function getExtraOptions( $opts ) {
197 return array();
198 }
199
200 /**
201 * Return the legend displayed within the fieldset
202 * @todo This should not be static, then we can drop the parameter
203 * @todo Not called by anything, should be called by doHeader()
204 *
205 * @param $context the object available as $this in non-static functions
206 * @return string
207 */
208 public static function makeLegend( IContextSource $context ) {
209 global $wgRecentChangesFlags;
210 $user = $context->getUser();
211 # The legend showing what the letters and stuff mean
212 $legend = Xml::openElement( 'dl' ) . "\n";
213 # Iterates through them and gets the messages for both letter and tooltip
214 $legendItems = $wgRecentChangesFlags;
215 if ( !$user->useRCPatrol() ) {
216 unset( $legendItems['unpatrolled'] );
217 }
218 foreach ( $legendItems as $key => $legendInfo ) { # generate items of the legend
219 $label = $legendInfo['title'];
220 $letter = $legendInfo['letter'];
221 $cssClass = isset( $legendInfo['class'] ) ? $legendInfo['class'] : $key;
222
223 $legend .= Xml::element( 'dt',
224 array( 'class' => $cssClass ), $context->msg( $letter )->text()
225 ) . "\n";
226 if ( $key === 'newpage' ) {
227 $legend .= Xml::openElement( 'dd' );
228 $legend .= $context->msg( $label )->escaped();
229 $legend .= ' ' . $context->msg( 'recentchanges-legend-newpage' )->parse();
230 $legend .= Xml::closeElement( 'dd' ) . "\n";
231 } else {
232 $legend .= Xml::element( 'dd', array(),
233 $context->msg( $label )->text()
234 ) . "\n";
235 }
236 }
237 # (+-123)
238 $legend .= Xml::tags( 'dt',
239 array( 'class' => 'mw-plusminus-pos' ),
240 $context->msg( 'recentchanges-legend-plusminus' )->parse()
241 ) . "\n";
242 $legend .= Xml::element(
243 'dd',
244 array( 'class' => 'mw-changeslist-legend-plusminus' ),
245 $context->msg( 'recentchanges-label-plusminus' )->text()
246 ) . "\n";
247 $legend .= Xml::closeElement( 'dl' ) . "\n";
248
249 # Collapsibility
250 $legend =
251 '<div class="mw-changeslist-legend">' .
252 $context->msg( 'recentchanges-legend-heading' )->parse() .
253 '<div class="mw-collapsible-content">' . $legend . '</div>' .
254 '</div>';
255
256 return $legend;
257 }
258
259 /**
260 * Send the text to be displayed before the options. Should use $this->getOutput()->addWikiText()
261 * or similar methods to print the text.
262 *
263 * @param FormOptions $opts
264 */
265 function setTopText( FormOptions $opts ) {
266 // nothing by default
267 }
268
269 /**
270 * Send the text to be displayed after the options. Should use $this->getOutput()->addWikiText()
271 * or similar methods to print the text.
272 *
273 * @param FormOptions $opts
274 */
275 function setBottomText( FormOptions $opts ) {
276 // nothing by default
277 }
278
279 /**
280 * Add page-specific modules.
281 * @todo Not called by anything, should be called by execute()
282 */
283 protected function addModules() {
284 $out = $this->getOutput();
285 // These modules include styles and behavior for the legend box, load them unconditionally
286 $out->addModuleStyles( 'mediawiki.special.changeslist' );
287 $out->addModules( 'mediawiki.special.changeslist.js' );
288 }
289
290 protected function getGroupName() {
291 return 'changes';
292 }
293 }