* Added tipsy library
authorBrandon Harris <bharris@users.mediawiki.org>
Mon, 1 Nov 2010 21:17:15 +0000 (21:17 +0000)
committerBrandon Harris <bharris@users.mediawiki.org>
Mon, 1 Nov 2010 21:17:15 +0000 (21:17 +0000)
* Added associated files for tooltip display
* Added associated css rules for tooltip display
* Updated installer's help system in (most?) places to display help as tooltips instead of show/hide system
* Beginnings of visual changes (e.g., less boxes, more color)
* Modified several of the installer's widget display methods
* Added a couple new i18n values
* Fixed small bug in installer logic:
  - Password validation on new users was being executed even if there wasn't a $user object

15 files changed:
includes/installer/DatabaseInstaller.php
includes/installer/MysqlInstaller.php
includes/installer/OracleInstaller.php
includes/installer/PostgresInstaller.php
includes/installer/SqliteInstaller.php
includes/installer/WebInstaller.php
includes/installer/WebInstallerOutput.php
includes/installer/WebInstallerPage.php
resources/jquery/jquery.tipsy.js [new file with mode: 0644]
skins/common/config.css
skins/common/config.js
skins/common/images/help-question-hover.gif [new file with mode: 0644]
skins/common/images/help-question.gif [new file with mode: 0644]
skins/common/images/tipsy-arrow.gif [new file with mode: 0644]
skins/common/shared.css

index b637495..dc6b9fd 100644 (file)
@@ -8,7 +8,7 @@
 
 /**
  * Base class for DBMS-specific installation helper classes.
- * 
+ *
  * @ingroup Deployment
  * @since 1.17
  */
