Index: branches/wikidata/phase3/includes/SpecialAllpages.php |
— | — | @@ -52,7 +52,9 @@ |
53 | 53 | global $wgContLang, $wgScript; |
54 | 54 | $t = Title::makeTitle( NS_SPECIAL, $this->name ); |
55 | 55 | |
56 | | - $namespaceselect = HTMLnamespaceselector($namespace, null); |
| 56 | + # Selector needs to include hidden namespace, hence the "true" |
| 57 | + # parameter |
| 58 | + $namespaceselect = HTMLnamespaceselector($namespace, null, true); |
57 | 59 | |
58 | 60 | $frombox = "<input type='text' size='20' name='from' id='nsfrom' value=\"" |
59 | 61 | . htmlspecialchars ( $from ) . '"/>'; |
Index: branches/wikidata/phase3/includes/GlobalFunctions.php |
— | — | @@ -1369,9 +1369,10 @@ |
1370 | 1370 | * |
1371 | 1371 | * @param mixed $selected The namespace which should be selected, default '' |
1372 | 1372 | * @param string $allnamespaces Value of a special item denoting all namespaces. Null to not include (default) |
| 1373 | + * @param bool $includehidden Include hidden namespaces? |
1373 | 1374 | * @return Html string containing the namespace selector |
1374 | 1375 | */ |
1375 | | -function &HTMLnamespaceselector($selected = '', $allnamespaces = null) { |
| 1376 | +function &HTMLnamespaceselector($selected = '', $allnamespaces = null, $includehidden=false) { |
1376 | 1377 | if( $selected !== '' ) { |
1377 | 1378 | if( is_null( $selected ) ) { |
1378 | 1379 | // No namespace selected; let exact match work without hitting Main |
— | — | @@ -1382,7 +1383,7 @@ |
1383 | 1384 | } |
1384 | 1385 | } |
1385 | 1386 | $s = "<select name='namespace' class='namespaceselector'>\n\t"; |
1386 | | - $arr = Namespace::getFormattedDefaultNamespaces(); |
| 1387 | + $arr = Namespace::getFormattedDefaultNamespaces($includehidden); |
1387 | 1388 | if( !is_null($allnamespaces) ) { |
1388 | 1389 | $arr = array($allnamespaces => wfMsgHtml('namespacesall')) + $arr; |
1389 | 1390 | } |
Index: branches/wikidata/phase3/includes/ChangesList.php |
— | — | @@ -125,7 +125,7 @@ |
126 | 126 | $r .= $this->skin->commentBlock( $rc_comment, $rcObj->getTitle() ); |
127 | 127 | } |
128 | 128 | |
129 | | - if ($rcObj->numberofWatchingusers > 0) { |
| 129 | + if (isset($rcObj->numberofWatchingusers) && $rcObj->numberofWatchingusers > 0) { |
130 | 130 | $r .= wfMsg('number_of_watching_users_RCview', $wgContLang->formatNum($rcObj->numberofWatchingusers)); |
131 | 131 | } |
132 | 132 | |
— | — | @@ -346,7 +346,7 @@ |
347 | 347 | $this->insertUserRelatedLinks($s,$rc); |
348 | 348 | $this->insertComment($s, $rc); |
349 | 349 | |
350 | | - if ($rc->numberofWatchingusers > 0) { |
| 350 | + if (isset($rc->numberofWatchingusers) && $rc->numberofWatchingusers > 0) { |
351 | 351 | $s .= ' ' . wfMsg('number_of_watching_users_RCview', $wgContLang->formatNum($rc->numberofWatchingusers)); |
352 | 352 | } |
353 | 353 | |
Index: branches/wikidata/phase3/includes/SpecialUndelete.php |
— | — | @@ -383,7 +383,7 @@ |
384 | 384 | $undelete =& Title::makeTitle( NS_SPECIAL, 'Undelete' ); |
385 | 385 | $wgOut->addHTML( "<ul>\n" ); |
386 | 386 | while( $row = $result->fetchObject() ) { |
387 | | - $n = ($row->ar_namespace ? |
| 387 | + $n = ($row->ar_namespace && array_key_exists($row->ar_namespace,$wgNamespaces) ? |
388 | 388 | ($wgNamespaces[$row->ar_namespace]->getDefaultName(). ":") : ""). |
389 | 389 | $row->ar_title; |
390 | 390 | $link = $sk->makeKnownLinkObj( $undelete, |
Index: branches/wikidata/phase3/includes/Namespace.php |
— | — | @@ -107,6 +107,9 @@ |
108 | 108 | $defaultNameIndex, # Index of the name all other names redirect to? |
109 | 109 | $canonicalNameIndex; # Index of the name that's valid everywhere |
110 | 110 | |
| 111 | + /** |
| 112 | + * Constructor with reasonable defaults. |
| 113 | + */ |
111 | 114 | function Namespace() { |
112 | 115 | |
113 | 116 | $this->setIndex(NULL); |
— | — | @@ -115,26 +118,54 @@ |
116 | 119 | $this->setSubpages(false); |
117 | 120 | $this->setSearchedByDefault(false); |
118 | 121 | $this->setTarget(NULL); |
119 | | - $this->setHidden(false); |
120 | | - |
| 122 | + $this->setHidden(false); |
121 | 123 | } |
| 124 | + |
| 125 | + /** |
| 126 | + * @return index to the correct $wgNamespaces object |
| 127 | + * or database record for this namespace. |
| 128 | + */ |
122 | 129 | function getIndex() { |
123 | 130 | return $this->index; |
124 | 131 | } |
125 | 132 | |
| 133 | + /** |
| 134 | + * @param $index New index for this namespace. |
| 135 | + * Generally only used during creation. |
| 136 | + */ |
126 | 137 | function setIndex($index) { |
127 | 138 | $this->index=$index; |
128 | 139 | } |
129 | | - |
| 140 | + |
| 141 | + /** |
| 142 | + * @return String like NS_MAIN for identifying |
| 143 | + * system namespaces (see Defines.php). |
| 144 | + */ |
130 | 145 | function getSystemType() { |
131 | 146 | return $this->systemType; |
132 | 147 | } |
133 | 148 | |
| 149 | + /** |
| 150 | + * Set the system type for this namespace. |
| 151 | + * @param string Constant name - needs to exist |
| 152 | + * in Defines.php. |
| 153 | + * @return bool depending on success |
| 154 | + * |
| 155 | + */ |
134 | 156 | function setSystemType($type) { |
135 | | - // TODO: check for valid types |
136 | | - $this->systemType=(string)$type; |
| 157 | + $typeString=(string)$type; |
| 158 | + if(defined($typeString)) { |
| 159 | + $this->systemType=$typeString; |
| 160 | + return true; |
| 161 | + } else { |
| 162 | + return false; |
| 163 | + } |
137 | 164 | } |
138 | | - |
| 165 | + |
| 166 | + /** |
| 167 | + * Is this a system namsepace? |
| 168 | + * @return bool |
| 169 | + */ |
139 | 170 | function isSystemNamespace() { |
140 | 171 | $sys=$this->getSystemType(); |
141 | 172 | return !empty($sys); |
— | — | @@ -148,23 +179,43 @@ |
149 | 180 | function isMovable() { |
150 | 181 | return $this->isMovable; |
151 | 182 | } |
152 | | - |
| 183 | + |
| 184 | + /** |
| 185 | + * Can pages in this namespace be moved? |
| 186 | + * @param bool |
| 187 | + */ |
153 | 188 | function setMovable($movable=true) { |
154 | | - $this->movable=(bool)$movable; |
| 189 | + $this->isMovable=(bool)$movable; |
155 | 190 | } |
156 | | - |
| 191 | + |
| 192 | + /** |
| 193 | + * Are pages from this namespace hidden in lists? |
| 194 | + * @return bool |
| 195 | + */ |
157 | 196 | function isHidden() { |
158 | 197 | return $this->isHidden; |
159 | 198 | } |
160 | 199 | |
| 200 | + /** |
| 201 | + * Should pages from this namespace be hidden in lists? |
| 202 | + * @param bool |
| 203 | + */ |
161 | 204 | function setHidden($hidden=true) { |
162 | 205 | $this->isHidden=(bool)$hidden; |
163 | 206 | } |
164 | 207 | |
| 208 | + /** |
| 209 | + * @return int Index of the parent namespace to a |
| 210 | + * child namespace (talk or otherwise), NULL if none |
| 211 | + */ |
165 | 212 | function getParentIndex() { |
166 | 213 | return $this->parentIndex; |
167 | 214 | } |
168 | 215 | |
| 216 | + /** |
| 217 | + * @return int Same as getParentIndex(), but returns |
| 218 | + * this namespace's index if no parent namespace exists. |
| 219 | + */ |
169 | 220 | function getSubject() { |
170 | 221 | if($this->isTalk()) { |
171 | 222 | return $this->getParentIndex(); |
— | — | @@ -173,42 +224,77 @@ |
174 | 225 | } |
175 | 226 | } |
176 | 227 | |
| 228 | + /** |
| 229 | + * Set parent namespace |
| 230 | + * @param int |
| 231 | + */ |
177 | 232 | function setParentIndex($index) { |
178 | 233 | $this->parentIndex=$index; |
179 | 234 | } |
180 | | - |
| 235 | + |
| 236 | + /** |
| 237 | + * Does this namespace have a parent namespace? |
| 238 | + * @return bool |
| 239 | + */ |
181 | 240 | function hasParent() { |
182 | 241 | return ($this->getParentIndex()!=NULL); |
183 | 242 | } |
184 | | - |
| 243 | + |
| 244 | + /** |
| 245 | + * Synonym for hasParent(), but might be logically |
| 246 | + * different in the near future, if parent/child |
| 247 | + * relationships go beyond talk pages. |
| 248 | + * @return bool |
| 249 | + */ |
185 | 250 | function isTalk() { |
186 | 251 | return $this->hasParent(); |
187 | 252 | } |
188 | 253 | |
189 | | - /* |
| 254 | + /** |
190 | 255 | * Check if the given namespace is not a talk page |
191 | 256 | * @return bool |
192 | 257 | */ |
193 | 258 | function isMain( $index ) { |
194 | 259 | return !$this->isTalk(); |
195 | 260 | } |
196 | | - |
| 261 | + |
| 262 | + /** |
| 263 | + * Is this a "special" namespace (Media:, Special:)? |
| 264 | + * Special namespaces cannot contain any pages. |
| 265 | + * @return bool |
| 266 | + */ |
197 | 267 | function isSpecial() { |
198 | 268 | return($this->getIndex()<NS_MAIN); |
199 | 269 | } |
200 | 270 | |
| 271 | + /** |
| 272 | + * Is content in this namespace searched by default? |
| 273 | + * @return bool |
| 274 | + */ |
201 | 275 | function isSearchedByDefault() { |
202 | 276 | return $this->isSearchedByDefault; |
203 | 277 | } |
204 | 278 | |
| 279 | + /** |
| 280 | + * Should this namespace be searched by default? |
| 281 | + * @param bool |
| 282 | + */ |
205 | 283 | function setSearchedByDefault($search=true) { |
206 | 284 | $this->isSearchedByDefault=(bool)$search; |
207 | 285 | } |
208 | 286 | |
209 | | - /* TODO: support multiple discussion namespaces, |
210 | | - so that things like a Review: namespace |
211 | | - become possible in parallel to normal talk |
212 | | - pages. */ |
| 287 | + /** |
| 288 | + Get the index of the discussion namespace associated |
| 289 | + with a namespace. If this _is_ a discussion namespace, |
| 290 | + return its index. |
| 291 | + |
| 292 | + @return int |
| 293 | + |
| 294 | + TODO: support multiple discussion namespaces, |
| 295 | + so that things like a Review: namespace |
| 296 | + become possible in parallel to normal talk |
| 297 | + pages. |
| 298 | + */ |
213 | 299 | function getTalk() { |
214 | 300 | global $wgNamespaces; |
215 | 301 | /* This behavior is expected by Title.php! */ |
— | — | @@ -221,14 +307,49 @@ |
222 | 308 | return null; |
223 | 309 | } |
224 | 310 | |
| 311 | + /** |
| 312 | + * Return the default prefix for unprefixed links |
| 313 | + * from this namespace. |
| 314 | + * @return string |
| 315 | + */ |
225 | 316 | function getTarget() { |
226 | 317 | return $this->target; |
227 | 318 | } |
228 | | - |
| 319 | + |
| 320 | + /** |
| 321 | + * Set the default prefix for unprefixed links, e.g. |
| 322 | + * "User:" (local namespace prefix) or "MeatBall:" |
| 323 | + * (InterWiki prefix). |
| 324 | + * |
| 325 | + * @param string |
| 326 | + */ |
229 | 327 | function setTarget($target) { |
230 | 328 | $this->target=(string)$target; |
231 | 329 | } |
| 330 | + |
| 331 | + /** |
| 332 | + * Does this namespace allow [[/subpages]]? |
| 333 | + * @return bool |
| 334 | + */ |
| 335 | + function allowsSubpages() { |
| 336 | + return $this->allowsSubpages; |
232 | 337 | |
| 338 | + } |
| 339 | + |
| 340 | + /** |
| 341 | + * Should this namespace allow [[/subpages]]? |
| 342 | + * @param bool |
| 343 | + */ |
| 344 | + function setSubpages($subpages=true) { |
| 345 | + $this->allowsSubpages=(bool)$subpages; |
| 346 | + } |
| 347 | + |
| 348 | + /** |
| 349 | + * Return the default name for this namespace, if any. |
| 350 | + * The default name is the one all others redirect to. |
| 351 | + * |
| 352 | + * @return string |
| 353 | + */ |
233 | 354 | function getDefaultName() { |
234 | 355 | if(isset($this->defaultNameIndex) && array_key_exists($this->defaultNameIndex,$this->names)) { |
235 | 356 | return $this->names[$this->defaultNameIndex]; |
— | — | @@ -250,24 +371,33 @@ |
251 | 372 | } |
252 | 373 | return null; |
253 | 374 | } |
254 | | - |
| 375 | + |
| 376 | + /** |
| 377 | + * Among the names of this namespace, which one should |
| 378 | + * be set as the default name? |
| 379 | + * @param int Key to the names array |
| 380 | + */ |
255 | 381 | function setDefaultNameIndex($index) { |
256 | 382 | $this->defaultNameIndex=$index; |
257 | 383 | } |
258 | 384 | |
| 385 | + /** |
| 386 | + * Among the names of this namespace, which one |
| 387 | + * should be "canonical" (i.e. not editable, and |
| 388 | + * assumed to exist under this name in other |
| 389 | + * wikis)? |
| 390 | + * @param int Key to the names array |
| 391 | + */ |
259 | 392 | function setCanonicalNameIndex($index) { |
260 | 393 | $this->canonicalNameIndex=$index; |
261 | 394 | } |
262 | 395 | |
263 | | - function allowsSubpages() { |
264 | | - return $this->allowsSubpages; |
265 | | - |
266 | | - } |
267 | | - |
268 | | - function setSubpages($subpages=true) { |
269 | | - $this->allowsSubpages=(bool)$subpages; |
270 | | - } |
271 | | - |
| 396 | + /** |
| 397 | + * Add a name to the list of names for this |
| 398 | + * namespace. |
| 399 | + * @return index of the newly added name, |
| 400 | + * or NULL if hte name is not valid. |
| 401 | + */ |
272 | 402 | function addName($name) { |
273 | 403 | $index=count($this->names); |
274 | 404 | if($this->isValidName($name)) { |
— | — | @@ -278,7 +408,12 @@ |
279 | 409 | return NULL; |
280 | 410 | } |
281 | 411 | } |
282 | | - |
| 412 | + |
| 413 | + /** |
| 414 | + * Return the key in the name list for a given |
| 415 | + * name. |
| 416 | + * @return int Matching key or NULL |
| 417 | + */ |
283 | 418 | function getNameIndexForName($findname) { |
284 | 419 | foreach($this->names as $nsi=>$name) { |
285 | 420 | if($name==$findname) { |
— | — | @@ -288,6 +423,13 @@ |
289 | 424 | return null; |
290 | 425 | } |
291 | 426 | |
| 427 | + /** |
| 428 | + * Change a namespace name. |
| 429 | + * @param $oldname The old name |
| 430 | + * @param $newname The new name |
| 431 | + * @param $checkvalid Does the new name have to be |
| 432 | + * valid? (is checked by save() in any case) |
| 433 | + */ |
292 | 434 | function setName($oldname,$newname,$checkvalid=true) { |
293 | 435 | if($checkvalid && !$this->isValidName($newname)) { |
294 | 436 | return NULL; |
— | — | @@ -302,7 +444,11 @@ |
303 | 445 | } |
304 | 446 | } |
305 | 447 | |
306 | | - /* static */ |
| 448 | + /** |
| 449 | + * Is this a valid namespace name? Valid characters |
| 450 | + * are defined in the NS_CHAR constant. |
| 451 | + * @return bool |
| 452 | + */ |
307 | 453 | function isValidName($name) { |
308 | 454 | # Consist only of (at least one) valid char(s) |
309 | 455 | if(preg_match("/^".NS_CHAR."+$/",$name)) { |
— | — | @@ -311,96 +457,49 @@ |
312 | 458 | return false; |
313 | 459 | } |
314 | 460 | } |
315 | | - |
| 461 | + |
| 462 | + /** |
| 463 | + * How many pages does this namespace contain? |
| 464 | + * @return The number of pages |
| 465 | + */ |
| 466 | + function countPages() { |
| 467 | + $dbs =& wfGetDB(DB_SLAVE); |
| 468 | + return $dbs->selectField( |
| 469 | + 'page', |
| 470 | + 'count(*)', |
| 471 | + array('page_namespace'=>$this->getIndex()) |
| 472 | + ); |
| 473 | + } |
| 474 | + |
| 475 | + /** |
| 476 | + * Get the default name with spaces instead of |
| 477 | + * underscores. |
| 478 | + * @return string |
| 479 | + */ |
316 | 480 | function getFormattedDefaultName() { |
317 | 481 | $ns=$this->getDefaultName(); |
318 | 482 | return strtr($ns, '_',' '); |
319 | 483 | } |
320 | | - |
321 | 484 | /** |
322 | | - * Returns the namespace index for a given name or synonym, |
323 | | - * if valid |
324 | | - * |
325 | | - * @static |
326 | | - */ |
327 | | - function getIndexForName ( $name ) { |
328 | | - global $wgNamespaces; |
329 | | - foreach ($wgNamespaces as $ns) { |
330 | | - foreach($ns->names as $synonym) { |
331 | | - if(strcasecmp($synonym,$name)==0) { |
332 | | - return $ns->getIndex(); |
333 | | - } |
334 | | - } |
335 | | - } |
336 | | - return NULL; |
337 | | - } |
338 | | - |
339 | | - /** |
340 | | - * Return the default name for any namespace name |
341 | | - * given as a parameter, even if it is the default |
342 | | - * name already. |
343 | | - * |
344 | | - * @static |
345 | | - */ |
346 | | - function getDefaultNameForName ( $name ) { |
347 | | - global $wgNamespaces; |
348 | | - $index=Namespace::getIndexForName($name); |
349 | | - if(!is_null($index)) { |
350 | | - return $wgNamespaces[$index]->getDefaultName(); |
351 | | - } else { |
352 | | - return null; |
353 | | - } |
354 | | - } |
355 | | - |
356 | | - /** |
357 | | - * |
358 | | - * resets array pointer |
359 | | - * |
360 | | - * @param $includeHidden |
361 | | - * |
362 | | - * @static |
| 485 | + * @return the key in the names array for the default |
| 486 | + * name of this namespace |
363 | 487 | */ |
364 | | - function &getDefaultNamespaces($includeHidden=false) { |
365 | | - global $wgNamespaces; |
366 | | - $dns=array(); |
367 | | - foreach($wgNamespaces as $ns) { |
368 | | - if(!$ns->isHidden()) { |
369 | | - $dn=$ns->getDefaultName(); |
370 | | - if(!is_null($dn)) { |
371 | | - $dns[$ns->getIndex()]=$dn; |
372 | | - } else { |
373 | | - $dns[$ns->getIndex()]=''; |
374 | | - } |
375 | | - } |
376 | | - } |
377 | | - return $dns; |
378 | | - } |
379 | | - |
380 | | - /** |
381 | | - * A convenience function that returns the same thing as |
382 | | - * getDefaultNamespaces() except with the array values changed to ' ' |
383 | | - * where it found '_', useful for producing output to be displayed |
384 | | - * e.g. in <select> forms. |
385 | | - * |
386 | | - * @static |
387 | | - * @param $includeHidden |
388 | | - * @return array |
389 | | - */ |
390 | | - function &getFormattedDefaultNamespaces($includeHidden=false) { |
391 | | - $ns = Namespace::getDefaultNamespaces($includeHidden); |
392 | | - foreach($ns as $k => $v) { |
393 | | - $ns[$k] = strtr($v, '_', ' '); |
394 | | - } |
395 | | - return $ns; |
396 | | - } |
397 | | - |
398 | 488 | function getDefaultNameIndex() { |
399 | 489 | return $this->defaultNameIndex; |
400 | 490 | } |
| 491 | + |
| 492 | + /** |
| 493 | + * @return the key in the names array for the |
| 494 | + * canonical name of this namespace |
| 495 | + */ |
401 | 496 | function getCanonicalNameIndex() { |
402 | 497 | return $this->canonicalNameIndex; |
403 | 498 | } |
404 | 499 | |
| 500 | + /** |
| 501 | + * @return The canonical name associated with |
| 502 | + * this namespace, or NULL |
| 503 | + */ |
405 | 504 | function getCanonicalName() { |
406 | 505 | if(!is_null($this->getCanonicalNameIndex())) { |
407 | 506 | return $this->names[$this->getCanonicalNameIndex()]; |
— | — | @@ -408,14 +507,36 @@ |
409 | 508 | return null; |
410 | 509 | } |
411 | 510 | } |
| 511 | + |
| 512 | + /** |
| 513 | + * @param int Key to the names array of the name |
| 514 | + * which should be removed. |
| 515 | + */ |
| 516 | + function removeNameByIndex($index) { |
| 517 | + if(array_key_exists($index,$this->names)) { |
| 518 | + unset($this->names[$index]); |
| 519 | + return true; |
| 520 | + } else { |
| 521 | + return false; |
| 522 | + } |
| 523 | + } |
412 | 524 | |
413 | 525 | /** |
| 526 | + * Kill them all! Well, all the ones in this namespace |
| 527 | + * object. And only if we save(). |
| 528 | + */ |
| 529 | + function removeAllNames() { |
| 530 | + $this->names=array(); |
| 531 | + return true; |
| 532 | + } |
| 533 | + |
| 534 | + /** |
414 | 535 | * Serialize this namespace to the database. |
415 | 536 | * No part of the operation will be completed |
416 | 537 | * unless it cannot be fully done. |
417 | 538 | * |
418 | | - * If the index of the namespace index is NULL, |
419 | | - * a new namespace will be created. |
| 539 | + * If the namespace index is NULL, a new namespace |
| 540 | + * will be created. |
420 | 541 | * |
421 | 542 | * @param boolean $testSave |
422 | 543 | * If this is set to true, no actual changes |
— | — | @@ -425,8 +546,7 @@ |
426 | 547 | * all of them will succeed. |
427 | 548 | * @param boolean $overrideInterwiki |
428 | 549 | * If a namespace name overlaps with an Interwiki |
429 | | - * prefix, should it be created anyway? Note that |
430 | | - * you can only override one Interwiki prefix at |
| 550 | + * prefix, should it be created anyway? |
431 | 551 | * |
432 | 552 | * @return array() |
433 | 553 | * An array that describes the results of the |
— | — | @@ -441,7 +561,6 @@ |
442 | 562 | * NS_DUPLICATE_NAMES=>array(names) |
443 | 563 | * NS_INTERWIKI_NAMES=>array(names) |
444 | 564 | * NS_PREFIX_NAMES=>array(names) |
445 | | - * NS_LINKED_NAMES=>array(names) |
446 | 565 | * ) |
447 | 566 | * |
448 | 567 | * NS_RESULT can be: |
— | — | @@ -474,13 +593,6 @@ |
475 | 594 | * NS_PREFIX_NAMES |
476 | 595 | * names which are used as hardcoded title prefixes |
477 | 596 | * |
478 | | - * - For removed or renamed names: |
479 | | - * |
480 | | - * NS_LINKED_NAMES |
481 | | - * names which are still in use (linked to) from some |
482 | | - * pages -- these links would become invalid if the |
483 | | - * name was changed or removed. |
484 | | - * |
485 | 597 | * How this function works: |
486 | 598 | * ------------------------ |
487 | 599 | * Check if the namespace has a valid ID (not null) |
— | — | @@ -516,8 +628,7 @@ |
517 | 629 | NS_ILLEGAL_NAMES=>array(), |
518 | 630 | NS_DUPLICATE_NAMES=>array(), |
519 | 631 | NS_INTERWIKI_NAMES=>array(), |
520 | | - NS_PREFIX_NAMES=>array(), |
521 | | - NS_LINKED_NAMES=>array() |
| 632 | + NS_PREFIX_NAMES=>array() |
522 | 633 | ); |
523 | 634 | $nameOperations=array(); |
524 | 635 | $dbs =& wfGetDB( DB_SLAVE ); |
— | — | @@ -607,38 +718,8 @@ |
608 | 719 | } |
609 | 720 | $dbs->freeResult($res); |
610 | 721 | } |
611 | | - # Check first if the name to be deleted |
612 | | - # has not just moved to another slot. |
613 | | - elseif($operation==NS_NAME_DELETE |
614 | | - && is_null($this->getNameIndexForName($name))) { |
615 | | - |
616 | | - # Would any broken links result from deletion? |
617 | | - $match=$dbs->addQuotes("%[[$name:%"); |
| 722 | + } |
618 | 723 | |
619 | | - # Query needs to be optimized/simplified, |
620 | | - # but will generally be run very rarely. |
621 | | - $res = $dbs->select( |
622 | | - array('page', /* FROM */ |
623 | | - 'pagelinks', |
624 | | - 'revision', |
625 | | - 'text'), |
626 | | - array('DISTINCT page_title', |
627 | | - 'page_namespace'), |
628 | | - array('pl_namespace='.$index, |
629 | | - 'page_id=pl_from', |
630 | | - 'rev_id=page_latest', |
631 | | - 'rev_text_id=old_id', |
632 | | - 'old_text like '.$match), |
633 | | - array('LIMIT'=>1) |
634 | | - ); |
635 | | - if($dbs->numRows($res) > 0) { |
636 | | - $rv[NS_RESULT]=NS_NAME_ISSUES; |
637 | | - $rv[NS_LINKED_NAMES][]=$name; |
638 | | - } |
639 | | - $dbs->freeResult($res); |
640 | | - } |
641 | | - } |
642 | | - |
643 | 724 | # If there are problems, return the array |
644 | 725 | if($rv[NS_RESULT]==NS_NAME_ISSUES) { |
645 | 726 | return $rv; |
— | — | @@ -789,6 +870,8 @@ |
790 | 871 | * This function allows deleting system namespaces if explicitly |
791 | 872 | * specified; this should however not be possible through the |
792 | 873 | * user interface. |
| 874 | + * |
| 875 | + * @param $deleteSystem bool Override system namespace protection |
793 | 876 | */ |
794 | 877 | function deleteNamespace($deleteSystem=false) { |
795 | 878 | global $wgNamespaces; |
— | — | @@ -826,30 +909,112 @@ |
827 | 910 | unset($wgNamespaces[$this->getIndex()]); |
828 | 911 | return array(NS_RESULT=>NS_DELETED); |
829 | 912 | } |
| 913 | + |
| 914 | + /* ---------- all static functions below ----------- */ |
| 915 | + |
| 916 | + /** |
| 917 | + * For _any_ name (among all namespaces), return |
| 918 | + * the index of the namespace to which it belongs. |
| 919 | + * |
| 920 | + * @param string Name to search for |
| 921 | + * @return int Index of the namespace associated |
| 922 | + * with this name (or NULL) |
| 923 | + * @static |
| 924 | + */ |
| 925 | + function getIndexForName ( $name ) { |
| 926 | + global $wgNamespaces; |
| 927 | + foreach ($wgNamespaces as $ns) { |
| 928 | + foreach($ns->names as $synonym) { |
| 929 | + if(strcasecmp($synonym,$name)==0) { |
| 930 | + return $ns->getIndex(); |
| 931 | + } |
| 932 | + } |
| 933 | + } |
| 934 | + return NULL; |
| 935 | + } |
830 | 936 | |
831 | | - function removeNameByIndex($index) { |
832 | | - if(array_key_exists($index,$this->names)) { |
833 | | - unset($this->names[$index]); |
834 | | - return true; |
835 | | - } else { |
836 | | - return false; |
837 | | - } |
| 937 | + /** |
| 938 | + * Return the default name for any namespace name |
| 939 | + * given as a parameter, even if it is the default |
| 940 | + * name already. Searches all namespaces. |
| 941 | + * |
| 942 | + * @param string Any namespace name |
| 943 | + * @return string The name (may be identical) |
| 944 | + * @static |
| 945 | + */ |
| 946 | + function getDefaultNameForName ( $name ) { |
| 947 | + global $wgNamespaces; |
| 948 | + $index=Namespace::getIndexForName($name); |
| 949 | + if(!is_null($index)) { |
| 950 | + return $wgNamespaces[$index]->getDefaultName(); |
| 951 | + } else { |
| 952 | + return null; |
| 953 | + } |
838 | 954 | } |
839 | 955 | |
840 | | - function removeAllNames() { |
841 | | - $this->names=array(); |
842 | | - return true; |
| 956 | + /** |
| 957 | + * Return an array of the default names of all |
| 958 | + * namespaces. Resets array pointer of $wgNamespaces. |
| 959 | + * @param $includeHidden Should hidden namespaces |
| 960 | + * be part of the array? |
| 961 | + * @return array |
| 962 | + * @static |
| 963 | + */ |
| 964 | + function &getDefaultNamespaces($includeHidden=false) { |
| 965 | + global $wgNamespaces; |
| 966 | + $dns=array(); |
| 967 | + foreach($wgNamespaces as $ns) { |
| 968 | + if(!$ns->isHidden() || $includeHidden) { |
| 969 | + $dn=$ns->getDefaultName(); |
| 970 | + if(!is_null($dn)) { |
| 971 | + $dns[$ns->getIndex()]=$dn; |
| 972 | + } else { |
| 973 | + $dns[$ns->getIndex()]=''; |
| 974 | + } |
| 975 | + } |
| 976 | + } |
| 977 | + return $dns; |
843 | 978 | } |
| 979 | + |
| 980 | + /** |
| 981 | + * A convenience function that returns the same thing as |
| 982 | + * getDefaultNamespaces() except with the array values changed to ' ' |
| 983 | + * where it found '_', useful for producing output to be displayed |
| 984 | + * e.g. in <select> forms. |
| 985 | + * |
| 986 | + * @static |
| 987 | + * @param $includeHidden |
| 988 | + * @return array |
| 989 | + */ |
| 990 | + function &getFormattedDefaultNamespaces($includeHidden=false) { |
| 991 | + $ns = Namespace::getDefaultNamespaces($includeHidden); |
| 992 | + foreach($ns as $k => $v) { |
| 993 | + $ns[$k] = strtr($v, '_', ' '); |
| 994 | + } |
| 995 | + return $ns; |
| 996 | + } |
844 | 997 | |
845 | 998 | /** |
846 | 999 | * Load or reload namespace definitions from the database |
847 | 1000 | * into a global array. |
848 | 1001 | * |
| 1002 | + * @param $purgeCache If definitions exist in memory, should |
| 1003 | + * they be reloaded anyway? |
| 1004 | + * |
849 | 1005 | * @static |
850 | 1006 | */ |
851 | | - function load() { |
| 1007 | + function load($purgeCache=false) { |
852 | 1008 | |
853 | | - global $wgNamespaces; |
| 1009 | + global $wgNamespaces, $wgMemc, $wgDBname; |
| 1010 | + $key="$wgDBname:namespaces:list"; |
| 1011 | + if(!$purgeCache) { |
| 1012 | + $fromMemory = $wgMemc->get($key); |
| 1013 | + if(is_array($fromMemory)) { |
| 1014 | + # Cached definitions found |
| 1015 | + $wgNamespaces=$fromMemory; |
| 1016 | + return true; |
| 1017 | + } |
| 1018 | + } |
854 | 1019 | $wgNamespaces = array(); |
855 | 1020 | $dbr =& wfGetDB( DB_SLAVE ); |
856 | 1021 | $res = $dbr->select( 'namespace', |
— | — | @@ -863,6 +1028,12 @@ |
864 | 1029 | # properties which are accessed below. |
865 | 1030 | $id=$row->ns_id; |
866 | 1031 | $wgNamespaces[$id]=new Namespace(); |
| 1032 | + |
| 1033 | + # Cannot currently be changed through the UI - is |
| 1034 | + # there a need for it to be changeable? |
| 1035 | + $wgNamespaces[$id]->setMovable( |
| 1036 | + $id < NS_MAIN || $id==NS_IMAGE || |
| 1037 | + $id==NS_CATEGORY ? false : true ); |
867 | 1038 | $wgNamespaces[$id]->setIndex($id); |
868 | 1039 | $wgNamespaces[$id]->setSystemType($row->ns_system); |
869 | 1040 | $wgNamespaces[$id]->setSearchedByDefault($row->ns_search_default); |
— | — | @@ -886,6 +1057,7 @@ |
887 | 1058 | } |
888 | 1059 | } |
889 | 1060 | $dbr->freeResult( $res ); |
| 1061 | + $wgMemc->set($key,$wgNamespaces); |
890 | 1062 | } |
891 | 1063 | |
892 | 1064 | /** |
— | — | @@ -973,18 +1145,6 @@ |
974 | 1146 | return array(NS_RESULT=>NS_PSEUDO_CONVERTED); |
975 | 1147 | |
976 | 1148 | } |
977 | | - /** |
978 | | - * How many pages does this namespace contain? |
979 | | - * @return The number of pages |
980 | | - */ |
981 | | - function countPages() { |
982 | | - $dbs =& wfGetDB(DB_SLAVE); |
983 | | - return $dbs->selectField( |
984 | | - 'page', |
985 | | - 'count(*)', |
986 | | - array('page_namespace'=>$this->getIndex()) |
987 | | - ); |
988 | | - } |
989 | 1149 | |
990 | 1150 | } |
991 | 1151 | |
Index: branches/wikidata/phase3/includes/LogPage.php |
— | — | @@ -41,7 +41,7 @@ |
42 | 42 | * Constructor |
43 | 43 | * |
44 | 44 | * @param string $type One of '', 'block', 'protect', 'rights', 'delete', |
45 | | - * 'upload', 'move' |
| 45 | + * 'upload', 'move', 'namespace' |
46 | 46 | * @param bool $rc Whether to update recent changes as well as the logging table |
47 | 47 | */ |
48 | 48 | function LogPage( $type, $rc = true ) { |
— | — | @@ -92,7 +92,7 @@ |
93 | 93 | * @static |
94 | 94 | */ |
95 | 95 | function validTypes() { |
96 | | - static $types = array( '', 'block', 'protect', 'rights', 'delete', 'upload', 'move' ); |
| 96 | + static $types = array( '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'namespace' ); |
97 | 97 | wfRunHooks( 'LogPageValidTypes', array( &$types ) ); |
98 | 98 | return $types; |
99 | 99 | } |
— | — | @@ -115,7 +115,8 @@ |
116 | 116 | 'rights' => 'bureaucratlog', |
117 | 117 | 'delete' => 'dellogpage', |
118 | 118 | 'upload' => 'uploadlogpage', |
119 | | - 'move' => 'movelogpage' |
| 119 | + 'move' => 'movelogpage', |
| 120 | + 'namespace' => 'namespacelogpage', |
120 | 121 | ); |
121 | 122 | wfRunHooks( 'LogPageLogName', array( &$typeText ) ); |
122 | 123 | |
— | — | @@ -133,7 +134,8 @@ |
134 | 135 | 'rights' => 'rightslogtext', |
135 | 136 | 'delete' => 'dellogpagetext', |
136 | 137 | 'upload' => 'uploadlogpagetext', |
137 | | - 'move' => 'movelogpagetext' |
| 138 | + 'move' => 'movelogpagetext', |
| 139 | + 'namespace' => 'namespacelogtext', |
138 | 140 | ); |
139 | 141 | wfRunHooks( 'LogPageLogHeader', array( &$headerText ) ); |
140 | 142 | |
— | — | @@ -162,7 +164,12 @@ |
163 | 165 | 'upload/upload' => 'uploadedimage', |
164 | 166 | 'upload/revert' => 'uploadedimage', |
165 | 167 | 'move/move' => '1movedto2', |
166 | | - 'move/move_redir' => '1movedto2_redir' |
| 168 | + 'move/move_redir' => '1movedto2_redir', |
| 169 | + |
| 170 | + 'namespace/add' => 'namespaceaddlog', |
| 171 | + 'namespace/delete' => 'namespacedeletelog', |
| 172 | + 'namespace/modify' => 'namespacemodifylog', |
| 173 | + 'namespace/pseudo' => 'namespacepseudolog', |
167 | 174 | ); |
168 | 175 | wfRunHooks( 'LogPageActionText', array( &$actions ) ); |
169 | 176 | |
— | — | @@ -206,7 +213,7 @@ |
207 | 214 | |
208 | 215 | /** |
209 | 216 | * Add a log entry |
210 | | - * @param string $action one of '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'move_redir' |
| 217 | + * @param string $action one of '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'move_redir', 'namespace' |
211 | 218 | * @param object &$target A title object. |
212 | 219 | * @param string $comment Description associated |
213 | 220 | * @param array $params Parameters passed later to wfMsg.* functions |
Index: branches/wikidata/phase3/includes/SpecialNamespaces.php |
— | — | @@ -69,7 +69,7 @@ |
70 | 70 | $talksuffix = wfEscapeJsString(wfMsgForContent('talkpagesuffix')); |
71 | 71 | |
72 | 72 | # For the namespace selection box |
73 | | - $name_array = Namespace::getFormattedDefaultNamespaces(); |
| 73 | + $name_array = Namespace::getFormattedDefaultNamespaces(true); |
74 | 74 | $noparent = wfMsg('no_parent_namespace'); |
75 | 75 | $name_array[key($name_array)-1] = $noparent; |
76 | 76 | |
— | — | @@ -323,7 +323,7 @@ |
324 | 324 | $wgOut->addHTML( $htmlform ); |
325 | 325 | |
326 | 326 | // Pseudonamespace converter |
327 | | - $all_name_array = Namespace::getFormattedDefaultNamespaces(); |
| 327 | + $all_name_array = Namespace::getFormattedDefaultNamespaces(true); |
328 | 328 | $pseudons_select=$this->getSelector($all_name_array); |
329 | 329 | $wgOut->addWikiText( wfMsg( 'fix_pseudonamespaces_header' ) ); |
330 | 330 | $phtmlform =' |
— | — | @@ -447,9 +447,32 @@ |
448 | 448 | // Report success to user |
449 | 449 | $wgOut->addWikiText($complete); |
450 | 450 | $this->showForm(); |
| 451 | + |
| 452 | + $this->logNs('add',$nsname); |
| 453 | + if($nscreatetalk) { |
| 454 | + $this->logNs('add',$nstalkname); |
| 455 | + } |
451 | 456 | } |
452 | 457 | |
453 | 458 | /** |
| 459 | + * Convenient access to the logging functions |
| 460 | + * @param $action - 'add','delete','modify' or 'pseudo' |
| 461 | + * @param $ns - name of the namespace |
| 462 | + * @param $tns - for pseudonamespaces, name of the target namespace |
| 463 | + */ |
| 464 | + function logNs($action,$ns='',$tns='') { |
| 465 | + $log = new LogPage( 'namespace' ); |
| 466 | + $dummyTitle = Title::makeTitle( 0, '' ); |
| 467 | + if($action=='pseudo') { |
| 468 | + $log->addEntry( $action,$dummyTitle,'',array($ns,$tns)); |
| 469 | + } elseif($action=='modify') { |
| 470 | + $log->addEntry( $action,$dummyTitle,''); |
| 471 | + } else { |
| 472 | + $log->addEntry( $action,$dummyTitle,'',array($ns)); |
| 473 | + } |
| 474 | + } |
| 475 | + |
| 476 | + /** |
454 | 477 | * Modify, delete or add namespace names, set default names, |
455 | 478 | * or change namespace properties. Uses the request data from |
456 | 479 | * the form. Note that we have to create a new namespace object, |
— | — | @@ -545,15 +568,18 @@ |
546 | 569 | # Does the name exist and is it non-empty? |
547 | 570 | if( |
548 | 571 | !is_null($dindex) |
549 | | - && array_key_exists($dindex, $newns[$nsindex]->names) |
| 572 | + && array_key_exists($dindex, |
| 573 | + $newns[$nsindex]->names) |
550 | 574 | && !empty($newns[$nsindex]->names[$dindex]) |
551 | 575 | ) { |
552 | 576 | # Use this default name. |
553 | 577 | $newns[$nsindex]->setDefaultNameIndex($dindex); |
554 | 578 | } else { |
555 | | - # We have lost our default name, perhaps it was deleted. |
556 | | - # Get a new one if possible. |
557 | | - $newns[$nsindex]->setDefaultNameIndex($newns[$nsindex]->getNewDefaultNameIndex()); |
| 579 | + # We have lost our default name, perhaps it |
| 580 | + # was deleted. Get a new one if possible. |
| 581 | + $newns[$nsindex]->setDefaultNameIndex( |
| 582 | + $newns[$nsindex]->getNewDefaultNameIndex() |
| 583 | + ); |
558 | 584 | } |
559 | 585 | } |
560 | 586 | |
— | — | @@ -562,20 +588,34 @@ |
563 | 589 | if( $nrv[NS_RESULT] == NS_NAME_ISSUES ) { |
564 | 590 | $this->showForm( |
565 | 591 | wfMsg( |
566 | | - 'namespace_error', |
567 | | - $nns->getDefaultName()), |
568 | | - $this->nameIssues($nrv) |
| 592 | + 'namespace_error', |
| 593 | + $nns->getDefaultName()), |
| 594 | + $this->nameIssues($nrv) |
569 | 595 | ); |
570 | 596 | return false; |
| 597 | + } elseif($nrv[NS_RESULT] == NS_MISSING) { |
| 598 | + $this->showForm( |
| 599 | + wfmsg('namespace_has_gone_missing', |
| 600 | + $nns->getIndex()) |
| 601 | + ); |
| 602 | + return false; |
571 | 603 | } |
| 604 | + } |
| 605 | + |
| 606 | + # Only do anything if everything can be done successfully. |
| 607 | + foreach($newns as $nns) { |
572 | 608 | $nns->save(); |
573 | 609 | } |
574 | 610 | |
| 611 | + # Unfortunately, NS_IDENTICAL does not work consistently |
| 612 | + # atm, so we can only add a generic log entry. |
| 613 | + $this->logNs('modify'); |
| 614 | + |
575 | 615 | # IMPORTANT: The namespace name indexes are unpredictable when |
576 | 616 | # serialized, so we have to reload the definitions from the |
577 | 617 | # database at this point; otherwise, there could be index |
578 | 618 | # mismatches. |
579 | | - Namespace::load(); |
| 619 | + Namespace::load(true); |
580 | 620 | |
581 | 621 | # Return to the namespace manager with the changes made. |
582 | 622 | $wgOut->addWikiText( wfMsg('namespace_changes_saved') ); |
— | — | @@ -677,7 +717,7 @@ |
678 | 718 | /* There should be no delete links for namespaces which cannot |
679 | 719 | be deleted, but let's catch two possible problems just in case. */ |
680 | 720 | if(!array_key_exists( $nsid, $wgNamespaces) ) { |
681 | | - $this->showForm( wfMsg('namespace_not_deletable') , wfMsg('namespace_not_deletable_missing', $nsid) ); |
| 721 | + $this->showForm( wfMsg('namespace_not_deletable') , wfMsg('namespace_has_gone_missing', $nsid) ); |
682 | 722 | return false; |
683 | 723 | } elseif( $wgNamespaces[$nsid]->isSystemNamespace() ) { |
684 | 724 | $this->showForm( wfMsg('namespace_not_deletable') , wfMsg('namespace_not_deletable_system', $nsid) ); |
— | — | @@ -696,6 +736,7 @@ |
697 | 737 | if( $drv[NS_RESULT] == NS_DELETED ) { |
698 | 738 | $wgOut->addWikiText( wfMsg('namespace_deleted',$nsdeletename) ); |
699 | 739 | $this->showForm(); |
| 740 | + $this->logNs('delete',$nsdeletename); |
700 | 741 | return true; |
701 | 742 | } elseif( $drv[NS_RESULT] == NS_NAME_ISSUES ) { |
702 | 743 | $this->showForm( wfMsg('namespace_delete_error',$nsdeletename),$this->nameIssues($drv) ); |
— | — | @@ -750,6 +791,7 @@ |
751 | 792 | } |
752 | 793 | } else { |
753 | 794 | $wgOut->addWikiText(wfMsg('pseudonamespace_converted', $prefix, $wgNamespaces[$targetid]->getDefaultName())); |
| 795 | + $this->logNs('pseudo',$prefix,$wgNamespaces[$targetid]->getDefaultName()); |
754 | 796 | } |
755 | 797 | if($converttalk) { |
756 | 798 | # A pseudonamespace, by definition, exists in the |
Index: branches/wikidata/phase3/languages/Language.php |
— | — | @@ -2226,6 +2226,14 @@ |
2227 | 2227 | 'pseudonamespace_cannot_merge'=>'The target namespace contains pages. You have not specified that you want to merge into a non-empty namespace, or do not have permission to do so. This action is restricted because it is potentially irreversible.', |
2228 | 2228 | 'pseudonamespace_title_dupes'=>'The target namespace already contains pages with the following titles:', |
2229 | 2229 | |
| 2230 | +# Namespace logging |
| 2231 | +'namespacelogpage'=>'Namespace_log', |
| 2232 | +'namespacelogtext'=>'This is a log of all changes made through the namespace manager.', |
| 2233 | +'namespaceaddlog'=>'Added namespace "$2"', |
| 2234 | +'namespacedeletelog'=>'Deleted namespace "$2"', |
| 2235 | +'namespacemodifylog'=>'Modified namespace definitions', |
| 2236 | +'namespacepseudolog'=>'Converted pseudonamespace "$2" into real namespace "$3"', |
| 2237 | + |
2230 | 2238 | # This is appended via JavaScript to the entered namsepace name |
2231 | 2239 | # as a suggested talkpage name in Special:Namespaces. If set to '-', |
2232 | 2240 | # it will not be used. |
— | — | @@ -2247,7 +2255,7 @@ |
2248 | 2256 | 'namespace_delete_name'=>'Delete', |
2249 | 2257 | 'namespace_save_changes'=>'Save changes', |
2250 | 2258 | 'namespace_not_deletable'=>'The namespace cannot be deleted.', |
2251 | | -'namespace_not_deletable_missing'=>'A namespace with the number $1 was not found.', |
| 2259 | +'namespace_has_gone_missing'=>'A namespace with the number $1 was not found.', |
2252 | 2260 | 'namespace_not_deletable_system'=>'The namespace with the number $1 is a system namespace which is required for the operation of MediaWiki.', |
2253 | 2261 | |
2254 | 2262 | # Other namespace stuff |