r19779 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r19778‎ | r19779 | r19780 >
Date:04:21, 5 February 2007
Author:erik
Status:old
Tags:
Comment:
Namespace code merge (with architectural changes by Rob Lanphier,
separating storage class & namespace class, and UI changes
by Brion).
Modified paths:
  • /branches/wikidata/RELEASE-NOTES (modified) (history)
  • /branches/wikidata/config/index.php (modified) (history)
  • /branches/wikidata/includes/AutoLoader.php (modified) (history)
  • /branches/wikidata/includes/DefaultSettings.php (modified) (history)
  • /branches/wikidata/includes/Defines.php (modified) (history)
  • /branches/wikidata/includes/GlobalFunctions.php (modified) (history)
  • /branches/wikidata/includes/Namespace.php (modified) (history)
  • /branches/wikidata/includes/NamespaceStore.php (added) (history)
  • /branches/wikidata/includes/SkinTemplate.php (modified) (history)
  • /branches/wikidata/includes/SpecialNamespaces.php (added) (history)
  • /branches/wikidata/includes/SpecialPage.php (modified) (history)
  • /branches/wikidata/includes/Title.php (modified) (history)
  • /branches/wikidata/languages/Language.php (modified) (history)
  • /branches/wikidata/languages/messages/MessagesEn.php (modified) (history)
  • /branches/wikidata/maintenance/archives/patch-namespace.sql (added) (history)
  • /branches/wikidata/maintenance/archives/patch-namespace_names.sql (added) (history)
  • /branches/wikidata/maintenance/mysql5/tables.sql (modified) (history)
  • /branches/wikidata/maintenance/nsBootstrap.php (added) (history)
  • /branches/wikidata/maintenance/tables.sql (modified) (history)
  • /branches/wikidata/maintenance/updaters.inc (modified) (history)

Diff [purge]

Index: branches/wikidata/maintenance/archives/patch-namespace.sql
@@ -0,0 +1,15 @@
 2+-- New namespace system
 3+
 4+DROP TABLE IF EXISTS /*$wgDBprefix*/namespace;
 5+CREATE TABLE /*$wgDBprefix*/namespace (
 6+ `ns_id` int(8) NOT NULL default '0',
 7+ `ns_system` varchar(80) default '',
 8+ `ns_subpages` tinyint(1) NOT NULL default '0',
 9+ `ns_search_default` tinyint(1) NOT NULL default '0',
 10+ `ns_target` varchar(200) default NULL,
 11+ `ns_parent` int(8) default NULL,
 12+ `ns_hidden` tinyint(1) default NULL,
 13+ `ns_count` tinyint(1) default NULL,
 14+ `ns_class` varchar(255) default '',
 15+ PRIMARY KEY (`ns_id`)
 16+) TYPE=InnoDB;
Property changes on: branches/wikidata/maintenance/archives/patch-namespace.sql
___________________________________________________________________
Added: svn:eol-style
117 + native
Index: branches/wikidata/maintenance/archives/patch-namespace_names.sql
@@ -0,0 +1,9 @@
 2+-- New namespace system
 3+
 4+DROP TABLE IF EXISTS /*$wgDBprefix*/namespace_names;
 5+CREATE TABLE /*$wgDBprefix*/namespace_names (
 6+ `ns_id` int(8) NOT NULL default '0',
 7+ `ns_name` varchar(200) NOT NULL default '',
 8+ `ns_default` tinyint(1) NOT NULL default '0',
 9+ `ns_canonical` tinyint(1) default NULL
 10+) TYPE=InnoDB;
Property changes on: branches/wikidata/maintenance/archives/patch-namespace_names.sql
___________________________________________________________________
Added: svn:eol-style
111 + native
Index: branches/wikidata/maintenance/nsBootstrap.php
@@ -0,0 +1,233 @@
 2+<?php
 3+// Purpose: Create entries in the namespace and namespace_names tables,
 4+// based on the configured language. Take into account existing (deprecated)
 5+// namespace settings in an update.
 6+//
 7+// We can't depend on commandLine.inc because this has to be runnable from the installer
 8+
 9+
 10+global $wgLanguageCode;
 11+$wgContLanguageCode = $wgLanguageCode;
 12+$wgContLangClass = 'Language' . str_replace( '-', '_', ucfirst( $wgContLanguageCode ) );
 13+
 14+$wgContLang = new StubContLang;
 15+$wgContLang->initEncoding();
 16+
 17+class NamespaceBootstrap {
 18+ var $mStdNs;
 19+ var $mExtraNs;
 20+ var $dbw;
 21+
 22+ var $mContLangNs;
 23+ var $mContLangNsSynonyms;
 24+ var $mLanguageCode;
 25+
 26+ function NamespaceBootstrap() {
 27+ global $wgExtraNamespaces, $wgContLang, $wgNamespaceSynonymsEn;
 28+
 29+ $this->mStdNs = array(
 30+ 'NS_MEDIA' => NS_MEDIA,
 31+ 'NS_SPECIAL' => NS_SPECIAL,
 32+ 'NS_MAIN' => NS_MAIN,
 33+ 'NS_MAIN' => NS_MAIN,
 34+ 'NS_TALK' => NS_TALK,
 35+ 'NS_USER' => NS_USER,
 36+ 'NS_USER_TALK' => NS_USER_TALK,
 37+ 'NS_PROJECT' => NS_PROJECT,
 38+ 'NS_PROJECT_TALK' => NS_PROJECT_TALK,
 39+ 'NS_IMAGE' => NS_IMAGE,
 40+ 'NS_IMAGE_TALK' => NS_IMAGE_TALK,
 41+ 'NS_MEDIAWIKI' => NS_MEDIAWIKI,
 42+ 'NS_MEDIAWIKI_TALK' => NS_MEDIAWIKI_TALK,
 43+ 'NS_TEMPLATE' => NS_TEMPLATE,
 44+ 'NS_TEMPLATE_TALK' => NS_TEMPLATE_TALK,
 45+ 'NS_HELP' => NS_HELP,
 46+ 'NS_HELP_TALK' => NS_HELP_TALK,
 47+ 'NS_CATEGORY' => NS_CATEGORY,
 48+ 'NS_CATEGORY_TALK' => NS_CATEGORY_TALK
 49+ );
 50+
 51+ $this->mExtraNs = isset( $wgExtraNamespaces ) ? $wgExtraNamespaces : array();
 52+ $this->mContLangNs = $wgContLang->getNamespacesBootstrap();
 53+ $this->mLanguageCode = $wgContLang->getCode();
 54+
 55+ if ( $wgNamespaceSynonymsEn == $wgContLang->getNamespaceSynonymsBootstrap() && $this->mLanguageCode !== 'en' )
 56+ $this->mContLangNsSynonyms = array();
 57+ else
 58+ $this->mContLangNsSynonyms = $wgContLang->getNamespaceSynonymsBootstrap();
 59+
 60+
 61+ $this->dbw =& wfGetDB( DB_MASTER );
 62+ }
 63+
 64+ function initialize() {
 65+ global $wgContLang;
 66+
 67+ $fname = 'NamespaceBootstrap::initialize';
 68+
 69+ // namespace table, standard namespaces
 70+ foreach ( $this->mStdNs as $system => $id ) {
 71+ $subject = $this->getSubject( $id );
 72+
 73+ $this->dbw->insert( 'namespace',
 74+ array(
 75+ 'ns_id' => $id,
 76+ 'ns_system' => $system,
 77+ 'ns_subpages' => $this->getSubpages( $id ),
 78+ 'ns_search_default' => $this->getSearch( $id ),
 79+ 'ns_target' => null,
 80+ 'ns_parent' => $subject === $id ? null : $subject,
 81+ 'ns_hidden' => null,
 82+ 'ns_count' => $id == NS_MAIN ? true : false,
 83+ 'ns_class' => null,
 84+ ),
 85+ $fname
 86+ );
 87+ }
 88+
 89+ // namespace table, extra namespaces
 90+ foreach ( $this->mExtraNs as $id => $name ) {
 91+ $subject = $this->getSubject( $id );
 92+
 93+ $this->dbw->insert( 'namespace',
 94+ array(
 95+ 'ns_id' => $id,
 96+ 'ns_system' => null, // extra namespaces are null
 97+ 'ns_subpages' => $this->getSubpages( $id ),
 98+ 'ns_search_default' => $this->getSearch( $id ),
 99+ 'ns_target' => null,
 100+ 'ns_parent' => $subject === $id ? null : $subject,
 101+ 'ns_hidden' => null,
 102+ 'ns_count' => false,
 103+ 'ns_class' => null,
 104+ ),
 105+ $fname
 106+ );
 107+ }
 108+
 109+ // Cache already inserted results so we won't get a case where
 110+ // we'll do a bogus insert because namespaces haven't been
 111+ // translated or the translation equals the original.
 112+ $nscache = array();
 113+
 114+ // namespace_names, English fallbacks
 115+
 116+ //FIXME: need to use proper language code
 117+ $langobj = Language::factory( 'en' );
 118+ $langobj->initEncoding();
 119+ $langobj->initContLang();
 120+
 121+ foreach ( $langobj->getNamespaces() as $id => $text ) {
 122+ if ( @$nscache[$id] === $text || $text === '' )
 123+ continue;
 124+
 125+ $nscache[$id] = $text;
 126+
 127+ $this->dbw->insert( 'namespace_names',
 128+ array(
 129+ 'ns_id' => $id,
 130+ 'ns_name' => $text,
 131+ 'ns_default' => $this->mLanguageCode == 'en' || $this->mContLangNs[$id] === $text ? 1 : 0,
 132+ 'ns_canonical' => 1,
 133+ ),
 134+ $fname
 135+ );
 136+ }
 137+
 138+
 139+ // namespace_names, content language
 140+ foreach ( $this->mContLangNs as $ns => $text ) {
 141+ if ( $text === '' || @$nscache[$ns] === $text )
 142+ continue;
 143+
 144+ $nscache[$ns] = $text;
 145+
 146+ $this->dbw->insert( 'namespace_names',
 147+ array(
 148+ 'ns_id' => $ns,
 149+ 'ns_name' => $text,
 150+ 'ns_default' => 1,
 151+ 'ns_canonical' => 0
 152+ ),
 153+ $fname
 154+ );
 155+
 156+ }
 157+
 158+ // namespace_names, synonyms
 159+ foreach ( $this->mContLangNsSynonyms as $id => $synonyms )
 160+ foreach ( $synonyms as $synonym ) {
 161+ if ( $nscache[$id] === $synonym )
 162+ continue;
 163+
 164+ $this->dbw->insert( 'namespace_names',
 165+ array(
 166+ 'ns_id' => $id,
 167+ 'ns_name' => $synonym,
 168+ 'ns_default' => 0,
 169+ 'ns_canonical' => 0
 170+ ),
 171+ $fname
 172+ );
 173+ }
 174+
 175+ // namespace_names, Project and Project_talk are special cases, should be canonical
 176+ foreach ( array( NS_PROJECT => 'Project', NS_PROJECT_TALK => 'Project_talk' ) as $id => $text ) {
 177+ if ( $nscache[$id] === $text )
 178+ continue;
 179+
 180+ $this->dbw->insert( 'namespace_names',
 181+ array(
 182+ 'ns_id' => $id,
 183+ 'ns_name' => $text,
 184+ 'ns_default' => 0,
 185+ 'ns_canonical' => 1
 186+ ),
 187+ $fname
 188+ );
 189+ }
 190+
 191+ // namespace_names, Import extra namespaces specified using
 192+ // legacy syntax.
 193+ foreach ( $this->mExtraNs as $id => $name ) {
 194+ $this->dbw->insert( 'namespace_names',
 195+ array(
 196+ 'ns_id' => "$id",
 197+ 'ns_name' => $name,
 198+ 'ns_default' => 1,
 199+ 'ns_canonical' => 0,
 200+ ),
 201+ $fname
 202+ );
 203+ }
 204+ }
 205+
 206+ function getSubpages( $ns ) {
 207+ global $wgNamespacesWithSubpages;
 208+
 209+ return @$wgNamespacesWithSubpages[$ns] ? 1 : 0;
 210+
 211+ }
 212+
 213+ function getSearch( $ns ) {
 214+ global $wgNamespacesToBeSearchedDefault;
 215+
 216+ return @$wgNamespacesToBeSearchedDefault[$ns] ? 1 : 0;
 217+ }
 218+
 219+ function isTalk( $index ) {
 220+ return ($index > 0) // Special namespaces are negative
 221+ && ($index % 2); // Talk namespaces are odd-numbered
 222+ }
 223+
 224+ function getSubject( $index ) {
 225+ if ( $this->isTalk( $index ) ) {
 226+ return $index - 1;
 227+ } else {
 228+ return $index;
 229+ }
 230+ }
 231+}
 232+
 233+$nb = new NamespaceBootstrap;
 234+$nb->initialize();
Property changes on: branches/wikidata/maintenance/nsBootstrap.php
___________________________________________________________________
Added: svn:eol-style
1235 + native
Index: branches/wikidata/maintenance/updaters.inc
@@ -35,6 +35,8 @@
3636 array( 'querycache_info', 'patch-querycacheinfo.sql' ),
3737 array( 'filearchive', 'patch-filearchive.sql' ),
3838 array( 'querycachetwo', 'patch-querycachetwo.sql' ),
 39+ array( 'namespace', 'patch-namespace.sql' ),
 40+ array( 'namespace_names', 'patch-namespace_names.sql' ),
3941 );
4042
4143 $wgNewFields = array(
Index: branches/wikidata/maintenance/mysql5/tables.sql
@@ -1110,3 +1110,52 @@
11111111 KEY pr_level (pr_level),
11121112 KEY pr_cascade (pr_cascade)
11131113 ) ENGINE=InnoDB, DEFAULT CHARSET=utf8;
 1114+
 1115+CREATE TABLE /*$wgDBprefix*/namespace (
 1116+ -- This ID appears in all tables where this namespace is referenced.
 1117+ -- Note that the constants for system namespaces are currently
 1118+ -- hardcoded (Defines.php), and special namespaces start at -2.
 1119+ `ns_id` int(8) NOT NULL default '0',
 1120+ -- If this is a system namespace, this field contains the constant
 1121+ -- name identifying it (e.g. 'NS_MAIN', 'NS_CATEGORY').
 1122+ `ns_system` varchar(80) default '',
 1123+ -- Should this namespace allow subpages ([[Foo/Bar]])?
 1124+ `ns_subpages` tinyint(1) NOT NULL default '0',
 1125+ -- Should pages in this namespace be included in a full-text search
 1126+ -- by default?
 1127+ `ns_search_default` tinyint(1) NOT NULL default '0',
 1128+ -- If not empty, unprefixed links from this namespace (e.g. [[Foo]])
 1129+ -- will be treated as if they had this prefix. This could be a
 1130+ -- namespace prefix, a language prefix, or an interwiki prefix.
 1131+ `ns_target` varchar(200) default NULL,
 1132+ -- If this is a discussion namespace, this field refers to its subject
 1133+ -- namespace.
 1134+ `ns_parent` int(8) default NULL,
 1135+ -- Should this namespace be hidden by default from namespace selectors?
 1136+ -- [[Special:Allpages]] and [[Special:Namaespaces]] are excepted
 1137+ -- from this.
 1138+ `ns_hidden` tinyint(1) default NULL,
 1139+ -- Should an external class be used to override edit, view and delete?
 1140+ -- It will be expected in extensions/ClassName/ClassName.php
 1141+ -- Should pages in this namespace be counted as content?
 1142+ `ns_count` tinyint(1) default NULL,
 1143+ `ns_class` varchar(255) default '',
 1144+ PRIMARY KEY (`ns_id`)
 1145+) TYPE=InnoDB, DEFAULT CHARSET=utf8;
 1146+
 1147+CREATE TABLE /*$wgDBprefix*/namespace_names (
 1148+ -- A reference to the namespace to which this name belongs.
 1149+ -- Any namespace can have multiple names, so this is not
 1150+ -- a primary key.
 1151+ `ns_id` int(8) NOT NULL default '0',
 1152+ -- The name of this namespace. Spaces are underscores here.
 1153+ `ns_name` varchar(200) NOT NULL default '',
 1154+ -- Is this the default name to which all others redirect?
 1155+ `ns_default` tinyint(1) NOT NULL default '0',
 1156+ -- Is this the canonical English name which is expected to
 1157+ -- exist, and which cannot be deleted? (Mostly for system
 1158+ -- namespaces.)
 1159+ `ns_canonical` tinyint(1) default NULL,
 1160+ UNIQUE INDEX ns_name (ns_name),
 1161+ INDEX ns_id (ns_id)
 1162+) TYPE=InnoDB, DEFAULT CHARSET=utf8;
