Make import destination UI more intuitive and clearer
authorThis, that and the other <at.light@live.com.au>
Tue, 27 Jan 2015 09:01:04 +0000 (20:01 +1100)
committerUmherirrender <umherirrender_de.wp@web.de>
Wed, 22 Apr 2015 18:46:40 +0000 (18:46 +0000)
Previously there were two fields: Destination namespace, and Destination
root page. They were both optional, and the "root page" one in particular
was a bit mysterious until you tried it out. In addition, there was a
strange interaction when you set both fields (I still don't quite
understand what used to happen in this case).

Now, there is a set of three clearly described radio buttons, allowing the
user to select whether to import pages into their automatically chosen
locations, into a single namespace, or as subpages of a given page. These
correspond to the three ImportTitleFactory classes available in MediaWiki.

See https://phabricator.wikimedia.org/M28 for a screenshot.

The logic of WikiImporter#setTargetNamespace is tweaked slightly to remove
the interaction between target namespace and target root page, since only
one of these options can now be set. Similarly, the API's import module
is modified in the same way.

Bug: T17908
Change-Id: I11521260a88a7f4a95fbdb71ac50bcf7b4fe5cd1

RELEASE-NOTES-1.26
includes/Import.php
includes/api/ApiImport.php
includes/api/i18n/en.json
includes/specials/SpecialImport.php
languages/i18n/en.json
languages/i18n/qqq.json

index eddfe30..9426635 100644 (file)
@@ -21,6 +21,8 @@ production.
 === Action API changes in 1.26 ===
 * API action=query&list=tags: The displayname can now be boolean false if the
   tag is meant to be hidden from user interfaces.
+* action=import no longer allows both the namespace= and rootpage= parameters
+  to be set. If they are both set, the value of rootpage= will be ignored.
 
 === Action API internal changes in 1.26 ===
 
