Valid exit status codes range from 0 to 254.
[lhc/web/wiklou.git] / includes / CategoryPage.php
1 <?php
2 /**
3 * Special handling for category description pages
4 * Modelled after ImagePage.php
5 *
6 * @package MediaWiki
7 */
8
9 if( !defined( 'MEDIAWIKI' ) )
10 die( 1 );
11
12 /**
13 * @package MediaWiki
14 */
15 class CategoryPage extends Article {
16
17 function view() {
18 if(!wfRunHooks('CategoryPageView', array(&$this))) return;
19
20 if ( NS_CATEGORY == $this->mTitle->getNamespace() ) {
21 $this->openShowCategory();
22 }
23
24 Article::view();
25
26 # If the article we've just shown is in the "Image" namespace,
27 # follow it with the history list and link list for the image
28 # it describes.
29
30 if ( NS_CATEGORY == $this->mTitle->getNamespace() ) {
31 $this->closeShowCategory();
32 }
33 }
34
35 function openShowCategory() {
36 # For overloading
37 }
38
39 function closeShowCategory() {
40 global $wgOut, $wgRequest;
41 $from = $wgRequest->getVal( 'from' );
42 $until = $wgRequest->getVal( 'until' );
43 $wgOut->addHTML( $this->doCategoryMagic( $from, $until ) );
44 }
45
46 /**
47 * Format the category data list.
48 *
49 * @param string $from -- return only sort keys from this item on
50 * @param string $until -- don't return keys after this point.
51 * @return string HTML output
52 * @private
53 */
54 function doCategoryMagic( $from = '', $until = '' ) {
55 global $wgContLang,$wgUser, $wgCategoryMagicGallery, $wgCategoryPagingLimit;
56 $fname = 'CategoryPage::doCategoryMagic';
57 wfProfileIn( $fname );
58
59 $articles = array();
60 $articles_start_char = array();
61 $children = array();
62 $children_start_char = array();
63 if( $wgCategoryMagicGallery ) {
64 $ig = new ImageGallery();
65 }
66
67 $dbr =& wfGetDB( DB_SLAVE );
68 if( $from != '' ) {
69 $pageCondition = 'cl_sortkey >= ' . $dbr->addQuotes( $from );
70 $flip = false;
71 } elseif( $until != '' ) {
72 $pageCondition = 'cl_sortkey < ' . $dbr->addQuotes( $until );
73 $flip = true;
74 } else {
75 $pageCondition = '1 = 1';
76 $flip = false;
77 }
78 $limit = $wgCategoryPagingLimit;
79 $res = $dbr->select(
80 array( 'page', 'categorylinks' ),
81 array( 'page_title', 'page_namespace', 'page_len', 'cl_sortkey' ),
82 array( $pageCondition,
83 'cl_from = page_id',
84 'cl_to' => $this->mTitle->getDBKey()),
85 #'page_is_redirect' => 0),
86 #+ $pageCondition,
87 $fname,
88 array( 'ORDER BY' => $flip ? 'cl_sortkey DESC' : 'cl_sortkey',
89 'LIMIT' => $limit + 1 ) );
90
91 $sk =& $wgUser->getSkin();
92 $r = "<br style=\"clear:both;\"/>\n";
93 $count = 0;
94 $nextPage = null;
95 while( $x = $dbr->fetchObject ( $res ) ) {
96 if( ++$count > $limit ) {
97 // We've reached the one extra which shows that there are
98 // additional pages to be had. Stop here...
99 $nextPage = $x->cl_sortkey;
100 break;
101 }
102
103 $title = Title::makeTitle( $x->page_namespace, $x->page_title );
104
105 if( $title->getNamespace() == NS_CATEGORY ) {
106 // Subcategory; strip the 'Category' namespace from the link text.
107 array_push( $children, $sk->makeKnownLinkObj( $title, $wgContLang->convertHtml( $title->getText() ) ) );
108
109 // If there's a link from Category:A to Category:B, the sortkey of the resulting
110 // entry in the categorylinks table is Category:A, not A, which it SHOULD be.
111 // Workaround: If sortkey == "Category:".$title, than use $title for sorting,
112 // else use sortkey...
113 $sortkey='';
114 if( $title->getPrefixedText() == $x->cl_sortkey ) {
115 $sortkey=$wgContLang->firstChar( $x->page_title );
116 } else {
117 $sortkey=$wgContLang->firstChar( $x->cl_sortkey );
118 }
119 array_push( $children_start_char, $wgContLang->convert( $sortkey ) ) ;
120 } elseif( $wgCategoryMagicGallery && $title->getNamespace() == NS_IMAGE ) {
121 // Show thumbnails of categorized images, in a separate chunk
122 if( $flip ) {
123 $ig->insert( Image::newFromTitle( $title ) );
124 } else {
125 $ig->add( Image::newFromTitle( $title ) );
126 }
127 } else {
128 // Page in this category
129 array_push( $articles, $sk->makeSizeLinkObj( $x->page_len, $title, $wgContLang->convert( $title->getPrefixedText() ) ) ) ;
130 array_push( $articles_start_char, $wgContLang->convert( $wgContLang->firstChar( $x->cl_sortkey ) ) );
131 }
132 }
133 $dbr->freeResult( $res );
134
135 if( $flip ) {
136 $children = array_reverse( $children );
137 $children_start_char = array_reverse( $children_start_char );
138 $articles = array_reverse( $articles );
139 $articles_start_char = array_reverse( $articles_start_char );
140 }
141
142 if( $until != '' ) {
143 $r .= $this->pagingLinks( $this->mTitle, $nextPage, $until, $limit );
144 } elseif( $nextPage != '' || $from != '' ) {
145 $r .= $this->pagingLinks( $this->mTitle, $from, $nextPage, $limit );
146 }
147
148 # Don't show subcategories section if there are none.
149 if( count( $children ) > 0 ) {
150 # Showing subcategories
151 $r .= '<h2>' . wfMsg( 'subcategories' ) . "</h2>\n";
152 $r .= wfMsgExt( 'subcategorycount', array( 'parse' ), count( $children) );
153 $r .= $this->formatList( $children, $children_start_char );
154 }
155
156 # Showing articles in this category
157 $ti = htmlspecialchars( $this->mTitle->getText() );
158 $r .= '<h2>' . wfMsg( 'category_header', $ti ) . "</h2>\n";
159 $r .= wfMsgExt( 'categoryarticlecount', array( 'parse' ), count( $articles) );
160 $r .= $this->formatList( $articles, $articles_start_char );
161
162 if( $wgCategoryMagicGallery && ! $ig->isEmpty() ) {
163 $r.= $ig->toHTML();
164 }
165
166 if( $until != '' ) {
167 $r .= $this->pagingLinks( $this->mTitle, $nextPage, $until, $limit );
168 } elseif( $nextPage != '' || $from != '' ) {
169 $r .= $this->pagingLinks( $this->mTitle, $from, $nextPage, $limit );
170 }
171
172 wfProfileOut( $fname );
173 return $r;
174 }
175
176 /**
177 * Format a list of articles chunked by letter, either as a
178 * bullet list or a columnar format, depending on the length.
179 *
180 * @param array $articles
181 * @param array $articles_start_char
182 * @param int $cutoff
183 * @return string
184 * @private
185 */
186 function formatList( $articles, $articles_start_char, $cutoff = 6 ) {
187 if ( count ( $articles ) > $cutoff ) {
188 return $this->columnList( $articles, $articles_start_char );
189 } elseif ( count($articles) > 0) {
190 // for short lists of articles in categories.
191 return $this->shortList( $articles, $articles_start_char );
192 }
193 return '';
194 }
195
196 /**
197 * Format a list of articles chunked by letter in a three-column
198 * list, ordered vertically.
199 *
200 * @param array $articles
201 * @param array $articles_start_char
202 * @return string
203 * @private
204 */
205 function columnList( $articles, $articles_start_char ) {
206 // divide list into three equal chunks
207 $chunk = (int) (count ( $articles ) / 3);
208
209 // get and display header
210 $r = '<table width="100%"><tr valign="top">';
211
212 $prev_start_char = 'none';
213
214 // loop through the chunks
215 for($startChunk = 0, $endChunk = $chunk, $chunkIndex = 0;
216 $chunkIndex < 3;
217 $chunkIndex++, $startChunk = $endChunk, $endChunk += $chunk + 1)
218 {
219 $r .= "<td>\n";
220 $atColumnTop = true;
221
222 // output all articles in category
223 for ($index = $startChunk ;
224 $index < $endChunk && $index < count($articles);
225 $index++ )
226 {
227 // check for change of starting letter or begining of chunk
228 if ( ($index == $startChunk) ||
229 ($articles_start_char[$index] != $articles_start_char[$index - 1]) )
230
231 {
232 if( $atColumnTop ) {
233 $atColumnTop = false;
234 } else {
235 $r .= "</ul>\n";
236 }
237 $cont_msg = "";
238 if ( $articles_start_char[$index] == $prev_start_char )
239 $cont_msg = wfMsgHtml('listingcontinuesabbrev');
240 $r .= "<h3>" . htmlspecialchars( $articles_start_char[$index] ) . "$cont_msg</h3>\n<ul>";
241 $prev_start_char = $articles_start_char[$index];
242 }
243
244 $r .= "<li>{$articles[$index]}</li>";
245 }
246 if( !$atColumnTop ) {
247 $r .= "</ul>\n";
248 }
249 $r .= "</td>\n";
250
251
252 }
253 $r .= '</tr></table>';
254 return $r;
255 }
256
257 /**
258 * Format a list of articles chunked by letter in a bullet list.
259 * @param array $articles
260 * @param array $articles_start_char
261 * @return string
262 * @private
263 */
264 function shortList( $articles, $articles_start_char ) {
265 $r = '<h3>' . htmlspecialchars( $articles_start_char[0] ) . "</h3>\n";
266 $r .= '<ul><li>'.$articles[0].'</li>';
267 for ($index = 1; $index < count($articles); $index++ )
268 {
269 if ($articles_start_char[$index] != $articles_start_char[$index - 1])
270 {
271 $r .= "</ul><h3>" . htmlspecialchars( $articles_start_char[$index] ) . "</h3>\n<ul>";
272 }
273
274 $r .= "<li>{$articles[$index]}</li>";
275 }
276 $r .= '</ul>';
277 return $r;
278 }
279
280 /**
281 * @param Title $title
282 * @param string $first
283 * @param string $last
284 * @param int $limit
285 * @param array $query - additional query options to pass
286 * @return string
287 * @private
288 */
289 function pagingLinks( $title, $first, $last, $limit, $query = array() ) {
290 global $wgUser, $wgLang;
291 $sk =& $wgUser->getSkin();
292 $limitText = $wgLang->formatNum( $limit );
293
294 $prevLink = htmlspecialchars( wfMsg( 'prevn', $limitText ) );
295 if( $first != '' ) {
296 $prevLink = $sk->makeLinkObj( $title, $prevLink,
297 wfArrayToCGI( $query + array( 'until' => $first ) ) );
298 }
299 $nextLink = htmlspecialchars( wfMsg( 'nextn', $limitText ) );
300 if( $last != '' ) {
301 $nextLink = $sk->makeLinkObj( $title, $nextLink,
302 wfArrayToCGI( $query + array( 'from' => $last ) ) );
303 }
304
305 return "($prevLink) ($nextLink)";
306 }
307 }
308
309
310 ?>