Index: branches/wikidata/maintenance/tables.sql
@@ -1105,4 +1105,54 @@
11061106 KEY pr_cascade (pr_cascade)
11071107 ) TYPE=InnoDB;
11081108
 1109+
 1110+CREATE TABLE /*$wgDBprefix*/namespace (
 1111+ -- This ID appears in all tables where this namespace is referenced.
 1112+ -- Note that the constants for system namespaces are currently
 1113+ -- hardcoded (Defines.php), and special namespaces start at -2.
 1114+ `ns_id` int(8) NOT NULL default '0',
 1115+ -- If this is a system namespace, this field contains the constant
 1116+ -- name identifying it (e.g. 'NS_MAIN', 'NS_CATEGORY').
 1117+ `ns_system` varchar(80) default '',
 1118+ -- Should this namespace allow subpages ([[Foo/Bar]])?
 1119+ `ns_subpages` tinyint(1) NOT NULL default '0',
 1120+ -- Should pages in this namespace be included in a full-text search
 1121+ -- by default?
 1122+ `ns_search_default` tinyint(1) NOT NULL default '0',
 1123+ -- If not empty, unprefixed links from this namespace (e.g. [[Foo]])
 1124+ -- will be treated as if they had this prefix. This could be a
 1125+ -- namespace prefix, a language prefix, or an interwiki prefix.
 1126+ `ns_target` varchar(200) default NULL,
 1127+ -- If this is a discussion namespace, this field refers to its subject
 1128+ -- namespace.
 1129+ `ns_parent` int(8) default NULL,
 1130+ -- Should this namespace be hidden by default from namespace selectors?
 1131+ -- [[Special:Allpages]] and [[Special:Namaespaces]] are excepted
 1132+ -- from this.
 1133+ `ns_hidden` tinyint(1) default NULL,
 1134+ -- Should pages in this namespace be counted as content?
 1135+ `ns_count` tinyint(1) default NULL,
 1136+ -- Should an external class be used to override edit, view and delete?
 1137+ -- It will be expected in extensions/ClassName/ClassName.php
 1138+ `ns_class` varchar(255) default '',
 1139+ PRIMARY KEY (`ns_id`)
 1140+) TYPE=InnoDB;
 1141+
 1142+CREATE TABLE /*$wgDBprefix*/namespace_names (
 1143+ -- A reference to the namespace to which this name belongs.
 1144+ -- Any namespace can have multiple names, so this is not
 1145+ -- a primary key.
 1146+ `ns_id` int(8) NOT NULL default '0',
 1147+ -- The name of this namespace. Spaces are underscores here.
 1148+ `ns_name` varchar(200) NOT NULL default '',
 1149+ -- Is this the default name to which all others redirect?
 1150+ `ns_default` tinyint(1) NOT NULL default '0',
 1151+ -- Is this the canonical English name which is expected to
 1152+ -- exist, and which cannot be deleted? (Mostly for system
 1153+ -- namespaces.)
 1154+ `ns_canonical` tinyint(1) default NULL,
 1155+ UNIQUE INDEX ns_name (ns_name),
 1156+ INDEX ns_id (ns_id)
 1157+) TYPE=InnoDB;
 1158+
11091159 -- vim: sw=2 sts=2 et
Index: branches/wikidata/includes/Defines.php
@@ -205,5 +205,44 @@
206206 define( 'LIST_NAMES', 3);
207207 define( 'LIST_OR', 4);
208208
 209+/**#@+
 210+ * Namespace changes result codes
 211+ * See Namespace.php
 212+ */
 213+define('NS_RESULT',1);
 214+define('NS_SAVE_ID',2);
 215+define('NS_ILLEGAL_NAMES',3);
 216+define('NS_DUPLICATE_NAMES',4);
 217+define('NS_INTERWIKI_NAMES',5);
 218+define('NS_PREFIX_NAMES',6);
 219+/**#@-*/
209220
 221+/**#@+
 222+ * Namespace changes success codes
 223+ */
 224+define('NS_MODIFIED',1);
 225+define('NS_CREATED',2);
 226+define('NS_NAME_ISSUES',3);
 227+define('NS_MISSING',4);
 228+define('NS_IDENTICAL',5);
 229+define('NS_DELETED',6);
 230+define('NS_PROTECTED',7);
 231+define('NS_HAS_PAGES',8);
 232+/**#@-*/
 233+
 234+/**#@+
 235+ * Pseudonamespace conversions
 236+ */
 237+define('NS_PSEUDO_NOT_FOUND',1);
 238+define('NS_PSEUDO_CONVERTED',2);
 239+define('NS_NON_EMPTY',3);
 240+define('NS_DUPLICATE_TITLES',4);
 241+define('NS_DUPLICATE_TITLE_LIST',5);
 242+
 243+/**#@+
 244+ * Valid namespace names character class
 245+ */
 246+define('NS_CHAR','[ _0-9A-Za-z\x80-\xff]');
 247+
 248+
210249 ?>
Index: branches/wikidata/includes/GlobalFunctions.php
@@ -1565,6 +1565,20 @@
15661566 return MimeMagic::singleton();
15671567 }
15681568
 1569+ /**
 1570+ * Class factory for NamespaceStore singleton. NamespaceStore.php
 1571+ * is autoloaded thanks to definition in AutoLoader.php
 1572+ */
 1573+
 1574+function &wfGetNamespaceStore() {
 1575+ static $nsstore = null;
 1576+ if($nsstore == null) {
 1577+ $nsstore = new NamespaceStore();
 1578+ $nsstore->load();
 1579+ }
 1580+ return $nsstore;
 1581+}
 1582+