index 1e0f8e2..c2fae30 100644 (file)
@@ -34,7 +34,7 @@ class WikiImporter {
        private $reader = null;
        private $foreignNamespaces = null;
        private $mLogItemCallback, $mUploadCallback, $mRevisionCallback, $mPageCallback;
-       private $mSiteInfoCallback, $mTargetNamespace, $mPageOutCallback;
+       private $mSiteInfoCallback, $mPageOutCallback;
        private $mNoticeCallback, $mDebug;
        private $mImportUploads, $mImageBasePath;
        private $mNoUpdates = false;
@@ -240,7 +240,6 @@ class WikiImporter {
        public function setTargetNamespace( $namespace ) {
                if ( is_null( $namespace ) ) {
                        // Don't override namespaces
-                       $this->mTargetNamespace = null;
                        $this->setImportTitleFactory( new NaiveImportTitleFactory() );
                        return true;
                } elseif (
@@ -248,7 +247,6 @@ class WikiImporter {
                        MWNamespace::exists( intval( $namespace ) )
                ) {
                        $namespace = intval( $namespace );
-                       $this->mTargetNamespace = $namespace;
                        $this->setImportTitleFactory( new NamespaceImportTitleFactory( $namespace ) );
                        return true;
                } else {
@@ -268,10 +266,7 @@ class WikiImporter {
                        $this->setImportTitleFactory( new NaiveImportTitleFactory() );
                } elseif ( $rootpage !== '' ) {
                        $rootpage = rtrim( $rootpage, '/' ); //avoid double slashes
-                       $title = Title::newFromText( $rootpage, !is_null( $this->mTargetNamespace )
-                               ? $this->mTargetNamespace
-                               : NS_MAIN
-                       );
+                       $title = Title::newFromText( $rootpage );
 
                        if ( !$title || $title->isExternal() ) {
                                $status->fatal( 'import-rootpage-invalid' );
index 2e87d22..40cf6e2 100644 (file)
@@ -63,8 +63,7 @@ class ApiImport extends ApiBase {
                $importer = new WikiImporter( $source->value, $this->getConfig() );
                if ( isset( $params['namespace'] ) ) {
                        $importer->setTargetNamespace( $params['namespace'] );
-               }
-               if ( isset( $params['rootpage'] ) ) {
+               } elseif ( isset( $params['rootpage'] ) ) {
                        $statusRootPage = $importer->setTargetRootPage( $params['rootpage'] );
                        if ( !$statusRootPage->isGood() ) {
                                $this->dieStatus( $statusRootPage );
index 615d60a..88eaf7c 100644 (file)
        "apihelp-import-param-interwikipage": "For interwiki imports: page to import.",
        "apihelp-import-param-fullhistory": "For interwiki imports: import the full history, not just the current version.",
        "apihelp-import-param-templates": "For interwiki imports: import all included templates as well.",
-       "apihelp-import-param-namespace": "For interwiki imports: import to this namespace.",
-       "apihelp-import-param-rootpage": "Import as subpage of this page.",
+       "apihelp-import-param-namespace": "Import to this namespace. Overrides the <kbd>$1rootpage</kbd> parameter.",
+       "apihelp-import-param-rootpage": "Import as subpage of this page. Ignored if the <kbd>$1namespace</kbd> parameter is provided.",
        "apihelp-import-example-import": "Import [[meta:Help:Parserfunctions]] to namespace 100 with full history.",
 
        "apihelp-login-description": "Log in and get authentication cookies.\n\nIn the event of a successful log-in, the needed cookies will be included in the HTTP response headers. In the event of a failed log-in, further attempts may be throttled to limit automated password guessing attacks.",
index af86964..8124f10 100644 (file)
@@ -34,6 +34,7 @@ class SpecialImport extends SpecialPage {
        private $interwiki = false;
        private $subproject;
        private $fullInterwikiPrefix;
+       private $mapping = 'default';
        private $namespace;
        private $rootpage = '';
        private $frompage = '';
@@ -101,26 +102,33 @@ class SpecialImport extends SpecialPage {
        private function doImport() {
                $isUpload = false;
                $request = $this->getRequest();
-               $this->namespace = $request->getIntOrNull( 'namespace' );
                $this->sourceName = $request->getVal( "source" );
 
                $this->logcomment = $request->getText( 'log-comment' );
                $this->pageLinkDepth = $this->getConfig()->get( 'ExportMaxLinkDepth' ) == 0
                        ? 0
                        : $request->getIntOrNull( 'pagelink-depth' );
-               $this->rootpage = $request->getText( 'rootpage' );
+
+               $this->mapping = $request->getVal( 'mapping' );
+               if ( $this->mapping === 'namespace' ) {
+                       $this->namespace = $request->getIntOrNull( 'namespace' );
+               } elseif ( $this->mapping === 'subpage' ) {
+                       $this->rootpage = $request->getText( 'rootpage' );
+               } else {
+                       $this->mapping = 'default';
+               }
 
                $user = $this->getUser();
                if ( !$user->matchEditToken( $request->getVal( 'editToken' ) ) ) {
                        $source = Status::newFatal( 'import-token-mismatch' );
-               } elseif ( $this->sourceName == 'upload' ) {
+               } elseif ( $this->sourceName === 'upload' ) {
                        $isUpload = true;
                        if ( $user->isAllowed( 'importupload' ) ) {
                                $source = ImportStreamSource::newFromUpload( "xmlimport" );
                        } else {
                                throw new PermissionsError( 'importupload' );
                        }
-               } elseif ( $this->sourceName == "interwiki" ) {
+               } elseif ( $this->sourceName === 'interwiki' ) {
                        if ( !$user->isAllowed( 'import' ) ) {
                                throw new PermissionsError( 'import' );
                        }
@@ -163,8 +171,7 @@ class SpecialImport extends SpecialPage {
                        $importer = new WikiImporter( $source->value, $this->getConfig() );
                        if ( !is_null( $this->namespace ) ) {
                                $importer->setTargetNamespace( $this->namespace );
-                       }
-                       if ( !is_null( $this->rootpage ) ) {
+                       } elseif ( !is_null( $this->rootpage ) ) {
                                $statusRootPage = $importer->setTargetRootPage( $this->rootpage );
                                if ( !$statusRootPage->isGood() ) {
                                        $out->wrapWikiMsg(
@@ -219,6 +226,79 @@ class SpecialImport extends SpecialPage {
                }
        }
 
+       private function getMappingFormPart( $sourceName ) {
+               $isSameSourceAsBefore = ( $this->sourceName === $sourceName );
+               $defaultNamespace = $this->getConfig()->get( 'ImportTargetNamespace' );
+               return "<tr>
+                                       <td>
+                                       </td>
+                                       <td class='mw-input'>" .
+                                       Xml::radioLabel(
+                                               $this->msg( 'import-mapping-default' )->text(),
+                                               'mapping',
+                                               'default',
+                                               // mw-import-mapping-interwiki-default, mw-import-mapping-upload-default
+                                               "mw-import-mapping-$sourceName-default",
+                                               ( $isSameSourceAsBefore ?
+                                                       ( $this->mapping === 'default' ) :
+                                                       is_null( $defaultNamespace ) )
+                                       ) .
+                                       "</td>
+                               </tr>
+                               <tr>
+                                       <td>
+                                       </td>
+                                       <td class='mw-input'>" .
+                                       Xml::radioLabel(
+                                               $this->msg( 'import-mapping-namespace' )->text(),
+                                               'mapping',
+                                               'namespace',
+                                               // mw-import-mapping-interwiki-namespace, mw-import-mapping-upload-namespace
+                                               "mw-import-mapping-$sourceName-namespace",
+                                               ( $isSameSourceAsBefore ?
+                                                       ( $this->mapping === 'namespace' ) :
+                                                       !is_null( $defaultNamespace ) )
+                                       ) . ' ' .
+                                       Html::namespaceSelector(
+                                               array(
+                                                       'selected' => ( $isSameSourceAsBefore ?
+                                                               $this->namespace :
+                                                               ( $defaultNamespace || '' ) ),
+                                               ), array(
+                                                       'name' => "namespace",
+                                                       // mw-import-namespace-interwiki, mw-import-namespace-upload
+                                                       'id' => "mw-import-namespace-$sourceName",
+                                                       'class' => 'namespaceselector',
+                                               )
+                                       ) .
+                                       "</td>
+                               </tr>
+                               <tr>
+                                       <td>
+                                       </td>
+                                       <td class='mw-input'>" .
+                                       Xml::radioLabel(
+                                               $this->msg( 'import-mapping-subpage' )->text(),
+                                               'mapping',
+                                               'subpage',
+                                               // mw-import-mapping-interwiki-subpage, mw-import-mapping-upload-subpage
+                                               "mw-import-mapping-$sourceName-subpage",
+                                               ( $isSameSourceAsBefore ? ( $this->mapping === 'subpage' ) : '' )
+                                       ) . ' ' .
+                                       Xml::input( 'rootpage', 50,
+                                               ( $isSameSourceAsBefore ? $this->rootpage : '' ),
+                                               array(
+                                                       // Should be "mw-import-rootpage-...", but we keep this inaccurate
+                                                       // ID for legacy reasons
+                                                       // mw-interwiki-rootpage-interwiki, mw-interwiki-rootpage-upload
+                                                       'id' => "mw-interwiki-rootpage-$sourceName",
+                                                       'type' => 'text'
+                                               )
+                                       ) . ' ' .
+                                       "</td>
+                               </tr>";
+       }
+
        private function showForm() {
                $action = $this->getPageTitle()->getLocalURL( array( 'action' => 'submit' ) );
                $user = $this->getUser();
@@ -226,6 +306,7 @@ class SpecialImport extends SpecialPage {
                $importSources = $this->getConfig()->get( 'ImportSources' );
 
                if ( $user->isAllowed( 'importupload' ) ) {
+                       $mappingSelection = $this->getMappingFormPart( 'upload' );
                        $out->addHTML(
                                Xml::fieldset( $this->msg( 'import-upload' )->text() ) .
                                        Xml::openElement(
@@ -255,22 +336,11 @@ class SpecialImport extends SpecialPage {
                                        "</td>
                                        <td class='mw-input'>" .
                                        Xml::input( 'log-comment', 50,
-                                               ( $this->sourceName == 'upload' ? $this->logcomment : '' ),
+                                               ( $this->sourceName === 'upload' ? $this->logcomment : '' ),
                                                array( 'id' => 'mw-import-comment', 'type' => 'text' ) ) . ' ' .
                                        "</td>
                                </tr>
-                               <tr>
-                                       <td class='mw-label'>" .
-                                       Xml::label(
-                                               $this->msg( 'import-interwiki-rootpage' )->text(),
-                                               'mw-interwiki-rootpage-upload'
-                                       ) .
-                                       "</td>
-                                       <td class='mw-input'>" .
-                                       Xml::input( 'rootpage', 50, $this->rootpage,
-                                               array( 'id' => 'mw-interwiki-rootpage-upload', 'type' => 'text' ) ) . ' ' .
-                                       "</td>
-                               </tr>
+                               $mappingSelection
                                <tr>
                                        <td></td>
                                        <td class='mw-submit'>" .
@@ -301,6 +371,7 @@ class SpecialImport extends SpecialPage {
                                        "</td>
                                </tr>";
                        }
+                       $mappingSelection = $this->getMappingFormPart( 'interwiki' );
 
                        $out->addHTML(
                                Xml::fieldset( $this->msg( 'importinterwiki' )->text() ) .
@@ -413,45 +484,17 @@ class SpecialImport extends SpecialPage {
                                        "</td>
                                </tr>
                                $importDepth
-                               <tr>
-                                       <td class='mw-label'>" .
-                                       Xml::label( $this->msg( 'import-interwiki-namespace' )->text(), 'namespace' ) .
-                                       "</td>
-                                       <td class='mw-input'>" .
-                                       Html::namespaceSelector(
-                                               array(
-                                                       'selected' => $this->namespace,
-                                                       'all' => '',
-                                               ), array(
-                                                       'name' => 'namespace',
-                                                       'id' => 'namespace',
-                                                       'class' => 'namespaceselector',
-                                               )
-                                       ) .
-                                       "</td>
-                               </tr>
                                <tr>
                                        <td class='mw-label'>" .
                                        Xml::label( $this->msg( 'import-comment' )->text(), 'mw-interwiki-comment' ) .
                                        "</td>
                                        <td class='mw-input'>" .
                                        Xml::input( 'log-comment', 50,
-                                               ( $this->sourceName == 'interwiki' ? $this->logcomment : '' ),
+                                               ( $this->sourceName === 'interwiki' ? $this->logcomment : '' ),
                                                array( 'id' => 'mw-interwiki-comment', 'type' => 'text' ) ) . ' ' .
                                        "</td>
                                </tr>
-                               <tr>
-                                       <td class='mw-label'>" .
-                                       Xml::label(
-                                               $this->msg( 'import-interwiki-rootpage' )->text(),
-                                               'mw-interwiki-rootpage-interwiki'
-                                       ) .
-                                       "</td>
-                                       <td class='mw-input'>" .
-                                       Xml::input( 'rootpage', 50, $this->rootpage,
-                                               array( 'id' => 'mw-interwiki-rootpage-interwiki', 'type' => 'text' ) ) . ' ' .
-                                       "</td>
-                               </tr>
+                               $mappingSelection
                                <tr>
                                        <td>
                                        </td>
index b8cda24..8afed1a 100644 (file)
        "import-interwiki-history": "Copy all history revisions for this page",
        "import-interwiki-templates": "Include all templates",
        "import-interwiki-submit": "Import",
-       "import-interwiki-namespace": "Destination namespace:",
-       "import-interwiki-rootpage": "Destination root page (optional):",
+       "import-mapping-default": "Import to default locations",
+       "import-mapping-namespace": "Import to a namespace:",
+       "import-mapping-subpage": "Import as subpages of the following page:",
        "import-upload-filename": "Filename:",
        "import-comment": "Comment:",
        "importtext": "Please export the file from the source wiki using the [[Special:Export|export utility]].\nSave it to your computer and upload it here.",
index 4ee5f25..f4d1e40 100644 (file)
        "import-interwiki-history": "This is an option on [[Special:Import]]. Usually, when unchecked, only the first version of a page is imported. When you check the option, all versions are imported. This is important often to check for licensing reasons.\n\nSee also:\n* {{msg-mw|Import-interwiki-templates}}\n* {{msg-mw|Import-interwiki-namespace}}\n* {{msg-mw|Import-comment}}\n* {{msg-mw|Import-interwiki-rootpage}}\n* {{msg-mw|Import-interwiki-submit}}",
        "import-interwiki-templates": "Used as label for the checkbox in [[Special:Import]].\n\nSee also:\n* {{msg-mw|Import-interwiki-history}}\n* {{msg-mw|Import-interwiki-namespace}}\n* {{msg-mw|Import-comment}}\n* {{msg-mw|Import-interwiki-rootpage}}\n* {{msg-mw|Import-interwiki-submit}}",
        "import-interwiki-submit": "Used as Submit button text in [[Special:Import]].\n\nSee also:\n* {{msg-mw|Import-interwiki-history}}\n* {{msg-mw|Import-interwiki-templates}}\n* {{msg-mw|Import-interwiki-namespace}}\n* {{msg-mw|Import-comment}}\n* {{msg-mw|Import-interwiki-rootpage}}\n{{Identical|Import}}",
-       "import-interwiki-namespace": "Used as label in Import form on [[Special:Import]].\n\nSee also:\n* {{msg-mw|Import-interwiki-history}}\n* {{msg-mw|Import-interwiki-templates}}\n* {{msg-mw|Import-comment}}\n* {{msg-mw|Import-interwiki-rootpage}}\n* {{msg-mw|Import-interwiki-submit}}",
-       "import-interwiki-rootpage": "Used on [[Special:Import]] as label.\n\nSee also:\n* {{msg-mw|Import-interwiki-history}}\n* {{msg-mw|Import-interwiki-templates}}\n* {{msg-mw|Import-interwiki-namespace}}\n* {{msg-mw|Import-comment}}\n* {{msg-mw|Import-interwiki-submit}}",
+       "import-mapping-default": "Used as label for the first of three radio buttons in Import form on [[Special:Import]].\n\nSee also:\n* {{msg-mw|Import-mapping-namespace}}\n* {{msg-mw|Import-mapping-subpage}}",
+       "import-mapping-namespace": "Used as label for the second of three radio buttons in Import form on [[Special:Import]]. The radio button is followed by a drop-down list from which the user can select a namespace.\n\nSee also:\n* {{msg-mw|Import-mapping-default}}\n* {{msg-mw|Import-mapping-subpage}}",
+       "import-mapping-subpage": "Used as label for the third of three radio buttons in Import form on [[Special:Import]]. The radio button is followed by a text box in which the user can type a page name. The imported pages will be created as subpages of the entered page name.\n\nSee also:\n* {{msg-mw|Import-mapping-default}}\n* {{msg-mw|Import-mapping-namespace}}",
        "import-upload-filename": "Used on [[Special:Import]] as label for upload of an XML file containing the pages to import.\n{{Identical|Filename}}",
        "import-comment": "Used as label for input box in [[Special:Import]].\n\nSee also:\n* {{msg-mw|Import-interwiki-history}}\n* {{msg-mw|Import-interwiki-templates}}\n* {{msg-mw|Import-interwiki-namespace}}\n* {{msg-mw|Import-interwiki-rootpage}}\n* {{msg-mw|Import-interwiki-submit}}\n{{Identical|Comment}}",
        "importtext": "Used in the Import form on [[Special:Import]].",