@@ -16,30 +16,30 @@ abstract class DatabaseInstaller {
        
        /**
         * The Installer object.
-        * 
+        *
         * TODO: naming this parent is confusing, 'installer' would be clearer.
-        * 
+        *
         * @var Installer
         */
        public $parent;
 
        /**
         * The database connection.
-        * 
+        *
         * @var DatabaseBase
         */
        public $db;
 
        /**
         * Internal variables for installation.
-        * 
+        *
         * @var array
         */
        protected $internalDefaults = array();
 
        /**
         * Array of MW configuration globals this class uses.
-        * 
+        *
         * @var array
         */
        protected $globalNames = array();
@@ -56,7 +56,7 @@ abstract class DatabaseInstaller {
 
        /**
         * Get HTML for a web form that configures this database. Configuration
-        * at this time should be the minimum needed to connect and test 
+        * at this time should be the minimum needed to connect and test
         * whether install or upgrade is required.
         *
         * If this is called, $this->parent can be assumed to be a WebInstaller.
@@ -65,7 +65,7 @@ abstract class DatabaseInstaller {
 
        /**
         * Set variables based on the request array, assuming it was submitted
-        * via the form returned by getConnectForm(). Validate the connection 
+        * via the form returned by getConnectForm(). Validate the connection
         * settings by attempting to connect with them.
         *
         * If this is called, $this->parent can be assumed to be a WebInstaller.
@@ -77,7 +77,7 @@ abstract class DatabaseInstaller {
        /**
         * Get HTML for a web form that retrieves settings used for installation.
         * $this->parent can be assumed to be a WebInstaller.
-        * If the DB type has no settings beyond those already configured with 
+        * If the DB type has no settings beyond those already configured with
         * getConnectForm(), this should return false.
         */
        public function getSettingsForm() {
@@ -87,7 +87,7 @@ abstract class DatabaseInstaller {
        /**
         * Set variables based on the request array, assuming it was submitted via
         * the form return by getSettingsForm().
-        * 
+        *
         * @return Status
         */
        public function submitSettingsForm() {
@@ -96,7 +96,7 @@ abstract class DatabaseInstaller {
 
        /**
         * Connect to the database using the administrative user/password currently
-        * defined in the session. On success, return the connection, on failure, 
+        * defined in the session. On success, return the connection, on failure,
         * return a Status object.
         *
         * This may be called multiple times, so the result should be cached.
@@ -113,7 +113,7 @@ abstract class DatabaseInstaller {
 
        /**
         * Create database tables from scratch.
-        * 
+        *
         * @return Status
         */
        public function createTables() {
@@ -138,7 +138,7 @@ abstract class DatabaseInstaller {
 
        /**
         * Get the DBMS-specific options for LocalSettings.php generation.
-        * 
+        *
         * @return String
         */
        public abstract function getLocalSettings();
@@ -187,19 +187,19 @@ abstract class DatabaseInstaller {
         */
        public function getGlobalNames() {
                return $this->globalNames;
-       }               
+       }
 
        /**
         * Return any table options to be applied to all tables that don't
         * override them.
-        * 
+        *
         * @return Array
         */
        public function getTableOptions() {
                return array();
        }
 
-       /** 
+       /**
         * Construct and initialise parent.
         * This is typically only called from Installer::getDBInstaller()
         */
@@ -210,7 +210,7 @@ abstract class DatabaseInstaller {
        /**
         * Convenience function.
         * Check if a named extension is present.
-        * 
+        *
         * @see wfDl
         */
        protected static function checkExtension( $name ) {
@@ -266,15 +266,19 @@ abstract class DatabaseInstaller {
        /**
         * Get a labelled text box to configure a local variable.
         */
-       public function getTextBox( $var, $label, $attribs = array() ) {
+       public function getTextBox( $var, $label, $attribs = array(), $helpData = "" ) {
                $name = $this->getName() . '_' . $var;
                $value = $this->getVar( $var );
+               if ( !isset( $attribs ) ) {
+                   $attribs = array();
+               }
                return $this->parent->getTextBox( array(
                        'var' => $var,
                        'label' => $label,
                        'attribs' => $attribs,
                        'controlName' => $name,
-                       'value' => $value
+                       'value' => $value,
+                   'help' => $helpData
                ) );
        }
 
@@ -282,22 +286,26 @@ abstract class DatabaseInstaller {
         * Get a labelled password box to configure a local variable.
         * Implements password hiding.
         */
-       public function getPasswordBox( $var, $label, $attribs = array() ) {
+       public function getPasswordBox( $var, $label, $attribs = array(), $helpData = "" ) {
                $name = $this->getName() . '_' . $var;
                $value = $this->getVar( $var );
+               if ( !isset( $attribs ) ) {
+                   $attribs = array();
+               }
                return $this->parent->getPasswordBox( array(
                        'var' => $var,
                        'label' => $label,
                        'attribs' => $attribs,
                        'controlName' => $name,
-                       'value' => $value
+                       'value' => $value,
+                   'help' => $helpData
                ) );
        }
 
        /**
         * Get a labelled checkbox to configure a local boolean variable.
         */
-       public function getCheckBox( $var, $label, $attribs = array() ) {
+       public function getCheckBox( $var, $label, $attribs = array(), $helpData = "" ) {
                $name = $this->getName() . '_' . $var;
                $value = $this->getVar( $var );
                return $this->parent->getCheckBox( array(
@@ -306,6 +314,7 @@ abstract class DatabaseInstaller {
                        'attribs' => $attribs,
                        'controlName' => $name,
                        'value' => $value,
+                   'help' => $helpData
                ));
        }
 
@@ -338,11 +347,11 @@ abstract class DatabaseInstaller {
        }
 
        /**
-        * Determine whether an existing installation of MediaWiki is present in 
-        * the configured administrative connection. Returns true if there is 
+        * Determine whether an existing installation of MediaWiki is present in
+        * the configured administrative connection. Returns true if there is
         * such a wiki, false if the database doesn't exist.
         *
-        * Traditionally, this is done by testing for the existence of either 
+        * Traditionally, this is done by testing for the existence of either
         * the revision table or the cur table.
         *
         * @return Boolean
@@ -366,9 +375,8 @@ abstract class DatabaseInstaller {
                return
                        Xml::openElement( 'fieldset' ) .
                        Xml::element( 'legend', array(), wfMsg( 'config-db-install-account' ) ) .
-                       $this->getTextBox( '_InstallUser', 'config-db-username' ) .
-                       $this->getPasswordBox( '_InstallPassword', 'config-db-password' ) .
-                       $this->parent->getHelpBox( 'config-db-install-help' ) .
+                       $this->getTextBox( '_InstallUser', 'config-db-username', array(), $this->parent->getHelpBox( 'config-db-install-username' ) ) .
+                       $this->getPasswordBox( '_InstallPassword', 'config-db-password', array(), $this->parent->getHelpBox( 'config-db-install-password' ) ) .
                        Xml::closeElement( 'fieldset' );
        }
 
@@ -389,7 +397,7 @@ abstract class DatabaseInstaller {
                $name = $this->getName();
                $s = Xml::openElement( 'fieldset' ) .
                        Xml::element( 'legend', array(), wfMsg( 'config-db-web-account' ) ) .
-                       $this->getCheckBox( 
+                       $this->getCheckBox(
                                '_SameAccount', 'config-db-web-account-same',
                                array( 'class' => 'hideShowRadio', 'rel' => 'dbOtherAccount' )
                        ) .
@@ -408,7 +416,7 @@ abstract class DatabaseInstaller {
 
        /**
         * Submit the form from getWebUserBox().
-        * 
+        *
         * @return Status
         */
        public function submitWebUserBox() {
index d4af144..362810b 100644 (file)
@@ -8,7 +8,7 @@
 
 /**
  * Class for setting up the MediaWiki database using MySQL.
- * 
+ *
  * @ingroup Deployment
  * @since 1.17
  */
@@ -59,14 +59,11 @@ class MysqlInstaller extends DatabaseInstaller {
 
        public function getConnectForm() {
                return
-                       $this->getTextBox( 'wgDBserver', 'config-db-host' ) .
-                       $this->parent->getHelpBox( 'config-db-host-help' ) . 
+                       $this->getTextBox( 'wgDBserver', 'config-db-host', array(), $this->parent->getHelpBox( 'config-db-host-help' ) ) .
                        Xml::openElement( 'fieldset' ) .
                        Xml::element( 'legend', array(), wfMsg( 'config-db-wiki-settings' ) ) .
-                       $this->getTextBox( 'wgDBname', 'config-db-name' ) .
-                       $this->parent->getHelpBox( 'config-db-name-help' ) .
-                       $this->getTextBox( 'wgDBprefix', 'config-db-prefix' ) .
-                       $this->parent->getHelpBox( 'config-db-prefix-help' ) .
+                       $this->getTextBox( 'wgDBname', 'config-db-name', array(), $this->parent->getHelpBox( 'config-db-name-help' ) ) .
+                       $this->getTextBox( 'wgDBprefix', 'config-db-prefix', array(), $this->parent->getHelpBox( 'config-db-prefix-help' ) ) .
                        Xml::closeElement( 'fieldset' ) .
                        $this->getInstallUserBox();
        }
@@ -120,7 +117,7 @@ class MysqlInstaller extends DatabaseInstaller {
                                $this->getVar( '_InstallPassword' ),
                                false,
                                false,
-                               0, 
+                               0,
                                $this->getVar( 'wgDBprefix' )
                        );
                        $status->value = $this->db;
@@ -252,12 +249,12 @@ class MysqlInstaller extends DatabaseInstaller {
                if ( count( $parts ) != 2 ) {
                        return false;
                }
-               $quotedUser = $conn->addQuotes( $parts[0] ) . 
+               $quotedUser = $conn->addQuotes( $parts[0] ) .
                        '@' . $conn->addQuotes( $parts[1] );
 
                // The user needs to have INSERT on mysql.* to be able to CREATE USER
                // The grantee will be double-quoted in this query, as required
-               $res = $conn->select( 'INFORMATION_SCHEMA.USER_PRIVILEGES', '*', 
+               $res = $conn->select( 'INFORMATION_SCHEMA.USER_PRIVILEGES', '*',
                        array( 'GRANTEE' => $quotedUser ), __METHOD__ );
                $insertMysql = false;
                $grantOptions = array_flip( $this->webUserPrivs );
@@ -273,7 +270,7 @@ class MysqlInstaller extends DatabaseInstaller {
                // Check for DB-specific privs for mysql.*
                if ( !$insertMysql ) {
                        $row = $conn->selectRow( 'INFORMATION_SCHEMA.SCHEMA_PRIVILEGES', '*',
-                               array( 
+                               array(
                                        'GRANTEE' => $quotedUser,
                                        'TABLE_SCHEMA' => 'mysql',
                                        'PRIVILEGE_TYPE' => 'INSERT',
@@ -288,7 +285,7 @@ class MysqlInstaller extends DatabaseInstaller {
                }
 
                // Check for DB-level grant options
-               $res = $conn->select( 'INFORMATION_SCHEMA.SCHEMA_PRIVILEGES', '*', 
+               $res = $conn->select( 'INFORMATION_SCHEMA.SCHEMA_PRIVILEGES', '*',
                        array(
                                'GRANTEE' => $quotedUser,
                                'IS_GRANTABLE' => 1,
@@ -322,9 +319,9 @@ class MysqlInstaller extends DatabaseInstaller {
                }
                if ( count( $engines ) >= 2 ) {
                        $s .= $this->getRadioSet( array(
-                               'var' => '_MysqlEngine', 
-                               'label' => 'config-mysql-engine', 
-                               'itemLabelPrefix' => 'config-mysql-', 
+                               'var' => '_MysqlEngine',
+                               'label' => 'config-mysql-engine',
+                               'itemLabelPrefix' => 'config-mysql-',
                                'values' => $engines
                        ));
                        $s .= $this->parent->getHelpBox( 'config-mysql-engine-help' );
@@ -369,13 +366,13 @@ class MysqlInstaller extends DatabaseInstaller {
                if ( !$create ) {
                        // Test the web account
                        try {
-                               $webConn = new Database( 
+                               $webConn = new Database(
                                        $this->getVar( 'wgDBserver' ),
                                        $this->getVar( 'wgDBuser' ),
                                        $this->getVar( 'wgDBpassword' ),
                                        false,
                                        false,
-                                       0, 
+                                       0,
                                        $this->getVar( 'wgDBprefix' )
                                );
                        } catch ( DBConnectionError $e ) {
index d01bb34..2444f90 100644 (file)
@@ -8,7 +8,7 @@
  
 /**
  * Class for setting up the MediaWiki database using Oracle.
- * 
+ *
  * @ingroup Deployment
  * @since 1.17
  */
@@ -47,8 +47,7 @@ class OracleInstaller extends DatabaseInstaller {
                        Xml::element( 'legend', array(), wfMsg( 'config-db-web-account' ) ) .
                        Xml::openElement( 'div', array( 'id' => 'dbOtherAccount' ) ) .
                        $this->getTextBox( 'wgDBuser', 'config-db-username' ) .
-                       $this->getPasswordBox( 'wgDBpassword', 'config-db-password' ) .
-                       $this->parent->getHelpBox( 'config-db-web-help' ).
+                       $this->getPasswordBox( 'wgDBpassword', 'config-db-password', array(), $this->parent->getHelpBox( 'config-db-web-help' ) ) .
                        $this->getCheckBox( '_CreateDBAccount', 'config-db-web-create', array( 'disabled' => true ) ).
                        Xml::closeElement( 'div' ) . Xml::closeElement( 'fieldset' );
        }
@@ -57,14 +56,12 @@ class OracleInstaller extends DatabaseInstaller {
                $this->parent->setVar( '_InstallUser', 'sys' );
                $this->parent->setVar( 'wgDBserver', '' );
                return
-                       $this->getTextBox( 'wgDBserver', 'config-db-host-oracle' ) .
-                       $this->parent->getHelpBox( 'config-db-host-oracle-help' ) . 
+                       $this->getTextBox( 'wgDBserver', 'config-db-host-oracle', array(), $this->parent->getHelpBox( 'config-db-host-oracle-help' ) ) .
                        Xml::openElement( 'fieldset' ) .
                        Xml::element( 'legend', array(), wfMsg( 'config-db-wiki-settings' ) ) .
                        $this->getTextBox( 'wgDBprefix', 'config-db-prefix' ) .
                        $this->getTextBox( '_OracleDefTS', 'config-oracle-def-ts' ) .
-                       $this->getTextBox( '_OracleTempTS', 'config-oracle-temp-ts' ) .
-                       $this->parent->getHelpBox( 'config-db-oracle-help' ) .
+                       $this->getTextBox( '_OracleTempTS', 'config-oracle-temp-ts', array(), $this->parent->getHelpBox( 'config-db-oracle-help' ) ) .
                        Xml::closeElement( 'fieldset' ) .
                        $this->getInstallUserBox().
                        $this->getWebUserBox();
index c0d9677..a63208a 100644 (file)
@@ -8,7 +8,7 @@
  
 /**
  * Class for setting up the MediaWiki database using Postgres.
- * 
+ *
  * @ingroup Deployment
  * @since 1.17
  */
@@ -36,23 +36,20 @@ class PostgresInstaller extends DatabaseInstaller {
 
        function getConnectForm() {
                return
-                       $this->getTextBox( 'wgDBserver', 'config-db-host' ) .
-                       $this->parent->getHelpBox( 'config-db-host-help' ) . 
+                       $this->getTextBox( 'wgDBserver', 'config-db-host', array(), $this->parent->getHelpBox( 'config-db-host-help' ) ) .
                        $this->getTextBox( 'wgDBport', 'config-db-port' ) .
                        Xml::openElement( 'fieldset' ) .
                        Xml::element( 'legend', array(), wfMsg( 'config-db-wiki-settings' ) ) .
-                       $this->getTextBox( 'wgDBname', 'config-db-name' ) .
-                       $this->parent->getHelpBox( 'config-db-name-help' ) .
-                       $this->getTextBox( 'wgDBmwschema', 'config-db-schema' ) .
+                       $this->getTextBox( 'wgDBname', 'config-db-name', array(), $this->parent->getHelpBox( 'config-db-name-help' ) ) .
+                       $this->getTextBox( 'wgDBmwschema', 'config-db-schema', array(), $this->parent->getHelpBox( 'config-db-schema-help' ) ) .
                        $this->getTextBox( 'wgDBts2schema', 'config-db-ts2-schema' ) .
-                       $this->parent->getHelpBox( 'config-db-schema-help' ) .
                        Xml::closeElement( 'fieldset' ) .
                        $this->getInstallUserBox();
        }
 
        function submitConnectForm() {
                // Get variables from the request
-               $newValues = $this->setVarsFromRequest( array( 'wgDBserver', 'wgDBport', 
+               $newValues = $this->setVarsFromRequest( array( 'wgDBserver', 'wgDBport',
                        'wgDBname', 'wgDBmwschema', 'wgDBts2schema' ) );
 
                // Validate them
index 4dccdd1..d191f6e 100644 (file)
@@ -8,7 +8,7 @@
  
 /**
  * Class for setting up the MediaWiki database using SQLLite.
- * 
+ *
  * @ingroup Deployment
  * @since 1.17
  */
@@ -41,10 +41,8 @@ class SqliteInstaller extends DatabaseInstaller {
        }
 
        public function getConnectForm() {
-               return $this->getTextBox( 'wgSQLiteDataDir', 'config-sqlite-dir' ) .
-                       $this->parent->getHelpBox( 'config-sqlite-dir-help' ) .
-                       $this->getTextBox( 'wgDBname', 'config-db-name' ) .
-                       $this->parent->getHelpBox( 'config-sqlite-name-help' );
+               return $this->getTextBox( 'wgSQLiteDataDir', 'config-sqlite-dir', array(), $this->parent->getHelpBox( 'config-sqlite-dir-help' ) ) .
+                       $this->getTextBox( 'wgDBname', 'config-db-name', array(), $this->parent->getHelpBox( 'config-sqlite-name-help' ) );
        }
 
        public function submitConnectForm() {
index 9e2f192..5921e52 100644 (file)
@@ -605,23 +605,14 @@ class WebInstaller extends CoreInstaller {
                array_shift( $args );
                $args = array_map( 'htmlspecialchars', $args );
                $text = wfMsgReal( $msg, $args, false, false, false );
-               $html = $this->parse( $text, true );
-
+               //$html = $this->parse( $text, true );
+    $html = $text;
                return
-                       "<div class=\"config-help-wrapper\">\n" .
-                       "<div class=\"config-help-message\">\n" .
-                        $html .
-                       "</div>\n" .
-                       "<div class=\"config-show-help\">\n" .
-                       "<a href=\"#\">" .
-                       wfMsgHtml( 'config-show-help' ) .
-                       "</a></div>\n" .
-                       "<div class=\"config-hide-help\">\n" .
-                       "<a href=\"#\">" .
-                       wfMsgHtml( 'config-hide-help' ) .
-                       "</a></div>\n</div>\n";
+            "<span class=\"mw-help-field-hint\"\n" .
+           "     title=\"" . $html . "\"\n" .
+           "     original-title=\"" . $html . "\"></span>\n";
        }
-
+       
        /**
         * Output a help box.
         */
@@ -662,7 +653,7 @@ class WebInstaller extends CoreInstaller {
         * Label a control by wrapping a config-input div around it and putting a
         * label before it.
         */
-       public function label( $msg, $forId, $contents ) {
+       public function label( $msg, $forId, $contents, $helpData = "" ) {
                if ( strval( $msg ) == '' ) {
                        $labelText = '&#160;';
                } else {
@@ -676,14 +667,19 @@ class WebInstaller extends CoreInstaller {
                }
 
                return
-                       "<div class=\"config-input\">\n" .
+                       "<div class=\"config-block\">\n" .
+                   "  <div class=\"config-block-label\">\n" .
                        Xml::tags( 'label',
                                $attributes,
                                $labelText ) . "\n" .
-                       $contents .
+                           $helpData .
+                       "  </div>\n" .
+                   "  <div class=\"config-block-elements\">\n" .
+                           $contents .
+                       "  </div>\n" .
                        "</div>\n";
        }
-
+       
        /**
         * Get a labelled text box to configure a variable.
         *
@@ -694,6 +690,7 @@ class WebInstaller extends CoreInstaller {
         *      attribs:    Additional attributes for the input element (optional)
         *      controlName: The name for the input element (optional)
         *      value:      The current value of the variable (optional)
+        *      help:           The html for the help text (optional)
         */
        public function getTextBox( $params ) {
                if ( !isset( $params['controlName'] ) ) {
@@ -707,7 +704,9 @@ class WebInstaller extends CoreInstaller {
                if ( !isset( $params['attribs'] ) ) {
                        $params['attribs'] = array();
                }
-
+               if ( !isset( $params['help'] ) ) {
+                       $params['help'] = "";
+               }
                return
                        $this->label(
                                $params['label'],
@@ -721,10 +720,11 @@ class WebInstaller extends CoreInstaller {
                                                'class' => 'config-input-text',
                                                'tabindex' => $this->nextTabIndex()
                                        )
-                               )
+                               ),
+                               $params['help']
                        );
        }
-
+       
        /**
         * Get a labelled password box to configure a variable.
         *
@@ -736,6 +736,7 @@ class WebInstaller extends CoreInstaller {
         *      attribs:    Additional attributes for the input element (optional)
         *      controlName: The name for the input element (optional)
         *      value:      The current value of the variable (optional)
+        *      help:           The html for the help text (optional)
         */
        public function getPasswordBox( $params ) {
                if ( !isset( $params['value'] ) ) {
@@ -762,6 +763,7 @@ class WebInstaller extends CoreInstaller {
         *      attribs:    Additional attributes for the input element (optional)
         *      controlName: The name for the input element (optional)
         *      value:      The current value of the variable (optional)
+        *      help:           The html for the help text (optional)
         */
        public function getCheckBox( $params ) {
                if ( !isset( $params['controlName'] ) ) {
@@ -775,7 +777,9 @@ class WebInstaller extends CoreInstaller {
                if ( !isset( $params['attribs'] ) ) {
                        $params['attribs'] = array();
                }
-
+               if ( !isset( $params['help'] ) ) {
+                       $params['help'] = "";
+               }
                if( isset( $params['rawtext'] ) ) {
                        $labelText = $params['rawtext'];
                } else {
@@ -796,6 +800,7 @@ class WebInstaller extends CoreInstaller {
                        ) .
                        $labelText . "\n" .
                        "</label>\n" .
+                       $params['help'] .
                        "</div>\n";
        }
 
@@ -812,6 +817,7 @@ class WebInstaller extends CoreInstaller {
         *      commonAttribs   Attribute array applied to all items
         *      controlName:    The name for the input element (optional)
         *      value:          The current value of the variable (optional)
+        *      help:           The html for the help text (optional)
         */
        public function getRadioSet( $params ) {
                if ( !isset( $params['controlName']  ) ) {
@@ -825,13 +831,12 @@ class WebInstaller extends CoreInstaller {
                if ( !isset( $params['label'] ) ) {
                        $label = '';
                } else {
-                       $label = $this->parse( wfMsgNoTrans( $params['label'] ) );
+                       $label = $params['label'];
                }
-
-               $s = "<label class=\"config-label\">\n" .
-                       $label .
-                       "</label>\n" .
-                       "<ul class=\"config-settings-block\">\n";
+               if ( !isset( $params['help'] ) ) {
+                       $params['help'] = "";
+               }
+               $s = "<ul>\n";
                foreach ( $params['values'] as $value ) {
                        $itemAttribs = array();
 
@@ -859,7 +864,8 @@ class WebInstaller extends CoreInstaller {
                }
 
                $s .= "</ul>\n";
-               return $s;
+
+               return $this->label( $label, $params['controlName'], $s, $params['help'] );
        }
 
        /**
index a3677d2..58bbac9 100644 (file)
@@ -9,11 +9,11 @@
 /**
  * Output class modelled on OutputPage.
  *
- * I've opted to use a distinct class rather than derive from OutputPage here in 
- * the interests of separation of concerns: if we used a subclass, there would be 
- * quite a lot of things you could do in OutputPage that would break the installer, 
- * that wouldn't be immediately obvious. 
- * 
+ * I've opted to use a distinct class rather than derive from OutputPage here in
+ * the interests of separation of concerns: if we used a subclass, there would be
+ * quite a lot of things you could do in OutputPage that would break the installer,
+ * that wouldn't be immediately obvious.
+ *
  * @ingroup Deployment
  * @since 1.17
  */
@@ -21,9 +21,9 @@ class WebInstallerOutput {
        
        /**
         * The WebInstaller object this WebInstallerOutput is used by.
-        * 
+        *
         * @var WebInstaller
-        */     
+        */
        public $parent;
        
        public $contents = '';
@@ -35,7 +35,7 @@ class WebInstallerOutput {
 
        /**
         * Constructor.
-        * 
+        *
         * @param $parent WebInstaller
         */
        public function __construct( WebInstaller $parent ) {
@@ -145,6 +145,7 @@ class WebInstallerOutput {
        <?php echo Html::linkedStyle( '../skins/common/config.css' ) . "\n"; ?>
        <?php echo Html::inlineScript(  "var dbTypes = " . Xml::encodeJsVar( $dbTypes ) ) . "\n"; ?>
        <?php echo $this->getJQuery() . "\n"; ?>
+       <?php echo $this->getJQueryTipsy() . "\n"; ?>
        <?php echo Html::linkedScript( '../skins/common/config.js' ) . "\n"; ?>
 </head>
 
@@ -209,6 +210,7 @@ class WebInstallerOutput {
        <?php echo Html::linkedStyle( '../skins/monobook/main.css' ) . "\n"; ?>
        <?php echo Html::linkedStyle( '../skins/common/config.css' ) . "\n"; ?>
        <?php echo $this->getJQuery(); ?>
+       <?php echo $this->getJQueryTipsy() . "\n"; ?>
        <?php echo Html::linkedScript( '../skins/common/config.js' ); ?>
 </head>
 
@@ -224,7 +226,10 @@ class WebInstallerOutput {
        public function getJQuery() {
                return Html::linkedScript( "../resources/jquery/jquery.js" );
        }
-
+       public function getJQueryTipsy() {
+               return Html::linkedScript( "../resources/jquery/jquery.tipsy.js" );
+       }
+       
        public function outputWarnings() {
                $this->addHTML( $this->warnings );
                $this->warnings = '';
index 732d08b..3e1d685 100644 (file)
@@ -8,7 +8,7 @@
 
 /**
  * Abstract class to define pages for the web installer.
- * 
+ *
  * @ingroup Deployment
  * @since 1.17
  */
@@ -16,7 +16,7 @@ abstract class WebInstallerPage {
        
        /**
         * The WebInstaller object this WebInstallerPage belongs to.
-        * 
+        *
         * @var WebInstaller
         */
        public $parent;
@@ -25,7 +25,7 @@ abstract class WebInstallerPage {
        
        /**
         * Constructor.
-        * 
+        *
         * @param $parent WebInstaller
         */
        public function __construct( WebInstaller $parent ) {
@@ -216,13 +216,15 @@ class WebInstaller_Language extends WebInstallerPage {
                }
                $this->startForm();
                $s = Html::hidden( 'LanguageRequestTime', time() ) .
-                       $this->getLanguageSelector( 'UserLang', 'config-your-language', $userLang ) .
-                       $this->parent->getHelpBox( 'config-your-language-help' ) .
-                       $this->getLanguageSelector( 'ContLang', 'config-wiki-language', $contLang ) .
-                       $this->parent->getHelpBox( 'config-wiki-language-help' ) .
-                       $this->parent->getCheckBox( 
-                               array( 'var' => '_ExternalHTTP', 'label' => 'config-allow-requests' )
-                       ) . $this->parent->getHelpBox( 'config-allow-requests-help' );
+                       $this->getLanguageSelector( 'UserLang', 'config-your-language', $userLang, $this->parent->getHelpBox( 'config-your-language-help' ) ) .
+                       $this->getLanguageSelector( 'ContLang', 'config-wiki-language', $contLang, $this->parent->getHelpBox( 'config-wiki-language-help' ) ) .
+                       $this->parent->getCheckBox(
+                               array(
+                                       'var' => '_ExternalHTTP',
+                                       'label' => 'config-allow-requests',
+                                   'help' => $this->parent->getHelpBox( 'config-allow-requests-help' )
+                               )
+                       );
 
                $this->addHTML( $s );
                $this->endForm();
@@ -259,7 +261,7 @@ class WebInstaller_Welcome extends WebInstallerPage {
                $this->parent->output->addWikiText( wfMsgNoTrans( 'config-welcome' ) );
                $status = $this->parent->doEnvironmentChecks();
                if ( $status ) {
-                       $this->parent->output->addWikiText( wfMsgNoTrans( 'config-copyright', 
+                       $this->parent->output->addWikiText( wfMsgNoTrans( 'config-copyright',
                                SpecialVersion::getCopyrightAndAuthorList() ) );
                        $this->startForm();
                        $this->endForm();
@@ -291,7 +293,7 @@ class WebInstaller_DBConnect extends WebInstallerPage {
                $dbSupport = '';
                foreach( $this->parent->getDBTypes() as $type ) {
                        $db = 'Database' . ucfirst( $type );
-                       $dbSupport .= wfMsgNoTrans( "config-support-$type", 
+                       $dbSupport .= wfMsgNoTrans( "config-support-$type",
                                call_user_func( array( $db, 'getSoftwareLink' ) ) ) . "\n";
                }
                $this->addHTML( $this->parent->getInfoBox(
@@ -460,21 +462,22 @@ class WebInstaller_Name extends WebInstallerPage {
                        $this->parent->getTextBox( array(
                                'var' => 'wgSitename',
                                'label' => 'config-site-name',
+                         'help' => $this->parent->getHelpBox( 'config-site-name-help' )
                        ) ) .
-                       $this->parent->getHelpBox( 'config-site-name-help' ) .
                        $this->parent->getRadioSet( array(
                                'var' => '_NamespaceType',
                                'label' => 'config-project-namespace',
                                'itemLabelPrefix' => 'config-ns-',
                                'values' => array( 'site-name', 'generic', 'other' ),
                                'commonAttribs' => array( 'class' => 'enableForOther', 'rel' => 'config_wgMetaNamespace' ),
+                               'help' => $this->parent->getHelpBox( 'config-project-namespace-help' )
                        ) ) .
                        $this->parent->getTextBox( array(
                                'var' => 'wgMetaNamespace',
                                'label' => '',
                                'attribs' => array( 'disabled' => '' ),
+                           
                        ) ) .
-                       $this->parent->getHelpBox( 'config-project-namespace-help' ) .
                        $this->getFieldSetStart( 'config-admin-box' ) .
                        $this->parent->getTextBox( array(
                                'var' => '_AdminName',
@@ -483,22 +486,22 @@ class WebInstaller_Name extends WebInstallerPage {
                        $this->parent->getPasswordBox( array(
                                'var' => '_AdminPassword',
                                'label' => 'config-admin-password',
+                           'help' => $this->parent->getHelpBox( 'config-admin-help' )
                        ) ) .
                        $this->parent->getPasswordBox( array(
                                'var' => '_AdminPassword2',
                                'label' => 'config-admin-password-confirm'
                        ) ) .
-                       $this->parent->getHelpBox( 'config-admin-help' ) .
                        $this->parent->getTextBox( array(
                                'var' => '_AdminEmail',
-                               'label' => 'config-admin-email'
+                               'label' => 'config-admin-email',
+                           'help' => $this->parent->getHelpBox( 'config-admin-email-help' )
                        ) ) .
-                       $this->parent->getHelpBox( 'config-admin-email-help' ) .
                        $this->parent->getCheckBox( array(
                                'var' => '_Subscribe',
-                               'label' => 'config-subscribe'
+                               'label' => 'config-subscribe',
+                           'help' => $this->parent->getHelpBox( 'config-subscribe-help' )
                        ) ) .
-                       $this->parent->getHelpBox( 'config-subscribe-help' ) .
                        $this->getFieldSetEnd() .
                        $this->parent->getInfoBox( wfMsg( 'config-almost-done' ) ) .
                        $this->parent->getRadioSet( array(
@@ -580,9 +583,12 @@ class WebInstaller_Name extends WebInstallerPage {
 
                // Validate password
                $msg = false;
+               $valid = false;
                $pwd = $this->getVar( '_AdminPassword' );
                $user = User::newFromName( $cname );
-               $valid = $user->getPasswordValidity( $pwd );
+               if ( ( isset ( $pwd ) ) && ( $user != null ) ) {
+               $valid = $user->getPasswordValidity( $pwd );
+               }
                if ( strval( $pwd ) === '' ) {
                        # $user->getPasswordValidity just checks for $wgMinimalPasswordLength.
                        # This message is more specific and helpful.
@@ -690,31 +696,31 @@ class WebInstaller_Options extends WebInstallerPage {
                        }
                        
                        $extHtml .= $this->parent->getHelpBox( 'config-extensions-help' ) .
-                               $this->getFieldSetEnd();
+                       $this->getFieldSetEnd();
                        $this->addHTML( $extHtml );
                }
 
                $this->addHTML(
                        # Uploading
                        $this->getFieldSetStart( 'config-upload-settings' ) .
-                       $this->parent->getCheckBox( array( 
+                       $this->parent->getCheckBox( array(
                                'var' => 'wgEnableUploads',
                                'label' => 'config-upload-enable',
                                'attribs' => array( 'class' => 'showHideRadio', 'rel' => 'uploadwrapper' ),
+                           'help' => $this->parent->getHelpBox( 'config-upload-help' )
                        ) ) .
-                       $this->parent->getHelpBox( 'config-upload-help' ) .
                        '<div id="uploadwrapper" style="display: none;">' .
-                       $this->parent->getTextBox( array( 
+                       $this->parent->getTextBox( array(
                                'var' => 'wgDeletedDirectory',
                                'label' => 'config-upload-deleted',
+                           'help' => $this->parent->getHelpBox( 'config-upload-deleted-help' )
                        ) ) .
-                       $this->parent->getHelpBox( 'config-upload-deleted-help' ) .
                        '</div>' .
                        $this->parent->getTextBox( array(
                                'var' => 'wgLogo',
-                               'label' => 'config-logo'
-                       ) ) .
-                       $this->parent->getHelpBox( 'config-logo-help' )
+                               'label' => 'config-logo',
+                           'help' => $this->parent->getHelpBox( 'config-logo-help' )
+                       ) )
                );
                $canUse = $this->getVar( '_ExternalHTTP' ) ?
                        'config-instantcommons-good' : 'config-instantcommons-bad';
@@ -722,8 +728,8 @@ class WebInstaller_Options extends WebInstallerPage {
                        $this->parent->getCheckBox( array(
                                'var' => 'wgUseInstantCommons',
                                'label' => 'config-instantcommons',
+                           'help' => $this->parent->getHelpBox( 'config-instantcommons-help', wfMsgNoTrans( $canUse ) )
                        ) ) .
-                       $this->parent->getHelpBox( 'config-instantcommons-help', wfMsgNoTrans( $canUse ) ) .
                        $this->getFieldSetEnd()
                );
 
@@ -749,8 +755,9 @@ class WebInstaller_Options extends WebInstallerPage {
                        $this->parent->getTextBox( array(
                                'var' => '_MemCachedServers',
                                'label' => 'config-memcached-servers',
+                               'help' => $this->parent->getHelpBox( 'config-memcached-help' )
                        ) ) .
-                       $this->parent->getHelpBox( 'config-memcached-help' ) . '</div>' .
+                       '</div>' .
                        $this->getFieldSetEnd()
                );
                $this->endForm();
diff --git a/resources/jquery/jquery.tipsy.js b/resources/jquery/jquery.tipsy.js
new file mode 100644 (file)
index 0000000..60e5356
--- /dev/null
@@ -0,0 +1,202 @@
+// tipsy, facebook style tooltips for jquery
+// version 1.0.0a
+// (c) 2008-2010 jason frame [jason@onehackoranother.com]
+// released under the MIT license
+
+(function($) {
+               
+               function Tipsy(element, options) {
+                               this.$element = $(element);
+                               this.options = options;
+                               this.enabled = true;
+                               this.fixTitle();
+               }
+               
+               Tipsy.prototype = {
+                               show: function() {
+                                               var title = this.getTitle();
+                                               if (title && this.enabled) {
+                                                               var $tip = this.tip();
+                                                               
+                                                               $tip.find('.tipsy-inner')[this.options.html ? 'html' : 'text'](title);
+                                                               $tip[0].className = 'tipsy'; // reset classname in case of dynamic gravity
+                                                               $tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).appendTo(document.body);
+                                                               
+                                                               var pos = $.extend({}, this.$element.offset(), {
+                                                                               width: this.$element[0].offsetWidth,
+                                                                               height: this.$element[0].offsetHeight
+                                                               });
+                                                               
+                                                               var actualWidth = $tip[0].offsetWidth, actualHeight = $tip[0].offsetHeight;
+                                                               var gravity = (typeof this.options.gravity == 'function')
+                                                                                                                               ? this.options.gravity.call(this.$element[0])
+                                                                                                                               : this.options.gravity;
+                                                               
+                                                               var tp;
+                                                               switch (gravity.charAt(0)) {
+                                                                               case 'n':
+                                                                                               tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2};
+                                                                                               break;
+                                                                               case 's':
+                                                                                               tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2};
+                                                                                               break;
+                                                                               case 'e':
+                                                                                               tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset};
+                                                                                               break;
+                                                                               case 'w':
+                                                                                               tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset};
+                                                                                               break;
+                                                               }
+                                                               
+                                                               if (gravity.length == 2) {
+                                                                               if (gravity.charAt(1) == 'w') {
+                                                                                               tp.left = pos.left + pos.width / 2 - 15;
+                                                                               } else {
+                                                                                               tp.left = pos.left + pos.width / 2 - actualWidth + 15;
+                                                                               }
+                                                               }
+                                                               
+                                                               $tip.css(tp).addClass('tipsy-' + gravity);
+                                                               
+                                                               if (this.options.fade) {
+                                                                               $tip.stop().css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: this.options.opacity});
+                                                               } else {
+                                                                               $tip.css({visibility: 'visible', opacity: this.options.opacity});
+                                                               }
+                                               }
+                               },
+                               
+                               hide: function() {
+                                               if (this.options.fade) {
+                                                               this.tip().stop().fadeOut(function() { $(this).remove(); });
+                                               } else {
+                                                               this.tip().remove();
+                                               }
+                               },
+                               
+                               fixTitle: function() {
+                                               var $e = this.$element;
+                                               if ($e.attr('title') || typeof($e.attr('original-title')) != 'string') {
+                                                               $e.attr('original-title', $e.attr('title') || '').removeAttr('title');
+                                               }
+                               },
+                               
+                               getTitle: function() {
+                                               var title, $e = this.$element, o = this.options;
+                                               this.fixTitle();
+                                               var title, o = this.options;
+                                               if (typeof o.title == 'string') {
+                                                               title = $e.attr(o.title == 'title' ? 'original-title' : o.title);
+                                               } else if (typeof o.title == 'function') {
+                                                               title = o.title.call($e[0]);
+                                               }
+                                               title = ('' + title).replace(/(^\s*|\s*$)/, "");
+                                               return title || o.fallback;
+                               },
+                               
+                               tip: function() {
+                                               if (!this.$tip) {
+                                                               this.$tip = $('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>');
+                                               }
+                                               return this.$tip;
+                               },
+                               
+                               validate: function() {
+                                               if (!this.$element[0].parentNode) {
+                                                               this.hide();
+                                                               this.$element = null;
+                                                               this.options = null;
+                                               }
+                               },
+                               
+                               enable: function() { this.enabled = true; },
+                               disable: function() { this.enabled = false; },
+                               toggleEnabled: function() { this.enabled = !this.enabled; }
+               };
+               
+               $.fn.tipsy = function(options) {
+                               
+                               if (options === true) {
+                                               return this.data('tipsy');
+                               } else if (typeof options == 'string') {
+                                               var tipsy = this.data('tipsy');
+                                               if (tipsy) tipsy[options]();
+                                               return this;
+                               }
+                               
+                               options = $.extend({}, $.fn.tipsy.defaults, options);
+                               
+                               function get(ele) {
+                                               var tipsy = $.data(ele, 'tipsy');
+                                               if (!tipsy) {
+                                                               tipsy = new Tipsy(ele, $.fn.tipsy.elementOptions(ele, options));
+                                                               $.data(ele, 'tipsy', tipsy);
+                                               }
+                                               return tipsy;
+                               }
+                               
+                               function enter() {
+                                               var tipsy = get(this);
+                                               tipsy.hoverState = 'in';
+                                               if (options.delayIn == 0) {
+                                                               tipsy.show();
+                                               } else {
+                                                               tipsy.fixTitle();
+                                                               setTimeout(function() { if (tipsy.hoverState == 'in') tipsy.show(); }, options.delayIn);
+                                               }
+                               };
+                               
+                               function leave() {
+                                               var tipsy = get(this);
+                                               tipsy.hoverState = 'out';
+                                               if (options.delayOut == 0) {
+                                                               tipsy.hide();
+                                               } else {
+                                                               setTimeout(function() { if (tipsy.hoverState == 'out') tipsy.hide(); }, options.delayOut);
+                                               }
+                               };
+                               
+                               if (!options.live) this.each(function() { get(this); });
+                               
+                               if (options.trigger != 'manual') {
+                                               var binder       = options.live ? 'live' : 'bind',
+                                                               eventIn  = options.trigger == 'hover' ? 'mouseenter' : 'focus',
+                                                               eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur';
+                                               this[binder](eventIn, enter)[binder](eventOut, leave);
+                               }
+                               
+                               return this;
+                               
+               };
+               
+               $.fn.tipsy.defaults = {
+                               delayIn: 0,
+                               delayOut: 0,
+                               fade: false,
+                               fallback: '',
+                               gravity: 'n',
+                               html: false,
+                               live: false,
+                               offset: 0,
+                               opacity: 0.8,
+                               title: 'title',
+                               trigger: 'hover'
+               };
+               
+               // Overwrite this method to provide options on a per-element basis.
+               // For example, you could store the gravity in a 'tipsy-gravity' attribute:
+               // return $.extend({}, options, {gravity: $(ele).attr('tipsy-gravity') || 'n' });
+               // (remember - do not modify 'options' in place!)
+               $.fn.tipsy.elementOptions = function(ele, options) {
+                               return $.metadata ? $.extend({}, options, $(ele).metadata()) : options;
+               };
+               
+               $.fn.tipsy.autoNS = function() {
+                               return $(this).offset().top > ($(document).scrollTop() + $(window).height() / 2) ? 's' : 'n';
+               };
+               
+               $.fn.tipsy.autoWE = function() {
+                               return $(this).offset().left > ($(document).scrollLeft() + $(window).width() / 2) ? 'e' : 'w';
+               };
+               
+})(jQuery);
index ef5d3b4..c53a7ba 100644 (file)
@@ -6,17 +6,23 @@
 .config-section {
        margin-top: 2em;
 }
-
-.config-label {
-       clear: left;
+.config-block {
+       margin-top: 2em;
+       display: block;
+       
+}
+.config-block-label {
+       display: block;
+       margin-bottom: .2em;
+}
+.config-block-label label, .config-label {
        font-weight: bold;
-       width: 10em;
-       float: left;
-       text-align: right;
-       padding-right: 1em;
+       padding-right: .5em;
        padding-top: .2em;
 }
-
+.config-block-elements {
+       margin-left: 2em;
+}
 .config-input {
        clear: left;
        zoom: 100%; /* IE hack */
@@ -38,7 +44,7 @@
        padding: 0.5em 2em 0.5em 2em;
        /* 15em right margin to leave space for 12em page list */
        margin: 0.5em 15em 0.5em 0.5em;
-       border: 1px solid #aaa;
+       background: #EEEEEE;
 }
 
 .config-submit {
index 4b68732..d137b84 100644 (file)
@@ -1,19 +1,9 @@
 (function( $ ) {
        $( document ).ready( function() {
-               // Show/hide code for help text
-               $( '.config-show-help a' ).click( function() {
-                       $(this).parent().siblings( '.config-help-message' ).show( 'slow' );
-                       $(this).parent().siblings( '.config-hide-help' ).show();
-                       $(this).parent().hide();
-                       return false;
-               } );
-               $( '.config-hide-help a' ).click( function() {
-                       $(this).parent().siblings( '.config-help-message' ).hide( 'slow' );
-                       $(this).parent().siblings( '.config-show-help' ).show();
-                       $(this).parent().hide();
-                       return false;
-               } );
-               
+
+               // Generate the tool tips
+               $( '.mw-help-field-hint' ).tipsy( { gravity : 'se', opacity: '0.9' } );
+
                // Show/hide code for DB-specific options
                // FIXME: Do we want slow, fast, or even non-animated (instantaneous) showing/hiding here?
                $( '.dbRadio' ).each( function() { $( '#' + $(this).attr( 'rel' ) ).hide(); } );
diff --git a/skins/common/images/help-question-hover.gif b/skins/common/images/help-question-hover.gif
new file mode 100644 (file)
index 0000000..515138d
Binary files /dev/null and b/skins/common/images/help-question-hover.gif differ
diff --git a/skins/common/images/help-question.gif b/skins/common/images/help-question.gif
new file mode 100644 (file)
index 0000000..b4fc9c5
Binary files /dev/null and b/skins/common/images/help-question.gif differ
diff --git a/skins/common/images/tipsy-arrow.gif b/skins/common/images/tipsy-arrow.gif
new file mode 100644 (file)
index 0000000..9f1a15b
Binary files /dev/null and b/skins/common/images/tipsy-arrow.gif differ
index dd5d5ef..34975cd 100644 (file)
@@ -913,3 +913,23 @@ ol:lang(bn) li {
        list-style-type: -moz-bengali;
        list-style-type: bengali;
 }
+
+/* tooltip styles */
+.mw-help-field-hint {
+       width: 11px;
+       height: 24px;
+       display: inline-block;
+       padding: 0px;
+       margin-left: 2px;
+       margin-bottom: -8px;
+       background: url('images/help-question.gif') 0 50% no-repeat;
+}
+.mw-help-field-hint:hover {
+       background: url('images/help-question-hover.gif') 0 50% no-repeat;
+}
+.tipsy { padding: 5px 5px 10px; font-size: 12px; position: absolute; z-index: 100000; overflow: visible; }
+.tipsy-inner { padding: 5px 8px 4px 8px; background-color: #d6f3ff; color: black; border: 1px solid #5dc9f4; max-width: 300px; text-align: left; }
+.tipsy-arrow { position: absolute; background: url( 'images/tipsy-arrow.gif' ) no-repeat top left; width: 13px; height: 13px; }
+.tipsy-se .tipsy-arrow { bottom: -2px; right: 10px; background-position: 0% 100%; }
+
+