15691583 /**
15701584 * Tries to get the system directory for temporary files.
15711585 * The TMPDIR, TMP, and TEMP environment variables are checked in sequence,
Index: branches/wikidata/includes/NamespaceStore.php
@@ -0,0 +1,671 @@
 2+<?php
 3+/**
 4+ * Class for storing and retrieving namespace objects
 5+ *
 6+*/
 7+class NamespaceStore {
 8+ function NamespaceStore() {
 9+ global $wgNamespaces;
 10+ $this->nsarray = $wgNamespaces;
 11+ }
 12+
 13+ function getTalk($parentns) {
 14+ if($parentns->isTalk()) return $parentns->getIndex();
 15+
 16+ foreach($this->nsarray as $ns) {
 17+ if($ns->hasParent() && $ns->parentIndex==$parentns->index) {
 18+ return $ns->index;
 19+ }
 20+ }
 21+
 22+ return null;
 23+ }
 24+
 25+ /**
 26+ * Serialize this namespace to the database.
 27+ * No part of the operation will be completed
 28+ * unless it cannot be fully done.
 29+ *
 30+ * If the namespace index is NULL, a new namespace
 31+ * will be created.
 32+ *
 33+ * @param boolean $testSave
 34+ * If this is set to true, no actual changes
 35+ * will be made. This is useful for testing
 36+ * transactions on a number of namespaces,
 37+ * and not completing any of them unless
 38+ * all of them will succeed.
 39+ * @param boolean $overrideInterwiki
 40+ * If a namespace name overlaps with an Interwiki
 41+ * prefix, should it be created anyway?
 42+ *
 43+ * @return array()
 44+ * An array that describes the results of the
 45+ * operation, as follows:
 46+ *
 47+ * array(
 48+ * NS_RESULT=>
 49+ * NS_MODIFIED | NS_CREATED | NS_NAME_ISSUES
 50+ * NS_MISSING | NS_IDENTICAL
 51+ * NS_SAVE_ID=>namespace ID or NULL
 52+ * NS_ILLEGAL_NAMES=>array(names)
 53+ * NS_DUPLICATE_NAMES=>array(names)
 54+ * NS_INTERWIKI_NAMES=>array(names)
 55+ * NS_PREFIX_NAMES=>array(names)
 56+ * )
 57+ *
 58+ * NS_RESULT can be:
 59+ *
 60+ * NS_MODIFIED - existing namespace successfully changed
 61+ * NS_CREATED - new namespace successfully created
 62+ * NS_IDENTICAL - the version in the database is
 63+ * identical with the one to be saved
 64+ * NS_NAME_ISSUES - operation failed due to issues with
 65+ * name changes
 66+ * NS_MISSING - namespace with $nsobj->index not found
 67+ * in DB, cannot be altered.
 68+ *
 69+ * In order to show useful result information, we record
 70+ * exactly which names have been added, removed or changed
 71+ * (NS_NAMES_ADDED, NS_NAMES_MODIFIED, NS_NAMES_DELETED).
 72+ * If the save fails, we record which name change(s) caused
 73+ * the problem:
 74+ *
 75+ * NS_ILLEGAL_NAMES
 76+ * names which contain illegal characters
 77+ *
 78+ * NS_DUPLICATE_NAMES
 79+ * names which already exist
 80+ *
 81+ * NS_INTERWIKI_NAMES
 82+ * names which are also used as Interwiki prefixes
 83+ * (cf. $overrideInterwiki parameter)
 84+ *
 85+ * NS_PREFIX_NAMES
 86+ * names which are used as hardcoded title prefixes
 87+ *
 88+ * How this function works:
 89+ * ------------------------
 90+ * Check if the namespace has a valid ID (not null)
 91+ *
 92+ * NO: We will try to create it.
 93+ *
 94+ * 1.1) Obtain an index from $this->nsarray
 95+ * 1.2) Make a list of the names that are going
 96+ * to be added.
 97+ * 1.3) Proceed to 2.2)
 98+ *
 99+ * YES: We will try to modify it.
 100+ *
 101+ * 2.1) Compare this object with the corresponding
 102+ * one in $this->nsarray and make a list of
 103+ * the names that are going to be removed
 104+ * (set to NULL), changed, or added.
 105+ * 2.2) Verify whether all namespace name operations
 106+ * are possible. If not, return the appropriate
 107+ * error codes.
 108+ * 2.3) If all operations are possible, update or
 109+ * update the namespace and return the appropriate
 110+ * result array.
 111+ */
 112+ function saveNamespace($nsobj,
 113+ $overrideInterwiki=false,
 114+ $testSave=false) {
 115+
 116+ $fname='NamespaceStore::saveNamespace';
 117+ $rv=array(
 118+ NS_RESULT=>null,
 119+ NS_ILLEGAL_NAMES=>array(),
 120+ NS_DUPLICATE_NAMES=>array(),
 121+ NS_INTERWIKI_NAMES=>array(),
 122+ NS_PREFIX_NAMES=>array()
 123+ );
 124+ $nameOperations=array();
 125+ $dbs =& wfGetDB( DB_SLAVE );
 126+ $index=$nsobj->getIndex();
 127+ if(is_null($index)) {
 128+ $create = true;
 129+ end($this->nsarray);
 130+ $index=$this->nsarray[key($this->nsarray)]->getIndex()+1;
 131+ $nsobj->setIndex($index);
 132+ foreach($nsobj->names as $name) {
 133+ $nameOperations[$name]=NS_NAME_ADD;
 134+ }
 135+ } else {
 136+ $create = false;
 137+ # Does this namespace exist?
 138+ if(!array_key_exists($index,$this->nsarray)) {
 139+ $rv[NS_RESULT]=NS_MISSING;
 140+ return $rv;
 141+ }
 142+ # Has anything actually been changed?
 143+ if($nsobj===$this->nsarray[$nsobj->getIndex()]) {
 144+ $rv[NS_RESULT]=NS_IDENTICAL;
 145+ return $rv;
 146+ }
 147+ $oldcount=count($this->nsarray[$index]->names);
 148+ $newcount=count($nsobj->names);
 149+ for($i=0;$i<$oldcount || $i<$newcount;$i++) {
 150+ $existsOld=array_key_exists($i, $this->nsarray[$index]->names);
 151+ $existsNew=array_key_exists($i, $nsobj->names);
 152+ if($existsOld && $existsNew) {
 153+ if(strcasecmp($this->nsarray[$index]->names[$i], $nsobj->names[$i])!=0) {
 154+ $nameOperations[$nsobj->names[$i]]=NS_NAME_MODIFY;
 155+ }
 156+ } elseif($existsOld && !$existsNew) {
 157+ $nameOperations[$this->nsarray[$index]->names[$i]]=NS_NAME_DELETE;
 158+ } elseif(!$existsOld && $existsNew) {
 159+ $nameOperations[$nsobj->names[$i]]=NS_NAME_ADD;
 160+ }
 161+ }
 162+
 163+ }
 164+
 165+ # Are there any name operations to do? If so, check
 166+ # whether they are possible before doing anything else.
 167+ foreach($nameOperations as $name=>$operation) {
 168+ if($operation==NS_NAME_ADD || $operation==NS_NAME_MODIFY) {
 169+
 170+ # Illegal characters?
 171+ # This should never happen if the setters
 172+ # are used.
 173+ if(!$nsobj->isValidName($name)) {
 174+ $rv[NS_RESULT]=NS_NAME_ISSUES;
 175+ $rv[NS_ILLEGAL_NAMES][]=$name;
 176+ }
 177+
 178+ # Duplicate names
 179+ foreach($this->nsarray as $exns) {
 180+ $dupes=array_keys($exns->names,$name);
 181+ if(count($dupes)) {
 182+ $rv[NS_RESULT] = NS_NAME_ISSUES;
 183+ $rv[NS_DUPLICATE_NAMES][]=$name;
 184+ }
 185+ }
 186+
 187+ # Interwiki
 188+ if(Title::getInterwikiLink( $name)) {
 189+ $rv[NS_RESULT]=NS_NAME_ISSUES;
 190+ $rv[NS_INTERWIKI_NAMES][]=$name;
 191+ }
 192+
 193+ # Pseudo-namespaces (title prefixes)
 194+ $likename = str_replace( '_', '\\_', $name);
 195+ $likename = str_replace( '%', '\\%', $likename);
 196+ $match = $dbs->addQuotes($likename.":%");
 197+ $res = $dbs->select(
 198+ 'page',
 199+ array('page_title'),
 200+ array('page_namespace'=>0,
 201+ 'page_title LIKE '.$match,
 202+ ),
 203+ $fname,
 204+ array('LIMIT'=>1)
 205+ );
 206+ if($dbs->numRows($res) > 0) {
 207+ $rv[NS_RESULT]=NS_NAME_ISSUES;
 208+ $rv[NS_PREFIX_NAMES][]=$name;
 209+ }
 210+ $dbs->freeResult($res);
 211+ }
 212+ }
 213+
 214+ # If there are problems, return the array
 215+ if($rv[NS_RESULT]==NS_NAME_ISSUES) {
 216+ return $rv;
 217+ }
 218+
 219+ $dbm =& wfGetDB(DB_MASTER);
 220+ $nsasdb=array(
 221+ 'ns_id'=>$index,
 222+ 'ns_system'=>$nsobj->getSystemType(),
 223+ 'ns_subpages'=>$nsobj->allowsSubpages(),
 224+ 'ns_search_default'=>$nsobj->isSearchedByDefault(),
 225+ 'ns_target'=>$nsobj->getTarget(),
 226+ 'ns_parent'=>$nsobj->getParentIndex(),
 227+ 'ns_hidden'=>$nsobj->isHidden()
 228+ );
 229+ if($create) {
 230+ # testSave checks should always be placed
 231+ # right before a transaction that alters
 232+ # the database or memory state.
 233+ if(!$testSave) {
 234+ $dbm->insert(
 235+ 'namespace',
 236+ $nsasdb,
 237+ $fname,
 238+ array()
 239+ );
 240+ }
 241+ }
 242+ foreach($nameOperations as $name=>$operation) {
 243+ if($operation==NS_NAME_ADD) {
 244+ $isDefault = ($name==$nsobj->getDefaultName());
 245+ $isCanonical = ($name==$nsobj->getCanonicalName());
 246+ if(!$testSave) {
 247+ $dbm->insert(
 248+ 'namespace_names',
 249+ array(
 250+ 'ns_id'=>$nsobj->getIndex(),
 251+ 'ns_name'=>$name,
 252+ 'ns_default'=>$isDefault,
 253+ 'ns_canonical'=>$isCanonical
 254+ ),
 255+ $fname,
 256+ array()
 257+ );
 258+ }
 259+ } elseif($operation==NS_NAME_MODIFY) { $oldname = $this->nsarray[$index]->names[$nsobj->getNameIndexForName($name)];
 260+ if(!$testSave) {
 261+ $dbm->update(
 262+ 'namespace_names',
 263+ array( /* SET */
 264+ 'ns_name'=>$name,
 265+ ),
 266+ array(
 267+ 'ns_name'=>$oldname),
 268+ $fname);
 269+ }
 270+ } elseif($operation==NS_NAME_DELETE) {
 271+ $dbm->delete(
 272+ 'namespace_names',
 273+ array('ns_name'=>$name),
 274+ '*');
 275+ }
 276+ }
 277+ if($create) {
 278+ $rv[NS_RESULT]=NS_CREATED;
 279+
 280+ # If this was just a test for a new
 281+ # namespace, reset the index to NULL so
 282+ # it will be created for real
 283+ # if save() is called on the same object.
 284+ if($testSave) {
 285+ $nsobj->setIndex(NULL);
 286+ }
 287+ } else {
 288+ # Set canonical and default names.
 289+ # This needs to happen after other name operations
 290+ # because we can't operate on the new names until
 291+ # they exist. :-)
 292+ $oldDefaultName=$this->nsarray[$index]->getDefaultName();
 293+ $newDefaultName=$nsobj->getDefaultName();
 294+
 295+ # Note that canonical names normally should NEVER change,
 296+ # but we provide the functionality just in case it's needed
 297+ # by some maintenance scripts.
 298+ $oldCanonical=$this->nsarray[$index]->getCanonicalName();
 299+ $newCanonical=$nsobj->getCanonicalName();
 300+ if(!$testSave) {
 301+ $dbm->update(
 302+ 'namespace',
 303+ $nsasdb, /* SET */
 304+ array('ns_id'=>$index),
 305+ $fname
 306+ );
 307+ if($oldDefaultName != $newDefaultName) {
 308+ $dbm->update(
 309+ 'namespace_names',
 310+ array('ns_default'=>0), /* SET */
 311+ array('ns_name'=>$oldDefaultName),
 312+ $fname
 313+ );
 314+ $dbm->update(
 315+ 'namespace_names',
 316+ array('ns_default'=>1), /* SET */
 317+ array('ns_name'=>$newDefaultName),
 318+ $fname
 319+ );
 320+ }
 321+ if($oldCanonical != $newCanonical) {
 322+ $dbm->update(
 323+ 'namespace_names',
 324+ array('ns_canonical'=>0), /* SET */
 325+ array('ns_name'=>$oldCanonical),
 326+ $fname
 327+ );
 328+ $dbm->update(
 329+ 'namespace_names',
 330+ array('ns_canonical'=>1), /* SET */
 331+ array('ns_name'=>$newCanonical),
 332+ $fname
 333+ );
 334+ }
 335+ }
 336+
 337+ $rv[NS_RESULT]=NS_MODIFIED;
 338+ }
 339+ $rv[NS_SAVE_ID]=$index;
 340+
 341+ # Note that it may be desirable to call Namespace::load()
 342+ # in addition to this since the name (not namespace) indexes in
 343+ # the database can be different from the one in the array.
 344+ if(!$testSave) {
 345+ $this->nsarray[$index]=$nsobj;
 346+ }
 347+ $this->refreshReverseIndex();
 348+ return $rv;
 349+ }
 350+ /**
 351+ * Delete a namespace from the database and the namespace array.
 352+ * Only use this on clone()s of objects in the $this->nsarray array.
 353+ * This function allows deleting system namespaces if explicitly
 354+ * specified; this should however not be possible through the
 355+ * user interface.
 356+ *
 357+ * @param $deleteSystem bool Override system namespace protection
 358+ */
 359+ function deleteNamespace($nsobj, $deleteSystem=false) {
 360+ if(is_null($nsobj->getIndex())) {
 361+ return array(NS_RESULT=>NS_MISSING);
 362+ }
 363+
 364+ if($nsobj->isSystemNamespace() && !$deleteSystem) {
 365+ return array(NS_RESULT=>NS_PROTECTED);
 366+ }
 367+ if($nsobj->countPages()>0) {
 368+ return array(NS_RESULT=>NS_HAS_PAGES);
 369+ }
 370+ # Remove all names
 371+ $nsobj->removeAllNames();
 372+ # Try saving
 373+ $trv=$nsobj->testSave();
 374+ if($trv[NS_RESULT]!=NS_MODIFIED) {
 375+ return $trv;
 376+ }
 377+
 378+ # As we just have to delete everything, we go
 379+ # right into the database if the test succeeds.
 380+ $dbm =& wfGetDB( DB_MASTER );
 381+ $dbm->delete(
 382+ 'namespace',
 383+ array('ns_id'=>$nsobj->getIndex()),
 384+ '*');
 385+ $dbm->delete(
 386+ 'namespace_names',
 387+ array('ns_id'=>$nsobj->getIndex()),
 388+ '*');
 389+ # Don't forget it's still in memory.
 390+ unset($this->nsarray[$nsobj->getIndex()]);
 391+ $this->refreshReverseIndex();
 392+ return array(NS_RESULT=>NS_DELETED);
 393+ }
 394+
 395+
 396+ /**
 397+ * Maintain index used by getIndexByName
 398+ */
 399+ function refreshReverseIndex() {
 400+ $this->reverseindex = array();
 401+ foreach ($this->nsarray as $ns) {
 402+ foreach($ns->names as $name) {
 403+ $this->reverseindex[strtolower($name)]=$ns->getIndex();
 404+ }
 405+ }
 406+ }
 407+
 408+ /**
 409+ * For _any_ name (among all namespaces), return
 410+ * the index of the namespace to which it belongs.
 411+ *
 412+ * @param string Name to search for
 413+ * @return int Index of the namespace associated
 414+ * with this name (or NULL)
 415+ *
 416+ * call refreshReverseIndex() first if there's any doubt whether
 417+ * the reverse index is up-to-date (though for performance
 418+ * reasons, don't do it if it isn't necessary.
 419+ *
 420+ * @static
 421+ */
 422+ function getIndexForName ( $name ) {
 423+ $index = @$this->reverseindex[strtolower($name)];
 424+ return isset($index) ? $index : NULL;
 425+ }
 426+
 427+ /**
 428+ * Return the default name for any namespace name
 429+ * given as a parameter, even if it is the default
 430+ * name already. Searches all namespaces.
 431+ *
 432+ * @param string Any namespace name
 433+ * @return string The name (may be identical)
 434+ * @static
 435+ */
 436+ function getDefaultNameForName ( $name ) {
 437+ $index=$this->getIndexForName($name);
 438+ if(!is_null($index)) {
 439+ return $this->nsarray[$index]->getDefaultName();
 440+ } else {
 441+ return null;
 442+ }
 443+ }
 444+
 445+ /**
 446+ * Return an array of the default names of all
 447+ * namespaces. Resets array pointer of $this->nsarray.
 448+ * @param $includeHidden Should hidden namespaces
 449+ * be part of the array?
 450+ * @return array
 451+ * @static
 452+ */
 453+ function getDefaultNamespaces($includeHidden=false) {
 454+ $dns=array();
 455+ foreach($this->nsarray as $ns) {
 456+ if(!$ns->isHidden() || $includeHidden) {
 457+ $dn=$ns->getDefaultName();
 458+ if(!is_null($dn)) {
 459+ $dns[$ns->getIndex()]=$dn;
 460+ } else {
 461+ $dns[$ns->getIndex()]='';
 462+ }
 463+ }
 464+ }
 465+ return $dns;
 466+ }
 467+
 468+ function getAllNamespaceArray() {
 469+ $allns=array();
 470+ foreach($this->nsarray as $ns) {
 471+ if(!$ns->isHidden() || $includeHidden) {
 472+ $allns[$ns->getIndex()]=$ns->getNames();
 473+ }
 474+ }
 475+ return $allns;
 476+ }
 477+
 478+ /**
 479+ * A convenience function that returns the same thing as
 480+ * getDefaultNamespaces() except with the array values changed to ' '
 481+ * where it found '_', useful for producing output to be displayed
 482+ * e.g. in <select> forms.
 483+ *
 484+ * @static
 485+ * @param $includeHidden
 486+ * @return array
 487+ */
 488+ function &getFormattedDefaultNamespaces($includeHidden=false) {
 489+ $ns = $this->getDefaultNamespaces($includeHidden);
 490+ foreach($ns as $k => $v) {
 491+ $ns[$k] = strtr($v, '_', ' ');
 492+ }
 493+ return $ns;
 494+ }
 495+
 496+ /**
 497+ * Load or reload namespace definitions from the database
 498+ * into a global array.
 499+ *
 500+ * @param $purgeCache If definitions exist in memory, should
 501+ * they be reloaded anyway?
 502+ *
 503+ * @static
 504+ */
 505+ function load($purgeCache=false) {
 506+
 507+ global $wgMemc, $wgDBname;
 508+ $key="$wgDBname:namespaces:list";
 509+ if(!$purgeCache) {
 510+ $fromMemory = $wgMemc->get($key);
 511+ if(is_array($fromMemory)) {
 512+ # Cached definitions found
 513+ $this->nsarray=$fromMemory;
 514+ # TODO: cache reverse index too
 515+ $this->refreshReverseIndex();
 516+ return true;
 517+ }
 518+ }
 519+ $this->nsarray = array();
 520+ $dbr =& wfGetDB( DB_SLAVE );
 521+ $res = $dbr->select( 'namespace',
 522+ array('ns_id','ns_search_default','ns_subpages', 'ns_parent', 'ns_target', 'ns_system', 'ns_hidden', 'ns_count', 'ns_class'),
 523+ array(),
 524+ 'Setup',
 525+ array('ORDER BY'=>'ns_id ASC')
 526+ );
 527+ while( $row = $dbr->fetchObject( $res ) ){
 528+ # See Namespace.php for documentation on all namespace
 529+ # properties which are accessed below.
 530+ $id=$row->ns_id;
 531+ $this->nsarray[$id]=new Namespace();
 532+
 533+ # Cannot currently be changed through the UI - is
 534+ # there a need for it to be changeable?
 535+ $this->nsarray[$id]->setMovable(
 536+ $id < NS_MAIN || $id==NS_IMAGE ||
 537+ $id==NS_CATEGORY ? false : true );
 538+ $this->nsarray[$id]->setIndex($id);
 539+ $this->nsarray[$id]->setSystemType($row->ns_system);
 540+ $this->nsarray[$id]->setSearchedByDefault($row->ns_search_default);
 541+ $this->nsarray[$id]->setSubpages($row->ns_subpages);
 542+ $this->nsarray[$id]->setHidden($row->ns_hidden);
 543+ $this->nsarray[$id]->setTarget($row->ns_target);
 544+ $this->nsarray[$id]->setHandlerClass($row->ns_class);
 545+ $this->nsarray[$id]->setCountable($row->ns_count);
 546+ $this->nsarray[$id]->setParentIndex($row->ns_parent);
 547+ $res2 = $dbr->select( 'namespace_names', array('ns_name','ns_default,ns_canonical'),
 548+ array('ns_id = '. $row->ns_id),
 549+ 'Setup', array('order by'=>'ns_default desc,ns_canonical desc,ns_id asc'));
 550+
 551+ # Add the list of valid names
 552+ while($row2 = $dbr->fetchObject($res2) ) {
 553+ $nsi=$this->nsarray[$id]->addName($row2->ns_name);
 554+ if($row2->ns_default) {
 555+ $this->nsarray[$id]->setDefaultNameIndex($nsi);
 556+ }
 557+ if($row2->ns_canonical) {
 558+ $this->nsarray[$id]->setCanonicalNameIndex($nsi);
 559+ }
 560+ }
 561+ }
 562+ $dbr->freeResult( $res );
 563+ $wgMemc->set($key,$this->nsarray);
 564+ $this->refreshReverseIndex();
 565+ }
 566+
 567+ /**
 568+ * Convert a "pseudonamespace" (just prefixed titles) into a real
 569+ * one.
 570+ *
 571+ * @param string $prefix - The pseudonamespace prefix string
 572+ * @param Namespace $target - the target namespace object
 573+ * @param Namespace $source - the source namespace object (should
 574+ * usually be $this->nsarray[NS_MAIN] or ..[NS_TALK]). This is the
 575+ * one we expect the prefixed titles to be stored in.
 576+ * @param boolean $merge - Is it acceptable to merge into a namespace
 577+ * which does already contain pages? This is potentially irreversible!
 578+ *
 579+ * Why pass around Namespace objects? This saves us some validation,
 580+ * since the indexes can be assumed to exist.
 581+ *
 582+ * @static
 583+ */
 584+ function convertPseudonamespace($prefix,$target,$source,$merge=false) {
 585+ $dbm =& wfGetDB(DB_MASTER);
 586+ $dbs =& wfGetDB(DB_SLAVE);
 587+ $fname="Namespace::convertPseudonamespace";
 588+ $targetcount=$target->countPages();
 589+ if(!$merge && $targetcount>0) {
 590+ return array(NS_RESULT=>NS_NON_EMPTY);
 591+ }
 592+ $table = $dbs->tableName( 'page' );
 593+ $eprefix = $dbs->strencode( $prefix );
 594+ $likeprefix = str_replace( '_', '\\_', $eprefix);
 595+ $targetid=$target->getIndex();
 596+ $sourceid=$source->getIndex();
 597+
 598+ $sql = "SELECT page_id AS id,
 599+ page_title AS oldtitle,
 600+ TRIM(LEADING '$eprefix:' FROM page_title) AS title
 601+ FROM {$table}
 602+ WHERE page_namespace=$sourceid
 603+ AND page_title LIKE '$likeprefix:%'";
 604+
 605+ $result = $dbs->query( $sql, $fname );
 606+ $set = array();
 607+ while( $row = $dbs->fetchObject( $result ) ) {
 608+ $set[] = $row;
 609+ }
 610+ $dbs->freeResult( $result );
 611+
 612+ if(!count($set)) {
 613+ return array(NS_RESULT=>NS_PSEUDO_NOT_FOUND);
 614+ } else {
 615+ # Check duplicates
 616+ if($targetcount) {
 617+ $dupeTitles=array();
 618+ foreach($set as $row) {
 619+ $pageExists=$dbs->selectField(
 620+ 'page',
 621+ 'count(*)',
 622+ array('page_title'=>$row->title,
 623+ 'page_namespace'=>$targetid)
 624+ );
 625+ if($pageExists) {
 626+ $dupeTitles[]=$row->title;
 627+ }
 628+ }
 629+ if(count($dupeTitles)) {
 630+ return(array(
 631+ NS_RESULT => NS_DUPLICATE_TITLES,
 632+ NS_DUPLICATE_TITLE_LIST => $dupeTitles));
 633+
 634+ }
 635+ }
 636+ foreach($set as $row) {
 637+ $dbm->update( $table,
 638+ array(
 639+ "page_namespace" => $targetid,
 640+ "page_title" => $row->title,
 641+ ),
 642+ array(
 643+ "page_namespace" => $sourceid,
 644+ "page_title" => $row->oldtitle,
 645+ ),
 646+ $fname );
 647+ }
 648+ }
 649+ return array(NS_RESULT=>NS_PSEUDO_CONVERTED);
 650+
 651+ }
 652+
 653+ function getNamespaceObjectByIndex( $index ) {
 654+ return $this->nsarray[$index];
 655+ }
 656+
 657+ function hasIndex( $index ) {
 658+ return !empty($this->nsarray[$index]);
 659+ }
 660+
 661+ function getNamespaceObjectByName( $name ) {
 662+ $index=$this->getIndexForName($name);
 663+ return $this->nsarray[$index];
 664+ }
 665+
 666+ function getAllNamespaceObjects( ) {
 667+ return $this->nsarray;
 668+ }
 669+}
 670+
 671+
 672+?>
Property changes on: branches/wikidata/includes/NamespaceStore.php
___________________________________________________________________
Added: svn:eol-style
1673 + native
Index: branches/wikidata/includes/AutoLoader.php
@@ -116,6 +116,7 @@
117117 'MessageCache' => 'includes/MessageCache.php',
118118 'MimeMagic' => 'includes/MimeMagic.php',
119119 'Namespace' => 'includes/Namespace.php',
 120+ 'NamespaceStore' => 'includes/NamespaceStore.php',
120121 'FakeMemCachedClient' => 'includes/ObjectCache.php',
121122 'OutputPage' => 'includes/OutputPage.php',
122123 'PageHistory' => 'includes/PageHistory.php',
Index: branches/wikidata/includes/Title.php
@@ -648,8 +648,13 @@
649649 * @return string
650650 */
651651 function getTalkNsText() {
652 - global $wgContLang;
653 - return( $wgContLang->getNsText( Namespace::getTalk( $this->mNamespace ) ) );
 652+ $ns = Namespace::getTalk( $this->getNamespace() );
 653+ if(is_null($ns)) {
 654+ return null;
 655+ }
 656+ else {
 657+ return Title::makeTitle( $ns, $this->getDBkey() );
 658+ }
654659 }
655660
656661 /**
Index: branches/wikidata/includes/Namespace.php
@@ -1,120 +1,594 @@
22 <?php
33 /**
4 - * Provide things related to namespaces
 4+ * Class for creating namespace objects
 5+ * and static namespace-related functions.
 6+ *
 7+ * Definitions:
 8+ *
 9+ * Namespace:
 10+ * A prefix of the form "Abc:" represented on the database level
 11+ * with an integer number. Using namespaces, pages with the same title
 12+ * can exist in different contexts; for example, a page
 13+ * "User:Stephen King" could coexist with "Stephen King". (No prefix
 14+ * refers to the "article namespace", or to the target namespace; see
 15+ * below.
 16+ *
 17+ * Default name, synonyms:
 18+ * Any namespace can have an arbitrary number of valid names. This is
 19+ * to ensure that, for example, "Image:", "File:", "Video:" etc. can
 20+ * all be used to access uploaded files. The default name is the name
 21+ * which all these valid names ''redirect to'', that is, if you access
 22+ * index.php?title=Image:Bear.jpg, it will redirect you to
 23+ * index.php?Title=File:Bear.jpg, because "File:" is the default name
 24+ * for this namespace. Any name which is not the default name will be
 25+ * referred to herein as a synyonm.
 26+ *
 27+ * Canonical namespace name:
 28+ * Due to the fact that namespace names are translated into many
 29+ * languages, and customized to many wikis, it is desirable to have
 30+ * a reliable way by which a namespace with a particular ''meaning''
 31+ * can be accessed on any wiki installation. For example, you may
 32+ * want to access a user page on the Serbian Wikipedia, but you don't
 33+ * know the equivalent of "User:" in Serbian. During installation,
 34+ * some namespace names are flagged as canonical. These cannot
 35+ * be changed using the namespace manager, and can be expected
 36+ * to work on all wikis. A canonical namespace name does not have
 37+ * to be the default name, e.g., "User:" would still redirect to
 38+ * the Serbian equivalent.
 39+ *
 40+ * Namespace target:
 41+ * Depending on the nature of your project, it may be desirable
 42+ * that all [[unprefixed links]] within a namespace point to a
 43+ * particular destination (another namespace or InterWiki). An
 44+ * example is Wikibooks, where namespaces are used to separate
 45+ * different types of books, and you would like all links within
 46+ * a book to point to other chapters in the book unless otherwise
 47+ * specified. Another example is Wikinews, where links from the
 48+ * main namespace typically point to Wikipedia.
 49+ *
 50+ * Quite simply put, if this target is set for a namespace, all
 51+ * links without a valid namespace or InterWiki prefix in pages
 52+ * in that namespace are treated as if they were written:
 53+ * [[LINK TARGET:Actual title|Actual title]].
 54+ *
 55+ * How to modify a namespace and its properties:
 56+ * Do NOT alter the $wgNamespaces object. Instead, create a clone()
 57+ * of the object and change its properties. To delete a name,
 58+ * set it to null (not ''). Call its save() method. It will be
 59+ * compared to the matching object in $wgNamespaces and modified
 60+ * if posible.
 61+ *
 62+ * How to create a new namespace:
 63+ * Create a new namespace object with the desired properties. Set
 64+ * the index to NULL. Call its save() method.
 65+ *
566 */
667
7 -/**
8 - * Definitions of the NS_ constants are in Defines.php
9 - * @private
10 - */
11 -$wgCanonicalNamespaceNames = array(
12 - NS_MEDIA => 'Media',
13 - NS_SPECIAL => 'Special',
14 - NS_TALK => 'Talk',
15 - NS_USER => 'User',
16 - NS_USER_TALK => 'User_talk',
17 - NS_PROJECT => 'Project',
18 - NS_PROJECT_TALK => 'Project_talk',
19 - NS_IMAGE => 'Image',
20 - NS_IMAGE_TALK => 'Image_talk',
21 - NS_MEDIAWIKI => 'MediaWiki',
22 - NS_MEDIAWIKI_TALK => 'MediaWiki_talk',
23 - NS_TEMPLATE => 'Template',
24 - NS_TEMPLATE_TALK => 'Template_talk',
25 - NS_HELP => 'Help',
26 - NS_HELP_TALK => 'Help_talk',
27 - NS_CATEGORY => 'Category',
28 - NS_CATEGORY_TALK => 'Category_talk',
29 -);
3068
31 -if( is_array( $wgExtraNamespaces ) ) {
32 - $wgCanonicalNamespaceNames = $wgCanonicalNamespaceNames + $wgExtraNamespaces;
33 -}
3469
 70+# Namespace name operations
 71+# used by save() function
 72+define('NS_NAME_MODIFY',1);
 73+define('NS_NAME_DELETE',2);
 74+define('NS_NAME_ADD',3);
 75+
3576 /**
36 - * This is a utility class with only static functions
37 - * for dealing with namespaces that encodes all the
38 - * "magic" behaviors of them based on index. The textual
39 - * names of the namespaces are handled by Language.php.
 77+ * This class defines the namespace objects which are stored in
 78+ * $wgNamespaces.
4079 *
41 - * These are synonyms for the names given in the language file
42 - * Users and translators should not change them
43 - *
4480 */
4581 class Namespace {
4682
 83+ # Fundamentals
 84+ var
 85+ $index, # Database-level index of this namespace
 86+ $systemType; # If non-empty, string constant that defines
 87+ # a system namespace.
 88+
 89+ # Options
 90+ var
 91+ $isMovable, # Can pages in this namespace be moved?
 92+ $isCountable, # Should pages in this namespace count as content (stats)?
 93+ $parentIndex, # If this is a talk page, what is its mother
 94+ # namespace? Otherwise NULL.
 95+ $allowsSubpages, # Are subpages of the form [[Namespace:Foo/Bar]]
 96+ # valid?
 97+ $isSearchedByDefault, # Are pages in this namespace searched by default?
 98+ $isHidden, # Should this namespace be hidden from the UI?
 99+ $handlerClass, # Name of an external class to use for handling content
 100+ $target; # Treat unprefixed links as prefixed with "$target:"?
 101+
 102+ # Associated names
 103+ var
 104+ $names = array(), # Contains all the namespace names
 105+ $defaultNameIndex, # Index of the name all other names redirect to?
 106+ $canonicalNameIndex; # Index of the name that's valid everywhere
 107+
 108+
 109+ /**
 110+ * Constructor with reasonable defaults.
 111+ */
 112+ function Namespace() {
 113+
 114+ $this->setIndex(NULL);
 115+ $this->setMovable();
 116+ $this->setParentIndex(NULL);
 117+ $this->setSubpages(false);
 118+ $this->setSearchedByDefault(false);
 119+ $this->setTarget(NULL);
 120+ $this->setHidden(false);
 121+ }
 122+
47123 /**
48 - * Check if the given namespace might be moved
 124+ * @return index to the correct $wgNamespaces object
 125+ * or database record for this namespace.
 126+ */
 127+ function getIndex() {
 128+ return $this->index;
 129+ }
 130+
 131+ /**
 132+ * @param $index New index for this namespace.
 133+ * Generally only used during creation.
 134+ */
 135+ function setIndex($index) {
 136+ $this->index=$index;
 137+ }
 138+
 139+ /**
 140+ * @return String like NS_MAIN for identifying
 141+ * system namespaces (see Defines.php).
 142+ */
 143+ function getSystemType() {
 144+ return $this->systemType;
 145+ }
 146+
 147+ /**
 148+ * Set the system type for this namespace.
 149+ * @param string Constant name - needs to exist
 150+ * in Defines.php.
 151+ * @return bool depending on success
 152+ *
 153+ */
 154+ function setSystemType($type) {
 155+ $typeString=(string)$type;
 156+ if(defined($typeString)) {
 157+ $this->systemType=$typeString;
 158+ return true;
 159+ } else {
 160+ return false;
 161+ }
 162+ }
 163+
 164+ /**
 165+ * Is this a system namsepace?
49166 * @return bool
50167 */
51 - static function isMovable( $index ) {
52 - return !( $index < NS_MAIN || $index == NS_IMAGE || $index == NS_CATEGORY );
 168+ function isSystemNamespace() {
 169+ $sys=$this->getSystemType();
 170+ return !empty($sys);
53171 }
 172+
 173+ /**
 174+ * Check if pages in this namespace can be moved.
 175+ * Special pages, images and categories cannot be moved
 176+ * @return bool
 177+ */
 178+ function isMovable() {
 179+ return $this->isMovable;
 180+ }
54181
55182 /**
 183+ * Can pages in this namespace be moved?
 184+ * @param bool
 185+ */
 186+ function setMovable($movable=true) {
 187+ $this->isMovable=(bool)$movable;
 188+ }
 189+
 190+ /**
 191+ * Check if pages in this namespaces should be counted in the site statistics
 192+ * @return bool
 193+ */
 194+ function isCountable() {
 195+ return $this->isCountable;
 196+ }
 197+
 198+ /**
 199+ * Set if pages in this namespace should be counted in the site statistics
 200+ * @param bool
 201+ */
 202+ function setCountable($countable=true) {
 203+ $this->isCountable=(bool)$countable;
 204+ }
 205+
 206+ /**
 207+ * Are pages from this namespace hidden in lists?
 208+ * @return bool
 209+ */
 210+ function isHidden() {
 211+ return $this->isHidden;
 212+ }
 213+
 214+ /**
 215+ * Should pages from this namespace be hidden in lists?
 216+ * @param bool
 217+ */
 218+ function setHidden($hidden=true) {
 219+ $this->isHidden=(bool)$hidden;
 220+ }
 221+
 222+ /**
 223+ * @return int Index of the parent namespace to a
 224+ * child namespace (talk or otherwise), NULL if none
 225+ */
 226+ function getParentIndex() {
 227+ return $this->parentIndex;
 228+ }
 229+
 230+ /**
 231+ * @return int Same as getParentIndex(), but returns this
 232+ * namespace's index if no parent namespace exists. Doubles as
 233+ * a static function which returns the same given the namespace
 234+ * index.
 235+ */
 236+ function getSubject($index = null) {
 237+ if( is_null( $index ) ) {
 238+ $ns = $this;
 239+ }
 240+ else {
 241+ $nsstore = wfGetNamespaceStore();
 242+ $ns = $nsstore->getNamespaceObjectByIndex($index);
 243+ }
 244+
 245+ if($ns->isTalk()) {
 246+ return $ns->getParentIndex();
 247+ } else {
 248+ return $ns->getIndex();
 249+ }
 250+ }
 251+
 252+
 253+ /**
 254+ * Set parent namespace
 255+ * @param int
 256+ */
 257+ function setParentIndex($index) {
 258+ $this->parentIndex=$index;
 259+ }
 260+
 261+ /**
 262+ * Does this namespace have a parent namespace?
 263+ * @return bool
 264+ */
 265+ function hasParent() {
 266+ return ($this->getParentIndex()!=NULL);
 267+ }
 268+
 269+ /**
 270+ * Synonym for hasParent(), but might be logically different in
 271+ * the near future, if parent/child relationships go beyond talk
 272+ * pages. Doubles as a static function which returns the same
 273+ * given the namespace index.
 274+ * @return bool
 275+ */
 276+ function isTalk( $index = null ) {
 277+ if( is_null( $index ) ) {
 278+ return $this->hasParent();
 279+ }
 280+ else {
 281+ $nsstore = wfGetNamespaceStore();
 282+ $ns = $nsstore->getNamespaceObjectByIndex($index);
 283+ return $ns->hasParent();
 284+ }
 285+ }
 286+
 287+ /**
56288 * Check if the given namespace is not a talk page
57289 * @return bool
58290 */
59 - static function isMain( $index ) {
60 - return ! Namespace::isTalk( $index );
 291+ function isMain( $index = null) {
 292+ if( is_null( $index ) ) {
 293+ return !$this->isTalk();
 294+ }
 295+ else {
 296+ $nsstore = wfGetNamespaceStore();
 297+ $ns = $nsstore->getNamespaceObjectByIndex($index);
 298+ return !$ns->isTalk();
 299+ }
61300 }
62301
 302+
63303 /**
64 - * Check if the give namespace is a talk page
 304+ * Is this a "special" namespace (Media:, Special:)?
 305+ * Special namespaces cannot contain any pages.
65306 * @return bool
 307+ */
 308+ function isSpecial() {
 309+ return($this->getIndex()<NS_MAIN);
 310+ }
 311+
 312+ /**
 313+ * Is content in this namespace searched by default?
 314+ * @return bool
66315 */
67 - static function isTalk( $index ) {
68 - return ($index > NS_MAIN) // Special namespaces are negative
69 - && ($index % 2); // Talk namespaces are odd-numbered
 316+ function isSearchedByDefault() {
 317+ return $this->isSearchedByDefault;
70318 }
71319
72320 /**
73 - * Get the talk namespace corresponding to the given index
 321+ * Should this namespace be searched by default?
 322+ * @param bool
74323 */
75 - static function getTalk( $index ) {
76 - if ( Namespace::isTalk( $index ) ) {
 324+ function setSearchedByDefault($search=true) {
 325+ $this->isSearchedByDefault=(bool)$search;
 326+ }
 327+
 328+ /**
 329+ Get the index of the discussion namespace associated
 330+ with a namespace. If this _is_ a discussion namespace,
 331+ return its index.
 332+ Doubles as a static function which returns the same
 333+ given the namespace index.
 334+
 335+ @return int
 336+
 337+ TODO: support multiple discussion namespaces,
 338+ so that things like a Review: namespace
 339+ become possible in parallel to normal talk
 340+ pages.
 341+ */
 342+ function getTalk($index = null) {
 343+ if( is_null( $index ) ) {
 344+ $ns = $this;
 345+ }
 346+ else {
 347+ $nsstore = wfGetNamespaceStore();
 348+ $ns = $nsstore->getNamespaceObjectByIndex($index);
 349+ }
 350+
 351+ /* This behavior is expected by Title.php! */
 352+ if($ns->isTalk()) return $ns->getIndex();
 353+
 354+ $nsstore = wfGetNamespaceStore();
 355+ return $nsstore->getTalk($ns);
 356+ }
 357+
 358+
 359+ /**
 360+ * Return the default prefix for unprefixed links
 361+ * from this namespace.
 362+ * @return string
 363+ */
 364+ function getTarget() {
 365+ return $this->target;
 366+ }
 367+
 368+ /**
 369+ * Set the default prefix for unprefixed links, e.g.
 370+ * "User:" (local namespace prefix) or "MeatBall:"
 371+ * (InterWiki prefix).
 372+ *
 373+ * @param string
 374+ */
 375+ function setTarget($target) {
 376+ $this->target=(string)$target;
 377+ }
 378+
 379+ /**
 380+ * Does this namespace allow [[/subpages]]?
 381+ * @return bool
 382+ */
 383+ function allowsSubpages() {
 384+ return $this->allowsSubpages;
 385+
 386+ }
 387+
 388+ /**
 389+ * Should this namespace allow [[/subpages]]?
 390+ * @param bool
 391+ */
 392+ function setSubpages($subpages=true) {
 393+ $this->allowsSubpages=(bool)$subpages;
 394+ }
 395+
 396+ /**
 397+ * Return the default name for this namespace, if any.
 398+ * The default name is the one all others redirect to.
 399+ *
 400+ * @return string
 401+ */
 402+ function getDefaultName() {
 403+ if(isset($this->defaultNameIndex) && array_key_exists($this->defaultNameIndex,$this->names)) {
 404+ return $this->names[$this->defaultNameIndex];
 405+ } else {
 406+ return null;
 407+ }
 408+ }
 409+
 410+ /**
 411+ Used when a default name is deleted, to assign a new one
 412+ @return int - index to the first non-empty name of this namespace
 413+ null if there are no non-empty names.
 414+ */
 415+ function getNewDefaultNameIndex() {
 416+ foreach($this->names as $nsi=>$name) {
 417+ if(!empty($name)) {
 418+ return $nsi;
 419+ }
 420+ }
 421+ return null;
 422+ }
 423+
 424+ /**
 425+ * Among the names of this namespace, which one should
 426+ * be set as the default name?
 427+ * @param int Key to the names array
 428+ */
 429+ function setDefaultNameIndex($index) {
 430+ $this->defaultNameIndex=$index;
 431+ }
 432+
 433+ /**
 434+ * Among the names of this namespace, which one
 435+ * should be "canonical" (i.e. not editable, and
 436+ * assumed to exist under this name in other
 437+ * wikis)?
 438+ * @param int Key to the names array
 439+ */
 440+ function setCanonicalNameIndex($index) {
 441+ $this->canonicalNameIndex=$index;
 442+ }
 443+
 444+ /**
 445+ * Add a name to the list of names for this
 446+ * namespace.
 447+ * @return index of the newly added name,
 448+ * or NULL if hte name is not valid.
 449+ */
 450+ function addName($name) {
 451+ $index=count($this->names);
 452+ if($this->isValidName($name)) {
 453+ $name=strtr($name, ' ','_');
 454+ $this->names[$index]=$name;
77455 return $index;
78456 } else {
79 - # FIXME
80 - return $index + 1;
 457+ return NULL;
81458 }
82459 }
83460
84 - static function getSubject( $index ) {
85 - if ( Namespace::isTalk( $index ) ) {
86 - return $index - 1;
 461+ /**
 462+ * Return the key in the name list for a given
 463+ * name.
 464+ * @return int Matching key or NULL
 465+ */
 466+ function getNameIndexForName($findname) {
 467+ foreach($this->names as $nsi=>$name) {
 468+ if($name==$findname) {
 469+ return $nsi;
 470+ }
 471+ }
 472+ return null;
 473+ }
 474+
 475+ /**
 476+ * Change a namespace name.
 477+ * @param $oldname The old name
 478+ * @param $newname The new name
 479+ * @param $checkvalid Does the new name have to be
 480+ * valid? (is checked by save() in any case)
 481+ */
 482+ function setName($oldname,$newname,$checkvalid=true) {
 483+ if($checkvalid && !$this->isValidName($newname)) {
 484+ return NULL;
 485+ }
 486+ $newname=strtr($newname, ' ','_');
 487+ $nsi=$this->getNameIndexForName($oldname);
 488+ if(!is_null($nsi)) {
 489+ $this->names[$nsi]=$newname;
 490+ return true;
87491 } else {
88 - return $index;
 492+ return false;
89493 }
90494 }
 495+
 496+ /**
 497+ * Is this a valid namespace name? Valid characters
 498+ * are defined in the NS_CHAR constant.
 499+ * @return bool
 500+ */
 501+ function isValidName($name) {
 502+ # Consist only of (at least one) valid char(s)
 503+ if(preg_match("/^".NS_CHAR."+$/",$name)) {
 504+ return true;
 505+ } else {
 506+ return false;
 507+ }
 508+ }
91509
92510 /**
93 - * Returns the canonical (English Wikipedia) name for a given index
 511+ * How many pages does this namespace contain?
 512+ * @return The number of pages
 513+ */
 514+ function countPages() {
 515+ $dbs =& wfGetDB(DB_SLAVE);
 516+ return $dbs->selectField(
 517+ 'page',
 518+ 'count(*)',
 519+ array('page_namespace'=>$this->getIndex())
 520+ );
 521+ }
 522+
 523+ /**
 524+ * Get the default name with spaces instead of
 525+ * underscores.
 526+ * @return string
94527 */
95 - static function getCanonicalName( $index ) {
96 - global $wgCanonicalNamespaceNames;
97 - return $wgCanonicalNamespaceNames[$index];
 528+ function getFormattedDefaultName() {
 529+ $ns=$this->getDefaultName();
 530+ return strtr($ns, '_',' ');
98531 }
 532+ /**
 533+ * @return the key in the names array for the default
 534+ * name of this namespace
 535+ */
 536+ function getDefaultNameIndex() {
 537+ return $this->defaultNameIndex;
 538+ }
99539
100540 /**
101 - * Returns the index for a given canonical name, or NULL
102 - * The input *must* be converted to lower case first
 541+ * @return the key in the names array for the
 542+ * canonical name of this namespace
103543 */
104 - static function getCanonicalIndex( $name ) {
105 - global $wgCanonicalNamespaceNames;
106 - static $xNamespaces = false;
107 - if ( $xNamespaces === false ) {
108 - $xNamespaces = array();
109 - foreach ( $wgCanonicalNamespaceNames as $i => $text ) {
110 - $xNamespaces[strtolower($text)] = $i;
111 - }
 544+ function getCanonicalNameIndex() {
 545+ return $this->canonicalNameIndex;
 546+ }
 547+
 548+ /**
 549+ * @return The canonical name associated with this namespace, or
 550+ * NULL. Doubles as a static function which returns the same
 551+ * given the namespace index.
 552+ */
 553+ function getCanonicalName( $index = null ) {
 554+ if( is_null( $index ) ) {
 555+ $ns = $this;
112556 }
113 - if ( array_key_exists( $name, $xNamespaces ) ) {
114 - return $xNamespaces[$name];
 557+ else {
 558+ $nsstore = wfGetNamespaceStore();
 559+ $ns = $nsstore->getNamespaceObjectByIndex($index);
 560+ }
 561+ if(!is_null($ns->getCanonicalNameIndex())) {
 562+ return $ns->names[$ns->getCanonicalNameIndex()];
115563 } else {
116 - return NULL;
 564+ return null;
117565 }
118566 }
 567+
 568+ /**
 569+ * An external handler class can be configured for a namespace.
 570+ * It is expected in extensions/ClassName/ClassName.php by default
 571+ * and should have a view(), edit() and delete() function.
 572+ *
 573+ * @param $classname
 574+ */
 575+ function setHandlerClass($classname) {
 576+ $this->handlerClass=$classname;
 577+ }
 578+
 579+ /**
 580+ * @return name of the handler class (string)
 581+ */
 582+ function getHandlerClass() {
 583+ return $this->handlerClass;
 584+ }
 585+ /**
 586+ * Returns the index for a given canonical name, or NULL
 587+ * The input *must* be converted to lower case first
 588+ */
 589+ static function getCanonicalIndex( $name ) {
 590+ $nsstore = wfGetNamespaceStore();
 591+ return $nsstore->getIndexForName( $name );
 592+ }
119593
120594 /**
121595 * Can this namespace ever have a talk namespace?
@@ -123,19 +597,49 @@
124598 static function canTalk( $index ) {
125599 return( $index >= NS_MAIN );
126600 }
127 -
 601+
 602+
128603 /**
129 - * Does this namespace contain content, for the purposes
130 - * of calculating statistics, etc?
131 - *
132 - * @param $index Index to check
133 - * @return bool
 604+ * @param int Key to the names array of the name
 605+ * which should be removed.
134606 */
135 - public static function isContent( $index ) {
136 - global $wgContentNamespaces;
137 - return $index == NS_MAIN || in_array( $index, $wgContentNamespaces );
138 - }
139 -
 607+ function removeNameByIndex($index) {
 608+ if(array_key_exists($index,$this->names)) {
 609+ unset($this->names[$index]);
 610+ return true;
 611+ } else {
 612+ return false;
 613+ }
 614+ }
 615+
 616+ /**
 617+ * Kill them all! Well, all the ones in this namespace
 618+ * object. And only if we save().
 619+ */
 620+ function removeAllNames() {
 621+ $this->names=array();
 622+ return true;
 623+ }
 624+
 625+ function save($overrideInterwiki=false,
 626+ $testSave=false) {
 627+ $nsstore = wfGetNamespaceStore();
 628+ return $nsstore->saveNamespace($this,$overrideInterwiki,$testSave);
 629+ }
 630+
 631+ /**
 632+ * A simple shortcut to save() with the right parameters
 633+ * to run in test mode. See save() documentation.
 634+ */
 635+ function testSave($overrideInterwiki=false) {
 636+ return $this->save($overrideInterwiki,true);
 637+ }
 638+
 639+ function deleteNamespace($deleteSystem=false) {
 640+ $nsstore = wfGetNamespaceStore();
 641+ return $nsstore->deleteNamespace($this,$deleteSystem);
 642+ }
 643+
140644 }
141645
142646 ?>
Index: branches/wikidata/includes/SkinTemplate.php
@@ -653,12 +653,14 @@
654654 !$this->mTitle->isTalkPage() && !$prevent_active_tabs,
655655 '', true);
656656
657 - $content_actions['talk'] = $this->tabAction(
658 - $talkpage,
659 - 'talk',
660 - $this->mTitle->isTalkPage() && !$prevent_active_tabs,
661 - '',
662 - true);
 657+ if(!is_null($talkpage)) {
 658+ $content_actions['talk'] = $this->tabAction(
 659+ $talkpage,
 660+ 'talk',
 661+ $this->mTitle->isTalkPage() && !$prevent_active_tabs,
 662+ '',
 663+ true);
 664+ }
663665
664666 wfProfileIn( "$fname-edit" );
665667 if ( $this->mTitle->quickUserCan( 'edit' ) && ( $this->mTitle->exists() || $this->mTitle->quickUserCan( 'create' ) ) ) {
Index: branches/wikidata/includes/DefaultSettings.php
@@ -1004,7 +1004,10 @@
10051005
10061006 // Permission to change users' group assignments
10071007 $wgGroupPermissions['bureaucrat']['userrights'] = true;
 1008+// Permission to change namespace definitions
 1009+$wgGroupPermissions['bureaucrat']['namespaces'] = true;
10081010
 1011+
10091012 // Experimental permissions, not ready for production use
10101013 //$wgGroupPermissions['sysop']['deleterevision'] = true;
10111014 //$wgGroupPermissions['bureaucrat']['hiderevision'] = true;
Index: branches/wikidata/includes/SpecialPage.php
@@ -142,6 +142,9 @@
143143 'Mytalk' => array( 'SpecialMytalk' ),
144144 'Mycontributions' => array( 'SpecialMycontributions' ),
145145 'Listadmins' => array( 'SpecialRedirectToSpecial', 'Listadmins', 'Listusers', 'sysop' ),
 146+
 147+ 'Namespaces' => array( 'SpecialPage', 'Namespaces', 'namespaces'),
 148+
146149 );
147150
148151 static public $mAliases;
Index: branches/wikidata/includes/SpecialNamespaces.php
@@ -0,0 +1,883 @@
 2+<?php
 3+/**
 4+ *
 5+ * @package MediaWiki
 6+ * @subpackage SpecialPage
 7+ */
 8+
 9+/**
 10+ * Constructor
 11+ * Can display the main form or perform addition, changes,
 12+ * pseudonamespace conversion or deletions.
 13+ */
 14+function wfSpecialNamespaces() {
 15+ global $wgUser, $wgRequest;
 16+
 17+ $action = $wgRequest->getVal( 'action' );
 18+ $f = new NamespaceForm();
 19+
 20+ if ( $action == 'submit' && $wgRequest->wasPosted() &&
 21+ $wgUser->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ) ) {
 22+ if($wgRequest->getText('nsAction')=='addnamespaces') {
 23+ $f->addNamespaces();
 24+ } elseif($wgRequest->getText('nsAction')=='changenamespaces') {
 25+ $f->changeNamespaces();
 26+ } elseif($wgRequest->getText('nsAction')=='fixpseudonamespaces') {
 27+ $f->fixPseudonamespaces();
 28+ }
 29+ } elseif($action == 'delete') {
 30+ $f->deleteNamespace();
 31+ } else {
 32+ $f->showForm();
 33+ }
 34+}
 35+
 36+/**
 37+*
 38+* @package MediaWiki
 39+* @subpackage SpecialPage
 40+*/
 41+class NamespaceForm {
 42+
 43+/**
 44+*
 45+* This is the main namespace manager form which gives access to
 46+* all namespace operations.
 47+*
 48+* @param $errorHeader if this is an error page, we need at least a headline
 49+* @param $errorBody wikitext for extended error descriptions
 50+*
 51+*/
 52+function showForm( $errorHeader='', $errorBody='' ) {
 53+ global $wgOut, $wgUser, $wgTitle;
 54+
 55+ $wgOut->setPagetitle( wfMsg( 'namespaces' ) );
 56+
 57+ /* In case of an error, we generally just show what went wrong
 58+ and continue displaying the main form */
 59+ if ( '' != $errorHeader ) {
 60+ $wgOut->setSubtitle( wfMsg( 'transactionerror' ) );
 61+ $wgOut->addHTML( '<p class="error">' . htmlspecialchars($errorHeader) . '</p>');
 62+ if($errorBody) {
 63+ $wgOut->addWikiText($errorBody);
 64+ }
 65+ }
 66+
 67+ # Standard token to avoid remote form submission exploits
 68+ $token = $wgUser->editToken();
 69+ $action = $wgTitle->escapeLocalURL( 'action=submit' );
 70+ $talksuffix = wfEscapeJsString(wfMsgForContent('talkpagesuffix'));
 71+
 72+ $nsstore = wfGetNamespaceStore();
 73+
 74+ # For the namespace selection box
 75+ $name_array = $nsstore->getFormattedDefaultNamespaces(true);
 76+
 77+ $noparent = wfMsg('no_parent_namespace');
 78+ $name_array[key($name_array)-1] = $noparent;
 79+
 80+ # Sort for foreach loops
 81+ ksort($name_array);
 82+
 83+ $wgOut->addWikiText( wfMsg( 'add_namespaces_header' ) );
 84+
 85+ # Prefill talk namespace field, but only for languages
 86+ # where it's not disabled
 87+ if($talksuffix != '-') {
 88+ $talkpagejs=
 89+' onchange="if(!window.document.addnamespaces.nsTalkName.value &amp;&amp; window.document.addnamespaces.nsName.value &amp;&amp; window.document.addnamespaces.nsCreateTalk.checked) { window.document.addnamespaces.nsTalkName.value=window.document.addnamespaces.nsName.value+\''.$talksuffix.'\'; }"';
 90+ } else {
 91+ $talkpagejs='';
 92+ }
 93+
 94+ $addnshtmlform='
 95+<div id="addnsForm">
 96+<form name="addnamespaces" method="post" action="'.$action.'">
 97+<table>
 98+ <tr valign="top">
 99+ <td>'.wfMsg('add_namespace_default_name').'</td>
 100+ <td>
 101+ <input type="hidden" name="nsAction" value="addnamespaces" />
 102+ <input type="text" name="nsName" size="20"'.$talkpagejs.' />
 103+ </td>
 104+ </tr>
 105+ <tr valign="top">
 106+ <td>'.wfMsg('add_namespace_default_talk').'<br /></td>
 107+ <td><input type="text" name="nsTalkName" size="20" /></td>
 108+ </tr>
 109+ <tr>
 110+ <td colspan="2">
 111+ <label>
 112+ <input type="checkbox" name="nsCreateTalk" checked="checked" />'.wfMsg('add_namespace_talk_confirm').'
 113+ </label>
 114+ </td>
 115+ </tr>
 116+</table>
 117+<input type="hidden" name="wpEditToken" value="'.$token.'" />
 118+<input type="submit" value="'.wfMsg('add_namespace_button').'" />
 119+</form>
 120+</div>
 121+';
 122+ $wgOut->addHTML($addnshtmlform);
 123+
 124+ $wgOut->addWikiText( wfMsg( 'modify_namespaces_header' ) );
 125+
 126+ // Array of messages to be used
 127+ $nsMessages = array (
 128+ 'child_of', 'default_link_prefix', 'default_name', 'delete_name',
 129+ 'existing_names', 'hide_in_lists', 'names', 'new_names',
 130+ 'properties', 'save_changes', 'search_by_default', 'slot',
 131+ 'support_subpages', 'system',
 132+ );
 133+
 134+ // Build variables using the array. 'child_of' will do:
 135+ // $namespace_child_of = wfMsg('namespace_child_of');
 136+ foreach( $nsMessages as $nsMessage ) {
 137+ $msgName = 'namespace_' . $nsMessage ;
 138+ $$msgName = wfMsg( $msgName );
 139+ }
 140+
 141+ // Initialise the form
 142+ $htmlform = <<<END
 143+<style type="text/css">
 144+.mwNsAnnotation {
 145+ font-size: 80%;
 146+ color: #a0a0a0;
 147+}
 148+table.mwNsNames {
 149+ border-spacing: 0 2px;
 150+}
 151+table.mwNsNames tr.mwDefaultName {
 152+ background-color: #d2d5ff;
 153+}
 154+</style>
 155+
 156+<form name="changenamespaces" method="post" action="{$action}">
 157+<input type="hidden" name="nsAction" value="changenamespaces" />
 158+<input type="hidden" name="wpEditToken" value="{$token}" />
 159+END;
 160+
 161+ $nsobjects = $nsstore->getAllNamespaceObjects();
 162+ // Now we proceed each namespace
 163+ foreach ($nsobjects as $ns) {
 164+ $index = $ns->getIndex();
 165+
 166+ // Make sure the checkboxes remain checked:
 167+ $subpages = $ns->allowsSubpages() ? ' checked' : '';
 168+ $searchdefault = $ns->isSearchedByDefault() ? ' checked' :'';
 169+ $hidden = $ns->isHidden ? ' checked' : '';
 170+
 171+ $linkprefix = $ns->getTarget();
 172+ $parentslot = $ns->getParentIndex();
 173+ # maybe make HTMLnamespaceselector more flexible and use
 174+ # it instead here
 175+ if( !$ns->isSpecial() ) {
 176+ $namespaceselect=$this->getSelector($name_array,$parentslot);
 177+
 178+ // TODO : fix code below, maybe use HTMLForm ?
 179+
 180+ $namespaceselect_html = <<<END
 181+<tr valign="top">
 182+ <td colspan="2">{$namespace_child_of}<br />
 183+ <select name="ns{$index}Parent" size="1">{$namespaceselect}</select>
 184+ </td>
 185+</tr>
 186+END;
 187+ $subpages_html = $this->checkRow( 'namespace_support_subpages',
 188+ "ns{$index}Subpages", $ns->allowsSubpages() );
 189+ $searchdefault_html = $this->checkRow( 'namespace_search_by_default',
 190+ "ns{$index}Search", $ns->isSearchedByDefault() );
 191+ $hide_html = $this->checkRow( 'namespace_hide_in_lists',
 192+ "ns{$index}Hidden", $ns->isHidden() );
 193+
 194+ $target_html = <<<END
 195+<tr valign="top">
 196+ <td>{$namespace_default_link_prefix}</td>
 197+ <td align="right"><input type="text" size="10" name="ns{$index}Linkprefix" value="{$linkprefix}" /></td>
 198+</tr>
 199+END;
 200+ $target_html = $this->selectorRow( 'namespace_default_link_prefix',
 201+ "ns{$index}Linkprefix",
 202+ $nsstore->getIndexForName( $ns->getTarget() ) );
 203+ $special_html='';
 204+
 205+ } else {
 206+ // For special namespace
 207+ $namespaceselect_html = '';
 208+ $subpages_html = '';
 209+ $searchdefault_html = '';
 210+ $hide_html = '';
 211+ $target_html = '';
 212+ $special_namespace = wfMsg('special_namespace');
 213+ $special_html = '<tr valign="top"><td colspan="2"><em>'.$special_namespace.'</em></td></tr>' . "\n";
 214+ }
 215+
 216+
 217+ $systemtype = $ns->getSystemType();
 218+
 219+ if( $ns->getSystemType() ) {
 220+ // No delete link ?
 221+ $systemtype_html = <<<END
 222+<tr valign="top">
 223+ <td><b><font color="red">{$namespace_system}</font></b></td>
 224+ <td align="right"><b>{$systemtype}</b></td>
 225+</tr>
 226+END;
 227+ $deletenamespace_html = '';
 228+ } else {
 229+ // Give out a link to delete the namespace
 230+ $sk = $wgUser->getSkin();
 231+ $delete_link = $sk->makeKnownLinkObj( $wgTitle, wfMsg('delete_namespace'), 'action=delete&ns=' . $index );
 232+ $deletenamespace_html = '<tr valign="top"><td colspan="2"><b>'.$delete_link.'</b></td></tr>' . "\n";
 233+ $systemtype_html='';
 234+ }
 235+
 236+
 237+ // Yet another table of tables :p
 238+ $htmlform .= <<<END
 239+<table class="specialnamespaces">
 240+<tr valign="top"><td>
 241+ <table border="0" style="margin-right:1em;" width="300">
 242+ <tr><th colspan="2">{$namespace_properties}</th></tr>
 243+ <tr><td>{$namespace_slot}</td><td align="right">{$index}</td></tr>
 244+END;
 245+ // Also add html part generated before
 246+ $htmlform .=
 247+ $systemtype_html
 248+ . $special_html
 249+ . $subpages_html
 250+ . $searchdefault_html
 251+ . $hide_html
 252+ . $target_html
 253+ . $namespaceselect_html
 254+ . $deletenamespace_html
 255+ ;
 256+$htmlform .= <<<END
 257+ </table>
 258+</td><td>
 259+ <table class="mwNsNames">
 260+ <tr><th colspan="3">{$namespace_names}</th></tr>
 261+ <tr>
 262+ <th>{$namespace_default_name}</th>
 263+ <th align="left">{$namespace_existing_names}</th>
 264+ <th>{$namespace_delete_name}</th>
 265+ </tr>
 266+END;
 267+
 268+ foreach ( $ns->names as $nsi => $nsname ) {
 269+ $isDefault = ( $nsi === $ns->getDefaultNameIndex() );
 270+ $isCanonical = ( $nsi === $ns->getCanonicalNameIndex() );
 271+ $prettyName = str_replace( '_', ' ', $nsname );
 272+
 273+ $default = wfRadio( "ns{$index}Default", $nsi, $isDefault );
 274+ if( $isCanonical ) {
 275+ $nameinput = htmlspecialchars( $prettyName ) .
 276+ $this->annotation( wfMsg( 'canonicalname' ) );
 277+ $delete = "N/A";
 278+ } else {
 279+ $nameinput = wfInput( "ns{$index}Name{$nsi}", 20, $prettyName );
 280+ if( $isDefault ) {
 281+ $nameinput .= $this->annotation( wfMsg( 'defaultname' ) );
 282+ }
 283+ $delete = wfCheck( "ns{$index}Delete{$nsi}" );
 284+ }
 285+ $class = $isDefault ? 'mwDefaultName' : '';
 286+ $htmlform .=
 287+<<<END
 288+ <tr valign="top" class="$class">
 289+ <td align="center">{$default}</td>
 290+ <td>{$nameinput}</td>
 291+ <td align="center">{$delete}</td>
 292+ </tr>
 293+END;
 294+ }
 295+
 296+ $htmlform .= '<tr><th align="left" colspan="3">' . $namespace_new_names . '</th></tr>' ;
 297+
 298+ # 3 blank namespace fields
 299+ // FIXME cant we just count elements ?
 300+ if( !is_null( $ns->names ) ) {
 301+ end( $ns->names );
 302+ $highestName = key( $ns->names ) + 1;
 303+ } else {
 304+ $highestName = 0;
 305+ }
 306+
 307+ for( $i=$highestName; $i<$highestName+3; $i++) {
 308+ $htmlform .=
 309+<<<END
 310+ <tr valign="top">
 311+ <td align="center"><input type="radio" name="ns{$index}Default" value="{$i}" /></td>
 312+ <td><input name="ns{$index}NewName{$i}" size="20" value="" /></td>
 313+ <td align="center">&nbsp;</td>
 314+ </tr>
 315+
 316+END;
 317+ }
 318+ $htmlform .=
 319+<<<END
 320+</table>
 321+ </td></tr>
 322+</table>
 323+
 324+END;
 325+ }
 326+ $htmlform.=
 327+<<<END
 328+<input type="submit" value="{$namespace_save_changes}" />
 329+</form>
 330+<br/>
 331+END;
 332+
 333+
 334+ // Ouput the form
 335+ $wgOut->addHTML( $htmlform );
 336+
 337+ // Pseudonamespace converter
 338+ $all_name_array = $nsstore->getFormattedDefaultNamespaces(true);
 339+ $pseudons_select=$this->getSelector($all_name_array);
 340+ $wgOut->addWikiText( wfMsg( 'fix_pseudonamespaces_header' ) );
 341+ $phtmlform ='
 342+<div id="fixPseudoNsForm">
 343+<form name="fixpseudonamepaces" method="post" action="'.$action.'">
 344+<input type="hidden" name="nsAction" value="fixpseudonamespaces" />
 345+<input type="hidden" name="wpEditToken" value="'.$token.'" />
 346+<table>
 347+ <tr valign="top">
 348+ <td>'.wfMsgHtml('pseudonamespace_prefix').'</td>
 349+ <td>
 350+ <input type="text" name="nsPrefix" size="20" />
 351+ </td>
 352+ </tr>
 353+ <tr valign="top">
 354+ <td>'.wfMsgHtml('pseudonamespace_target').'<br /></td>
 355+ <td><select name="nsConvertTo" size="1">'.$pseudons_select.'</select></td>
 356+ </tr>
 357+ <tr>
 358+ <td colspan="2">
 359+ <label>
 360+ <input type="checkbox" name="nsConvertTalk" checked="checked" />'.wfMsgHtml('pseudonamespace_converttalk').'
 361+ </label>
 362+ </td>
 363+ </tr>';
 364+ if( $wgUser->isAllowed( 'merge_pseudonamespaces' ) ) {
 365+ $phtmlform.='
 366+ <tr>
 367+ <td colspan="2">
 368+ <label>
 369+ <input type="checkbox" name="nsMerge" />'.wfMsg('pseudonamespace_merge').'
 370+ </label>
 371+ </td>
 372+ </tr>';
 373+ }
 374+ $phtmlform.='
 375+</table>
 376+<input type="submit" value="'.wfMsgHtml('pseudonamespace_convert').'" />
 377+</form>
 378+</div>';
 379+ $wgOut->addHTML($phtmlform);
 380+
 381+}
 382+
 383+ /**
 384+ * Add a new namespace with a single default name,
 385+ * and optionally a talk namespace, also with a
 386+ * defaultname. Uses the request data from the form.
 387+ */
 388+ function addNamespaces() {
 389+
 390+ global $wgOut, $wgUser, $wgRequest;
 391+
 392+ $nsname = $wgRequest->getText('nsName');
 393+ $nstalkname = $wgRequest->getText('nsTalkName');
 394+ $nscreatetalk = $wgRequest->getBool('nsCreateTalk');
 395+
 396+ if(empty($nsname)) {
 397+ $this->showForm( wfMsg('namespace_name_missing') );
 398+ }
 399+
 400+ $ns = new Namespace();
 401+ $newnameindex = $ns->addName($nsname);
 402+
 403+ if( is_null($newnameindex) ) {
 404+ $this->showForm(
 405+ wfMsg('namespace_error',$nsname),
 406+ wfMsg('namespace_name_illegal_characters', NS_CHAR)
 407+ );
 408+ return false;
 409+ }
 410+
 411+ $ns->setDefaultNameIndex($newnameindex);
 412+ $nrv=$ns->testSave();
 413+ /*
 414+ The only errors which can occur here should be
 415+ name-related.
 416+ */
 417+ if( $nrv[NS_RESULT] == NS_NAME_ISSUES ) {
 418+ $this->showForm(
 419+ wfMsg('namespace_error',$nsname),
 420+ $this->nameIssues($nrv)
 421+ );
 422+ return false;
 423+ }
 424+
 425+ $newnamespaceindex = $nrv[NS_SAVE_ID];
 426+
 427+ if( $nscreatetalk && !empty($nstalkname) ) {
 428+
 429+ // Initialize a talk namespace
 430+ $talkns = new Namespace();
 431+ $talkns->setParentIndex( $newnamespaceindex );
 432+ $talkns->setSubpages();
 433+ $newtalknameindex=$talkns->addName( $nstalkname );
 434+ $talkns->setDefaultNameIndex( $newtalknameindex );
 435+
 436+ // attempt to create it
 437+ $trv = $talkns->testSave();
 438+ // Did it success ?
 439+ if( $trv[NS_RESULT] != NS_CREATED ) {
 440+ $this->showForm(
 441+ wfMsg('talk_namespace_error',$nstalkname),
 442+ $this->nameIssues($trv)
 443+ );
 444+ return false;
 445+ }
 446+ }
 447+
 448+ // We now have validated stuff, lets save for real.
 449+ // No logic errors should occur beyond this point.
 450+ $ns->save();
 451+ $complete = wfMsg( 'namespace_created', $nsname );
 452+
 453+ if( $nscreatetalk && !empty($nstalkname) ) {
 454+
 455+ $talkns->save();
 456+ $complete .= ' '.wfMsg('talk_namespace_created');
 457+ }
 458+
 459+ // Report success to user
 460+ $wgOut->addWikiText($complete);
 461+ $this->showForm();
 462+
 463+ $this->logNs('add',$nsname);
 464+ if($nscreatetalk) {
 465+ $this->logNs('add',$nstalkname);
 466+ }
 467+ }
 468+
 469+ /**
 470+ * Convenient access to the logging functions
 471+ * @param $action - 'add','delete','modify' or 'pseudo'
 472+ * @param $ns - name of the namespace
 473+ * @param $tns - for pseudonamespaces, name of the target namespace
 474+ */
 475+ function logNs($action,$ns='',$tns='') {
 476+ $log = new LogPage( 'namespace' );
 477+ $dummyTitle = Title::makeTitle( 0, '' );
 478+ if($action=='pseudo') {
 479+ $log->addEntry( $action,$dummyTitle,'',array($ns,$tns));
 480+ } elseif($action=='modify') {
 481+ $log->addEntry( $action,$dummyTitle,'');
 482+ } else {
 483+ $log->addEntry( $action,$dummyTitle,'',array($ns));
 484+ }
 485+ }
 486+
 487+ /**
 488+ * Modify, delete or add namespace names, set default names,
 489+ * or change namespace properties. Uses the request data from
 490+ * the form. Note that we have to create a new namespace object,
 491+ * since we do not want to modify the "live" namespace until
 492+ * we know that all the requested operations can be performed.
 493+ * Nothing will be done unless every transaction can be completed
 494+ * successfully.
 495+ */
 496+ function changeNamespaces() {
 497+
 498+ global $wgOut, $wgRequest;
 499+ $nsstore = wfGetNamespaceStore();
 500+ $nsobjects = $nsstore->getAllNamespaceObjects();
 501+
 502+ $newns = array();
 503+ foreach( $nsobjects as $ns ) {
 504+ $nsindex = $ns->getIndex();
 505+ $newns[$nsindex] = new Namespace();
 506+ $newns[$nsindex]->setIndex($nsindex);
 507+ $newns[$nsindex]->setSystemType($ns->getSystemType());
 508+
 509+ if(!$ns->isSpecial()) {
 510+ // Some variables names
 511+ $subvar = "ns{$nsindex}Subpages";
 512+ $searchvar = "ns{$nsindex}Search";
 513+ $hiddenvar = "ns{$nsindex}Hidden";
 514+ $prefixvar = "ns{$nsindex}Linkprefix";
 515+ $parentvar = "ns{$nsindex}Parent";
 516+
 517+ // Get data submitted by user
 518+ $subpages = $wgRequest->getBool($subvar);
 519+ $searchdefault = $wgRequest->getBool($searchvar);
 520+ $hidden = $wgRequest->getBool($hiddenvar);
 521+ $prefix = $wgRequest->getText($prefixvar);
 522+ $parent = $wgRequest->getIntOrNull($parentvar);
 523+
 524+ // Initialise our new namespace
 525+ $newns[$nsindex]->setSubpages($subpages);
 526+ $newns[$nsindex]->setSearchedByDefault($searchdefault);
 527+ $newns[$nsindex]->setHidden($hidden);
 528+ $newns[$nsindex]->setTarget($prefix);
 529+
 530+ if($nsstore->hasIndex($parent)) {
 531+ $newns[$nsindex]->setParentIndex($parent);
 532+ }
 533+ }
 534+
 535+ // Inherit namespace names
 536+ $newns[$nsindex]->names = $ns->names;
 537+
 538+ // This can never be changed by the user.
 539+ $newns[$nsindex]->setCanonicalNameIndex($ns->getCanonicalNameIndex());
 540+
 541+ // New names, appended to end
 542+ for($i=1;$i<=3;$i++) {
 543+ $nvar = "ns{$nsindex}NewName{$i}";
 544+ if( $nname = $wgRequest->getText($nvar) ) {
 545+ $newns[$nsindex]->addName($nname);
 546+ }
 547+ }
 548+
 549+ # Changes and deletions. Do them last since they can
 550+ # affect index slots of existing names.
 551+ foreach( $ns->names as $nameindex=>$name ) {
 552+ $var="ns{$nsindex}Name{$nameindex}";
 553+ if($req=$wgRequest->getText($var)) {
 554+ #wfDebug("Name var $var contains $req\n");
 555+
 556+ # Alter name if necessary.
 557+ if($req != $name) {
 558+ # The last parameter means that we do not check if the
 559+ # name is valid - this is done later for all names.
 560+ $newns[$nsindex]->setName($name, $req, false);
 561+
 562+ #wfDebug("Setting name $nameindex of namespace $nsindex to $req. Old name is $name.\n");
 563+ }
 564+ }
 565+ $delvar = "ns{$nsindex}Delete{$nameindex}";
 566+ if( $wgRequest->getInt($delvar) ) {
 567+ #wfDebug("$delvar should be deleted.\n");
 568+ $newns[$nsindex]->removeNameByIndex($nameindex);
 569+ }
 570+ }
 571+
 572+ $dvar = "ns{$nsindex}Default";
 573+
 574+ # Did the user select a default name?
 575+ $dindex = $wgRequest->getIntOrNull($dvar);
 576+
 577+ # If not, get the old one.
 578+ if(is_null($dindex)) {
 579+ $dindex=$ns->getDefaultNameIndex();
 580+ }
 581+
 582+ # Does the name exist and is it non-empty?
 583+ if(
 584+ !is_null($dindex)
 585+ && array_key_exists($dindex,
 586+ $newns[$nsindex]->names)
 587+ && !empty($newns[$nsindex]->names[$dindex])
 588+ ) {
 589+ # Use this default name.
 590+ $newns[$nsindex]->setDefaultNameIndex($dindex);
 591+ } else {
 592+ # We have lost our default name, perhaps it
 593+ # was deleted. Get a new one if possible.
 594+ $newns[$nsindex]->setDefaultNameIndex(
 595+ $newns[$nsindex]->getNewDefaultNameIndex()
 596+ );
 597+ }
 598+ }
 599+
 600+ foreach($newns as $nns) {
 601+ $nrv = $nns->testSave();
 602+ if( $nrv[NS_RESULT] == NS_NAME_ISSUES ) {
 603+ $this->showForm(
 604+ wfMsg(
 605+ 'namespace_error',
 606+ $nns->getDefaultName()),
 607+ $this->nameIssues($nrv)
 608+ );
 609+ return false;
 610+ } elseif($nrv[NS_RESULT] == NS_MISSING) {
 611+ $this->showForm(
 612+ wfmsg('namespace_has_gone_missing',
 613+ $nns->getIndex())
 614+ );
 615+ return false;
 616+ }
 617+ }
 618+ # Only do anything if everything can be done successfully.
 619+ foreach($newns as $nns) {
 620+ $nns->save();
 621+ }
 622+
 623+ # Unfortunately, NS_IDENTICAL does not work consistently
 624+ # atm, so we can only add a generic log entry.
 625+ $this->logNs('modify');
 626+
 627+ # IMPORTANT: The namespace name indexes are unpredictable when
 628+ # serialized, so we have to reload the definitions from the
 629+ # database at this point; otherwise, there could be index
 630+ # mismatches.
 631+ $nsstore->load(true);
 632+
 633+ # Return to the namespace manager with the changes made.
 634+ $wgOut->addWikiText( wfMsg('namespace_changes_saved') );
 635+ $this->showForm();
 636+
 637+ return true;
 638+ }
 639+
 640+ /**
 641+ * Creates a table showing problems with namespace name changes
 642+ * or additions, based on result data from the save operation.
 643+ *
 644+ * @param array Namespace::save result array
 645+ * @return string A HTML table with namespaces issues
 646+ */
 647+ function nameIssues( $result ) {
 648+
 649+ # Initialize table with heading
 650+ $htmltable=
 651+ '<table border="0" width="100%" cellspacing="5" cellpadding="5" rules="all">'
 652+ . '<tr><th colspan="2">' . wfMsg('namespace_name_issues') . '</th></tr>'
 653+ . '<tr><th>' . wfMsg('namespace_name_header') . '</th>'
 654+ . '<th>'.wfMsg('namespace_issue_header').'</th></tr>'
 655+ . "\n";
 656+
 657+ foreach($result[NS_ILLEGAL_NAMES] as $illegalName) {
 658+ $htmltable.=
 659+ '<tr><td>'
 660+ .$illegalName.
 661+ '</td><td>'
 662+ .wfMsg('namespace_name_illegal_characters').
 663+ '</td></tr>';
 664+ }
 665+ foreach($result[NS_DUPLICATE_NAMES] as $duplicateName) {
 666+ $htmltable.=
 667+ '<tr><td>'
 668+ .$duplicateName.
 669+ '</td><td>'
 670+ .wfMsg('namespace_name_dupe').
 671+ '</td></tr>';
 672+ }
 673+ foreach($result[NS_INTERWIKI_NAMES] as $interwikiName) {
 674+ $htmltable.=
 675+ '<tr><td>'
 676+ .$interwikiName.
 677+ '</td><td>'
 678+ .wfMsg('namespace_name_interwiki').
 679+ '</td></tr>';
 680+ }
 681+ foreach($result[NS_PREFIX_NAMES] as $prefixName) {
 682+ $htmltable.=
 683+ '<tr><td>'
 684+ .$prefixName.
 685+ '</td><td>'
 686+ .wfMsg('namespace_name_prefix').
 687+ '</td></tr>';
 688+ }
 689+
 690+ # Close table
 691+ $htmltable .= '</table>'."\n";
 692+ return $htmltable;
 693+ }
 694+
 695+ /**
 696+ * List of titles which exist in a real namespace
 697+ * which duplicate page titles in a pseudonamespace.
 698+ *
 699+ * @return a wiki-formatted list of links
 700+ */
 701+ function pseudoDupes( $prefix, $dupelist ) {
 702+ $wikilist=wfMsg('pseudonamespace_title_dupes')."\n";
 703+ foreach($dupelist as $dupe) {
 704+ $wikilist.="# [[{$prefix}:{$dupe}|{$dupe}]]\n";
 705+ }
 706+ return $wikilist;
 707+ }
 708+
 709+ /**
 710+ * Delete the namespace, using form data.
 711+ * Checks for many error conditions:
 712+ * - Namespace must exist
 713+ * - System namespaces cannot be deleted
 714+ * - Namespaces which are non-empty cannot be deleted
 715+ */
 716+ function deleteNamespace() {
 717+ global $wgOut,$wgRequest;
 718+
 719+ $nsstore = wfGetNamespaceStore();
 720+
 721+ $nsid = $wgRequest->getInt('ns');
 722+
 723+ $ns = $nsstore->getNamespaceObjectByIndex($nsid);
 724+
 725+ /* There should be no delete links for namespaces which cannot
 726+ be deleted, but let's catch two possible problems just in case. */
 727+ if(is_null($ns) ) {
 728+ $this->showForm( wfMsg('namespace_not_deletable') , wfMsg('namespace_has_gone_missing', $nsid) );
 729+ return false;
 730+ } elseif( $ns->isSystemNamespace() ) {
 731+ $this->showForm( wfMsg('namespace_not_deletable') , wfMsg('namespace_not_deletable_system', $nsid) );
 732+ return false;
 733+ }
 734+
 735+ $nsdelete = clone ($ns);
 736+ $nsdeletename = $ns->getDefaultName();
 737+ $drv = $nsdelete->deleteNamespace();
 738+
 739+ if( empty($nsdeletename) ) {
 740+ # At least show the index
 741+ $nsdeletename = $nsid;
 742+ }
 743+
 744+ if( $drv[NS_RESULT] == NS_DELETED ) {
 745+ $wgOut->addWikiText( wfMsg('namespace_deleted',$nsdeletename) );
 746+ $this->showForm();
 747+ $this->logNs('delete',$nsdeletename);
 748+ return true;
 749+ } elseif( $drv[NS_RESULT] == NS_NAME_ISSUES ) {
 750+ $this->showForm( wfMsg('namespace_delete_error',$nsdeletename),$this->nameIssues($drv) );
 751+ return false;
 752+ } elseif ($drv[NS_RESULT] == NS_HAS_PAGES) {
 753+ /** TODO: link to Special:Allpages/namespace */
 754+ $this->showForm(wfMsg('namespace_delete_error',$nsdeletename), wfMsg('namespace_delete_not_empty'));
 755+ return false;
 756+ } else {
 757+ $this->showForm( wfMsg('namespace_delete_error') );
 758+ return false;
 759+ }
 760+ }
 761+
 762+ /**
 763+ * Call Namespace::convertPseudonamespace with the correct
 764+ * parameters and display the results.
 765+ */
 766+ function fixPseudonamespaces() {
 767+
 768+ global $wgOut, $wgRequest, $wgUser;
 769+ # Merging into non-empty namespaces is generally prohibited
 770+ $merge=$wgRequest->getBool('nsMerge');
 771+ if($merge && !in_array( 'merge_pseudonamespaces', $wgUser->getRights())) {
 772+ $this->showForm( wfMsg('badaccess'), wfMsg('badaccesstext','[['.wfMsg('administrators').']]','fix_pseudonamespaces'));
 773+ return false;
 774+ }
 775+ $prefix=$wgRequest->getText('nsPrefix');
 776+ $targetid=$wgRequest->getIntOrNull('nsConvertTo');
 777+ $converttalk = $wgRequest->getBool('nsConvertTalk');
 778+ if(empty($prefix) || is_null($targetid)) {
 779+ $this->showForm (wfMsg('pseudonamespace_info_missing'));
 780+ return false;
 781+
 782+ }
 783+
 784+ $nsstore = wfGetNamespaceStore();
 785+ $nsobj = $nsstore->getNamespaceObjectByIndex($targetid);
 786+
 787+ $talktargetid=$nsobj->getTalk();
 788+ $talk4nsobj=$nsstore->getNamespaceObjectByIndex($targettalkid);
 789+
 790+ if($converttalk && is_null($talktargetid)) {
 791+ $this->showForm (wfMsg('pseudonamespace_target_talk_not_found'));
 792+ return false;
 793+ }
 794+
 795+ $mainnsobj = $nsstore->getNamespaceObjectByIndex(NS_MAIN);
 796+ $maintalknsobj = $nsstore->getNamespaceObjectByIndex(NS_TALK);
 797+ $rv=$nsstore->convertPseudonamespace($prefix,$nsobj,$mainnsobj,$merge);
 798+ if($rv[NS_RESULT]!=NS_PSEUDO_CONVERTED) {
 799+ if(!($rv[NS_RESULT]==NS_PSEUDO_NOT_FOUND && $converttalk)) {
 800+ $this->showPseudoError($rv,$targetid,$prefix);
 801+ return false;
 802+ } else {
 803+ # Even if the prefix doesn't exist, we still
 804+ # want to check for possible talk page content.
 805+ $wgOut->addWikiText(wfMsg('pseudonamespace_not_found',$prefix));
 806+ $wgOut->addWikiText(wfMsg('pseudonamespace_trying_talk'));
 807+ }
 808+ } else {
 809+ $wgOut->addWikiText(wfMsg('pseudonamespace_converted', $prefix, $nsobj->getDefaultName()));
 810+ $this->logNs('pseudo',$prefix,$nsobj->getDefaultName());
 811+ }
 812+ if($converttalk) {
 813+ # A pseudonamespace, by definition, exists in the
 814+ # main (unprefixed) namespace - therefore its talk
 815+ # pages are NS_TALK.
 816+ $trv=$nsstore->convertPseudonamespace($prefix,$talk4nsobj,$maintalknsobj,$merge);
 817+ if($trv[NS_RESULT]!=NS_PSEUDO_CONVERTED) {
 818+ $this->showPseudoError($trv,$talktargetid,$prefix);
 819+ return false;
 820+ } else {
 821+ $wgOut->addWikiText(wfMsg('pseudonamespace_talk_converted'));
 822+ }
 823+ }
 824+ $this->showForm();
 825+ }
 826+ function showPseudoError($rv,$targetid,$prefix) {
 827+ global $wgNamespaces;
 828+ $istalk=$wgNamespaces[$targetid]->isTalk();
 829+ # For messages
 830+ $talk=$istalk ? 'talk_' : '';
 831+ if($rv[NS_RESULT]==NS_PSEUDO_NOT_FOUND) {
 832+ $this->showForm( wfMsg("pseudonamespace_{$talk}not_found",$prefix));
 833+ } elseif($rv[NS_RESULT]==NS_NON_EMPTY) {
 834+ $this->showForm(
 835+ wfMsg("pseudonamespace_{$talk}conversion_error",$prefix),
 836+ wfMsg("pseudonamespace_cannot_merge"));
 837+ } elseif($rv[NS_RESULT]==NS_DUPLICATE_TITLES) {
 838+ $this->showForm(
 839+ wfMsg("pseudonamespace_{$talk}conversion_error",$prefix),
 840+ $this->pseudoDupes($wgNamespaces[$targetid]->getDefaultName(),$rv[NS_DUPLICATE_TITLE_LIST]));
 841+ }
 842+ }
 843+
 844+ function getSelector($name_array,$parentslot=null) {
 845+ $noparent = wfMsg('no_parent_namespace');
 846+ $namespaceselect='';
 847+ foreach ( $name_array as $arr_index => $arr_name ) {
 848+ if( $arr_index < NS_MAIN && $arr_name!=$noparent )
 849+ continue;
 850+ $list_option = ($arr_index == NS_MAIN ? wfMsg ( 'blanknamespace' ) : $arr_name);
 851+ if(is_null($parentslot)) {
 852+ $arr_name == $noparent ? $selected = ' selected="selected" ' : $selected='';
 853+ } else {
 854+ $arr_index == $parentslot ? $selected = ' selected="selected"' : $selected='';
 855+ }
 856+ $namespaceselect .= "\n<option value='$arr_index'$selected>$list_option</option>";
 857+ }
 858+ return $namespaceselect;
 859+
 860+ }
 861+
 862+ function annotation( $text ) {
 863+ return wfElement( 'div', array( 'class' => 'mwNsAnnotation' ), $text );
 864+ }
 865+
 866+ function checkRow( $labelMessage, $name, $checked ) {
 867+ return '<tr><td colspan="2">' .
 868+ wfCheckLabel( wfMsg( $labelMessage ), $name, $name, $checked ) .
 869+ "</td></tr>\n";
 870+ }
 871+
 872+ function selectorRow( $labelMessage, $name, $selected ) {
 873+ $nsstore = wfGetNamespaceStore();
 874+ return '<tr><td colspan="2">' .
 875+ "<div>" . wfMsgHtml( $labelMessage ) . "</div>\n" .
 876+ "<div>" .
 877+ wfOpenElement( 'select', array( 'name' => $name ) ) .
 878+ $this->getSelector( $nsstore->getFormattedDefaultNamespaces(true), $selected ) .
 879+ wfCloseElement( 'select' ) .
 880+ "</div>" .
 881+ "</td></tr>\n";
 882+ }
 883+}
 884+?>
Property changes on: branches/wikidata/includes/SpecialNamespaces.php
___________________________________________________________________
Added: svn:eol-style
1885 + native
Index: branches/wikidata/config/index.php
@@ -909,6 +909,14 @@
910910 $article->updateRevisionOn( $wgDatabase, $revision );
911911 }
912912
 913+ # Namespace defs will be needed for new and existing installations
 914+ if($wgDatabase->selectField('namespace', 'COUNT(*)')==0) {
 915+ print "<li>Bootstrapping namespace definitions...";
 916+ require_once '../maintenance/nsBootstrap.php';
 917+ print "Done.";
 918+ }
 919+
 920+
913921 /* Write out the config file now that all is well */
914922 print "<li style=\"list-style: none\">\n";
915923 print "<p>Creating LocalSettings.php...</p>\n\n";
Index: branches/wikidata/languages/messages/MessagesEn.php
@@ -2783,6 +2783,89 @@
27842784 'size-megabytes' => '$1 MB',
27852785 'size-gigabytes' => '$1 GB',
27862786
 2787+# Namespace manager and namespace related messages
 2788+'transactionerror' => 'Error: could not complete transaction',
 2789+'nstarget' => "''In this namespace, unprefixed links will be treated as if they were prefixed with \"'''<tt>$1:</tt>'''\" (for example, <tt><nowiki>[[Scratchpad]]</nowiki></tt> will point to <tt><nowiki>[[$1:Scratchpad]]</nowiki></tt>). To suppress this behavior, add a colon in front of the title, e.g. <tt><nowiki>[[:Scratchpad]]</nowiki></tt>.''",
 2790+'namespace_missing_prefix'=>'Invalid namespace',
 2791+
 2792+'namespaces' => 'Namespace management',
 2793+'no_parent_namespace'=>'(Not a discussion namespace)',
 2794+'add_namespaces_header' => 'Create new namespaces here, then set all namespace-specific preferences below. In most cases, you will also want to add a matching talk (discussion) namespace.',
 2795+'add_namespace_default_name' => 'Namespace default name',
 2796+'add_namespace_default_talk' => 'Talk namespace default name',
 2797+'add_namespace_talk_confirm' => 'Yes, I want to create a talk namespace',
 2798+'add_namespace_button' => 'Add namespace',
 2799+'namespace_created'=>'Namespace "$1" was successfully created.',
 2800+'talk_namespace_created'=>'A corresponding talk (discussion) namespace has also been created.',
 2801+'namespace_name_issues'=>'There are issues with the following name(s):',
 2802+'namespace_name_illegal_characters'=>'The namespace name contains illegal characters. Only the following characters are allowed in namespace names: \'\'\'$1\'\'\'',
 2803+'namespace_name_missing'=>'You have not entered a namespace name.',
 2804+'namespace_name_dupe'=>'The namespace name is already in use. Please choose a different name.',
 2805+'namespace_name_not_empty'=>'Some pages still refer to this namespace using this name. It canot be deleted or renamed until all links are changed.',
 2806+'namespace_name_prefix'=>'There are pages which contain this name as a "pseudonamespace" (a text prefix which is not recognized as a real namespace). Use the pseudonamespace conversion form at the bottom to convert the pseudonamespace into a real one. You can create a temporary name first and change it later.',
 2807+'namespace_name_interwiki'=>'The name is already used as an Interwiki prefix to link to another wiki site. This Interwiki prefix would become unusable if this name was used.',
 2808+'namespace_name_linked'=>'The namespace name is still linked to from some pages. If it was deleted, these links would be broken.',
 2809+'namespace_error'=>'The namespace "$1" cannot be created or modified.',
 2810+'namespace_delete_error'=>'The namespace "$1" cannot be deleted.',
 2811+'namespace_delete_not_empty'=>'The namespace still contains pages. Only empty namespaces can be removed.',
 2812+'namespace_deleted'=>'The namespace "$1" has been deleted successfully.',
 2813+'namespace_changes_saved'=>'The namespace changes have been saved.',
 2814+'talk_namespace_error'=>'The corresponding discussion (talk) namespace "$1" cannot be created. No namespaces have been added.',
 2815+'modify_namespaces_header' => 'Configure namespaces here. System namespaces cannot be deleted.',
 2816+'canonicalname' => 'canonical name',
 2817+'defaultname' => 'primary name',
 2818+'namespace_name_header'=>'Namespace name',
 2819+'namespace_issue_header'=>'Problem',
 2820+'fix_pseudonamespaces_header'=>'You can convert "pseudonamespaces" (titles with a consistent prefix like "Cookbook:" which is not a real namespace) into real namespaces here, by providing the prefix and selecting a target namespace. If the namespace does not yet exist, create a temporary name for it above first; you can change it after the conversion.',
 2821+'pseudonamespace_prefix'=>'Pseudonamespace prefix',
 2822+'pseudonamespace_target'=>'Convert into',
 2823+'pseudonamespace_converttalk'=>'Try to convert discussion pages into the associated talk namespace',
 2824+'pseudonamespace_convert'=>'Convert',
 2825+'pseudonamespace_converted'=>'The pseudonamespace "$1" was successfully converted into the real namespace with the default name "$2".',
 2826+'pseudonamespace_trying_talk'=>'Looking for talk pages anyway.',
 2827+'pseudonamespace_talk_converted'=>'The associated discussion pages were converted.',
 2828+'pseudonamespace_conversion_error'=>'There was a problem converting the pseudonamespace "$1".',
 2829+'pseudonamespace_talk_conversion_error'=>'There was a problem converting the talk pages of the pseudonamespace.',
 2830+'pseudonamespace_info_missing'=>'You did not provide a namespace name or target namespace.',
 2831+'pseudonamespace_not_found'=>'No pages with the prefix "$1" were found!',
 2832+'pseudonamespace_talk_not_found'=>'No talk pages associated with this pseudonamespace were found.',
 2833+'pseudonamespace_target_talk_not_found'=>'The target namespace does not appear to have an associated talk namespace!',
 2834+'pseudonamespace_merge'=>'Merge into a namespace that contains pages (MAY BE IRREVERSIBLE)',
 2835+'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.',
 2836+'pseudonamespace_title_dupes'=>'The target namespace already contains pages with the following titles:',
 2837+
 2838+# Namespace logging
 2839+'namespacelogpage'=>'Namespace_log',
 2840+'namespacelogtext'=>'This is a log of all changes made through the namespace manager.',
 2841+'namespaceaddlog'=>'Added namespace "$2"',
 2842+'namespacedeletelog'=>'Deleted namespace "$2"',
 2843+'namespacemodifylog'=>'Modified namespace definitions',
 2844+'namespacepseudolog'=>'Converted pseudonamespace "$2" into real namespace "$3"',
 2845+
 2846+# This is appended via JavaScript to the entered namsepace name
 2847+# as a suggested talkpage name in Special:Namespaces. If set to '-',
 2848+# it will not be used.
 2849+'talkpagesuffix' => ' talk',
 2850+'special_namespace'=>'This is a special namespace that cannot contain pages.',
 2851+'namespace_child_of'=>'Discussion namespace of:',
 2852+'namespace_support_subpages'=>'Support subpages',
 2853+'namespace_search_by_default'=>'Include in search results',
 2854+'namespace_hide_in_lists'=>'Hide in lists',
 2855+'namespace_default_link_prefix'=>'Unmarked links go to:',
 2856+'namespace_system'=>'System namespace',
 2857+'delete_namespace'=>'Delete namespace',
 2858+'namespace_properties'=>'Namespace properties',
 2859+'namespace_slot'=>'Internal slot',
 2860+'namespace_names'=>'Names',
 2861+'namespace_existing_names'=>'Existing names',
 2862+'namespace_new_names'=>'New names',
 2863+'namespace_default_name'=>'Default',
 2864+'namespace_delete_name'=>'Delete',
 2865+'namespace_save_changes'=>'Save changes',
 2866+'namespace_not_deletable'=>'The namespace cannot be deleted.',
 2867+'namespace_has_gone_missing'=>'A namespace with the number $1 was not found.',
 2868+'namespace_not_deletable_system'=>'The namespace with the number $1 is a system namespace which is required for the operation of MediaWiki.',
 2869+
27872870 );
27882871
27892872 ?>
Index: branches/wikidata/languages/Language.php
@@ -176,14 +176,52 @@
177177 return $this->bookstoreList;
178178 }
179179
180 - /**
 180+ /**#@+
 181+ *
 182+ * Only used for migrating older version of MediaWiki to the
 183+ * current version, and for populating the database in a fresh
 184+ * install.
181185 * @return array
182 - */
183 - function getNamespaces() {
 186+ *
 187+ */
 188+ function getNamespaceSynonymsBootstrap() {
 189+ return array(
 190+ NS_IMAGE => array( 'Image', 'Sound', 'Video' ),
 191+ NS_IMAGE_TALK => array( 'Image_talk', 'Sound_talk', 'Video_talk' )
 192+ );
 193+ }
 194+
 195+ function getNamespacesBootstrap() {
184196 $this->load();
185197 return $this->namespaceNames;
186198 }
187199
 200+ /**#@+
 201+ * @deprecated
 202+ *
 203+ */
 204+ function getNamespaceSynonyms() {
 205+ $nsstore = wfGetNamespaceStore();
 206+ $defns = $nsstore->getDefaultNamespaces();
 207+ $allns = $nsstore->getAllNamespacesArray();
 208+ foreach ($defns as $nskey => $nsstring) {
 209+ $aliases = array_diff($allns[$nskey],array($nsstring));
 210+ if(empty($aliases)) {
 211+ unset($allns[$nskey]);
 212+ }
 213+ else {
 214+ $allns[$ns]=$aliases;
 215+ }
 216+ }
 217+ return $allns;
 218+ }
 219+
 220+ function getNamespaces() {
 221+ $nsstore = wfGetNamespaceStore();
 222+ return $nsstore->getDefaultNamespaces();
 223+ }
 224+
 225+
188226 /**
189227 * A convenience function that returns the same thing as
190228 * getNamespaces() except with the array values changed to ' '
Index: branches/wikidata/RELEASE-NOTES
@@ -30,6 +30,8 @@
3131
3232 == Changes since 1.9 ==
3333
 34+* Namespace definitions moved into the database, new namespace manager (Special:Namespaces)
 35+ available to bureaucrats to change them. Various new namespace-related properties.
3436 * (bug 7292) Fix site statistics when moving pages in/out of content namespaces
3537 * (bug 6937) Introduce "statistics-footer" message, appended to Special:Statistics
3638 * (bug 8531) Correct local name of Lingála (patch by Raymond)