http://www.mediawiki.org/wiki/Special:Code/MediaWiki/89584

Revision: 89584
Author:   salvatoreingala
Date:     2011-06-06 17:37:12 +0000 (Mon, 06 Jun 2011)
Log Message:
-----------
- Added preferences of type "number"
- Improved validation
- Minor bugfixes

Modified Paths:
--------------
    branches/salvatoreingala/Gadgets/Gadgets.i18n.php
    branches/salvatoreingala/Gadgets/Gadgets.php
    branches/salvatoreingala/Gadgets/Gadgets_body.php
    branches/salvatoreingala/Gadgets/modules/jquery.formBuilder.js

Modified: branches/salvatoreingala/Gadgets/Gadgets.i18n.php
===================================================================
--- branches/salvatoreingala/Gadgets/Gadgets.i18n.php   2011-06-06 17:09:37 UTC 
(rev 89583)
+++ branches/salvatoreingala/Gadgets/Gadgets.i18n.php   2011-06-06 17:37:12 UTC 
(rev 89584)
@@ -54,6 +54,9 @@
        'gadgets-formbuilder-required' => 'This field is required.',
        'gadgets-formbuilder-minlength' => 'Please enter at least $1 
characters.',
        'gadgets-formbuilder-maxlength' => 'Please enter no more than $1 
characters.',
+       'gadgets-formbuilder-min' => 'Please enter a value not less than $1.',
+       'gadgets-formbuilder-max' => 'Please enter a value not greater than 
$1.',
+       'gadgets-formbuilder-integer' => 'Please enter an integer number.',
 );
 
 /** Message documentation (Message documentation)

Modified: branches/salvatoreingala/Gadgets/Gadgets.php
===================================================================
--- branches/salvatoreingala/Gadgets/Gadgets.php        2011-06-06 17:09:37 UTC 
(rev 89583)
+++ branches/salvatoreingala/Gadgets/Gadgets.php        2011-06-06 17:37:12 UTC 
(rev 89584)
@@ -72,7 +72,10 @@
 $wgResourceModules['jquery.formBuilder'] = array(
        'scripts'               => array( 'jquery.formBuilder.js' ),
        'dependencies'  => array( 'jquery', 'jquery.validate' ),
-       'messages'      => array( 'gadgets-formbuilder-required', 
'gadgets-formbuilder-minlength', 'gadgets-formbuilder-maxlength' ),
+       'messages'      => array(
+               'gadgets-formbuilder-required', 
'gadgets-formbuilder-minlength', 'gadgets-formbuilder-maxlength',
+               'gadgets-formbuilder-min', 'gadgets-formbuilder-max', 
'gadgets-formbuilder-integer'
+       ),
        'localBasePath' => $dir . 'modules/',
        'remoteExtPath' => 'Gadgets/modules'
 );

Modified: branches/salvatoreingala/Gadgets/Gadgets_body.php
===================================================================
--- branches/salvatoreingala/Gadgets/Gadgets_body.php   2011-06-06 17:09:37 UTC 
(rev 89583)
+++ branches/salvatoreingala/Gadgets/Gadgets_body.php   2011-06-06 17:37:12 UTC 
(rev 89584)
@@ -252,25 +252,52 @@
                        ),
                        'required' => array(
                                'isMandatory' => false,
-                               'checker' => 'is_bool'                          
        
+                               'checker' => 'is_bool'
                        ),
                        'minlength' => array(
                                'isMandatory' => false,
-                               'checker' => 'is_integer'                       
                
+                               'checker' => 'is_integer'
                        ),
                        'maxlength' => array(
                                'isMandatory' => false,
-                               'checker' => 'is_integer'                       
                
+                               'checker' => 'is_integer'
                        )
-                       
+               ),
+               'number' => array(
+                       'default' => array(
+                               'isMandatory' => true,
+                               'checker' => array( 'Gadget', 'isFloatOrInt' )
+                       ),
+                       'label' => array(
+                               'isMandatory' => true,
+                               'checker' => 'is_string'
+                       ),
+                       'required' => array(
+                               'isMandatory' => false,
+                               'checker' => 'is_bool'
+                       ),
+                       'integer' => array(
+                               'isMandatory' => false,
+                               'checker' => 'is_bool'
+                       ),
+                       'min' => array(
+                               'isMandatory' => false,
+                               'checker' => array( 'Gadget', 'isFloatOrInt' )
+                       ),
+                       'max' => array(
+                               'isMandatory' => false,
+                               'checker' => array( 'Gadget', 'isFloatOrInt' )
+                       )
                )
        );
 
        //Type-specific checkers for finer validation
        private static $typeCheckers = array(
-               'string' => array( 'Gadget', 'checkStringOption' )
+               'string' => array( 'Gadget', 'checkStringOption' ),
+               'number' => array( 'Gadget', 'checkNumberOption' )
        );
-               
+       
+       //Further checks for 'string' options
        private static function checkStringOption( $option ) {
                if ( isset( $option['minlength'] ) && $option['minlength'] < 0 
) {
                        return false;
@@ -286,9 +313,57 @@
                        }
                }
                
+               //$default must pass validation, too
+               $required = isset( $option['required'] ) ? $option['required'] 
: true;
+               $default = $option['default'];
+               
+               if ( $required === false && $default === '' ) {
+                       return true; //empty string is good, skip other checks
+               }
+               
+               $len = strlen( $default );
+               if ( isset( $option['minlength'] ) && $len < 
$option['minlength'] ) {
+                       return false;
+               }
+               if ( isset( $option['maxlength'] ) && $len > 
$option['maxlength'] ) {
+                       return false;
+               }
+               
                return true;
        }
 
+       private static function isFloatOrInt( $param ) {
+               return is_float( $param ) || is_int( $param );
+       }
+       
+       //Further checks for 'number' options
+       private static function checkNumberOption( $option ) {
+               if ( isset( $option['integer'] ) && $option['integer'] === true 
) {
+                       //Check if 'min', 'max' and 'default' are integers (if 
given)
+                       if ( intval( $option['default'] ) != $option['default'] 
) {
+                               return false;
+                       }
+                       if ( isset( $option['min'] ) && intval( $option['min'] 
) != $option['min'] ) {
+                               return false;
+                       }
+                       if ( isset( $option['max'] ) && intval( $option['max'] 
) != $option['max'] ) {
+                               return false;
+                       }
+               }
+               
+               //validate $option['default']
+               $default = $option['default'];
+               
+               if ( isset( $option['min'] ) && $default < $option['min'] ) {
+                       return false;
+               }
+               if ( isset( $option['max'] ) && $default > $option['max'] ) {
+                       return false;
+               }
+
+               return true;
+       }
+
        /**
         * Creates an instance of this class from definition in 
MediaWiki:Gadgets-definition
         * @param $definition String: Gadget definition
@@ -672,7 +747,7 @@
                                
                                $checker = $typeSpec[$fieldName]['checker'];
                                
-                               if ( !$checker( $fieldValue ) ) {
+                               if ( !call_user_func( $checker, $fieldValue ) ) 
{
                                        return false;
                                }
                        }
@@ -724,12 +799,17 @@
        }
 
        //Check if a preference is valid, according to description
-       //NOTE: $pref needs to be passed by reference to suppress warning on 
undefined
-       private static function checkSinglePref( &$prefDescription, &$pref ) {
-               if ( !isset( $pref ) ) {
+       //NOTE: we pass both $prefs and $prefName (instead of just 
$prefs[$prefName])
+       //      to allow checking for null.
+       private static function checkSinglePref( &$prefDescription, &$prefs, 
$prefName ) {
+               
+               //isset( $prefs[$prefName] ) would return false for null values
+               if ( !array_key_exists( $prefName, $prefs ) ) {
                        return false;
                }
-
+       
+               $pref = $prefs[$prefName];
+       
                switch ( $prefDescription['type'] ) {
                        case 'boolean':
                                return is_bool( $pref );
@@ -750,17 +830,48 @@
                                
                                //Checks the "minlength" option, if present
                                $minlength = isset( 
$prefDescription['minlength'] ) ? $prefDescription['minlength'] : 0;
-                               if ( is_integer( $minlength ) && $len < 
$minlength ){
+                               if ( $len < $minlength ){
                                        return false;
                                }
 
-                               //Checks the "minlength" option, if present
-                               $maxlength = isset( 
$prefDescription['maxlength'] ) ? $prefDescription['maxlength'] : 1000; //TODO: 
what big integer here?
-                               if ( is_integer( $maxlength ) && $len > 
$maxlength ){
+                               //Checks the "maxlength" option, if present
+                               $maxlength = isset( 
$prefDescription['maxlength'] ) ? $prefDescription['maxlength'] : 1024; //TODO: 
what big integer here?
+                               if ( $len > $maxlength ){
                                        return false;
                                }
                                
                                return true;
+                       case 'number':
+                               if ( !is_float( $pref ) && !is_int( $pref ) && 
$pref !== null ) {
+                                       return false;
+                               }
+
+                               $required = isset( $prefDescription['required'] 
) ? $prefDescription['required'] : true;
+                               if ( $required === false && $pref === null ) {
+                                       return true;
+                               }
+                               
+                               $integer = isset( $prefDescription['integer'] ) 
? $prefDescription['integer'] : false;
+                               
+                               if ( $integer === true && intval( $pref ) != 
$pref ) {
+                                       return false; //not integer
+                               }
+                               
+                               if ( isset( $prefsDescription['min'] ) ) {
+                                       $min = $prefsDescription['min'];
+                                       if ( $pref < $min ) {
+                                               return false; //value below 
minimum
+                                       }
+                               }
+
+                               if ( isset( $prefsDescription['max'] ) ) {
+                                       $max = $prefsDescription['max'];
+                                       if ( $pref > $max ) {
+                                               return false; //value above 
maximum
+                                       }
+                               }
+
+                               return true;
                        default:
                                return false; //unexisting type
                }
@@ -769,7 +880,7 @@
        //Returns true if $prefs is an array of preferences that passes 
validation
        private static function checkPrefsAgainstDescription( 
&$prefsDescription, &$prefs ) {
                foreach ( $prefsDescription['fields'] as $prefName => 
$prefDescription ) {
-                       if ( !self::checkSinglePref( $prefDescription, 
$prefs[$prefName] ) ) {
+                       if ( !self::checkSinglePref( $prefDescription, $prefs, 
$prefName ) ) {
                                return false;
                        }
                }
@@ -779,8 +890,16 @@
        //Fixes $prefs so that it matches the description given by 
$prefsDescription.
        //All values of $prefs that fail validation are replaced with default 
values.
        private static function matchPrefsWithDescription( &$prefsDescription, 
&$prefs ) {
+               //Remove unexisting preferences from $prefs
+               foreach ( $prefs as $prefName => $value ) {
+                       if ( !isset( $prefsDescription['fields'][$prefName] ) ) 
{
+                               unset( $prefs[$prefName] );
+                       }
+               }
+
+               //Fix preferences that fail validation
                foreach ( $prefsDescription['fields'] as $prefName => 
$prefDescription ) {
-                       if ( !self::checkSinglePref( $prefDescription, 
$prefs[$prefName] ) ) {
+                       if ( !self::checkSinglePref( $prefDescription, $prefs, 
$prefName ) ) {
                                $prefs[$prefName] = $prefDescription['default'];
                        }
                }

Modified: branches/salvatoreingala/Gadgets/modules/jquery.formBuilder.js
===================================================================
--- branches/salvatoreingala/Gadgets/modules/jquery.formBuilder.js      
2011-06-06 17:09:37 UTC (rev 89583)
+++ branches/salvatoreingala/Gadgets/modules/jquery.formBuilder.js      
2011-06-06 17:37:12 UTC (rev 89584)
@@ -4,7 +4,6 @@
  * Released under the MIT and GPL licenses.
  */
 
-
 (function($, mw) {
 
        var idPrefix = "mw-gadgets-dialog-";
@@ -18,6 +17,28 @@
                }
        }
 
+
+       //validator for "required" fields (without trimming whitespaces)
+       $.validator.addMethod( "requiredStrict", function( value, element ) {
+               return value.length > 0;
+       }, mw.msg( 'gadgets-formbuilder-required' ) );
+
+       //validator for "minlength" fields (without trimming whitespaces)
+       $.validator.addMethod( "minlengthStrict", function( value, element, 
param ) {
+               return value.length >= param;
+       } );
+
+       //validator for "maxlength" fields (without trimming whitespaces)
+       $.validator.addMethod( "maxlengthStrict", function( value, element, 
param ) {
+               return value.length <= param;
+       } );
+
+       //validator for integer fields
+       $.validator.addMethod( "integer", function( value, element ) {
+               return this.optional( element ) || /^-?\d+$/.test(value);
+       }, mw.msg( 'gadgets-formbuilder-integer' ) );
+
+
        //Helper function for inheritance, see 
http://javascript.crockford.com/prototypal.html
        function object(o) {
                function F() {}
@@ -57,7 +78,10 @@
        };
        
        EmptyField.prototype.getValidationSettings = function() {
-               return null;
+               return {
+                       rules: {},
+                       messages: {}
+               };
        }
 
        //A field with just a label
@@ -111,7 +135,7 @@
                        .attr( 'type', 'text' )
                        .attr( 'id', idPrefix + this.name )
                        .attr( 'name', idPrefix + this.name )
-                       .val( this.desc.value );
+                       .val( desc.value );
 
                this.$p.append( this.$text );
        }
@@ -121,9 +145,7 @@
        };
 
        StringField.prototype.getValidationSettings = function() {
-               var     settings = {
-                               rules: {}
-                       },
+               var     settings = 
LabelField.prototype.getValidationSettings.call( this ),
                        fieldId = idPrefix + this.name;
                
                settings.rules[fieldId] = {};
@@ -131,33 +153,90 @@
                        desc = this.desc;
 
                if ( desc.required === true ) {
-                       fieldRules.required = true;
+                       fieldRules.requiredStrict = true;
                }
                
                if ( typeof desc.minlength != 'undefined' ) {
-                       fieldRules.minlength = desc.minlength;
+                       fieldRules.minlengthStrict = desc.minlength;
                }
                if ( typeof desc.maxlength != 'undefined' ) {
-                       fieldRules.maxlength = desc.maxlength;
+                       fieldRules.maxlengthStrict = desc.maxlength;
                }
                
                settings.messages = {};
                
                settings.messages[fieldId] = {
-                       "required": mw.msg( 'gadgets-formbuilder-required' ),
-                       "minlength": mw.msg( 'gadgets-formbuilder-minlength', 
desc.minlength ),
-                       "maxlength": mw.msg( 'gadgets-formbuilder-maxlength', 
desc.maxlength )
+                       "minlengthStrict": mw.msg( 
'gadgets-formbuilder-minlength', desc.minlength ),
+                       "maxlengthStrict": mw.msg( 
'gadgets-formbuilder-maxlength', desc.maxlength )
                };
                                
                return settings;
        }
 
        
+       NumberField.prototype = object( LabelField.prototype );
+       NumberField.prototype.constructor = NumberField;
+       function NumberField( name, desc ){ 
+               LabelField.call( this, name, desc );
+
+               if ( desc.value !== null && typeof desc.value != 'number' ) {
+                       $.error( "desc.value is invalid" );
+               }
+
+               this.$text = $( '<input/>' )
+                       .attr( 'type', 'text' )
+                       .attr( 'id', idPrefix + this.name )
+                       .attr( 'name', idPrefix + this.name )
+                       .val( desc.value );
+
+               this.$p.append( this.$text );
+       }
        
+       NumberField.prototype.getValue = function() {
+               var val = parseFloat( this.$text.val() );
+               return isNaN( val ) ? null : val;
+       };
 
+       NumberField.prototype.getValidationSettings = function() {
+               var     settings = 
LabelField.prototype.getValidationSettings.call( this ),
+                       fieldId = idPrefix + this.name;
+               
+               settings.rules[fieldId] = {};
+               var     fieldRules = settings.rules[fieldId],
+                       desc = this.desc;
+
+               if ( desc.required !== false ) {
+                       fieldRules.requiredStrict = true;
+               }
+
+               if ( desc.integer === true ) {
+                       fieldRules.integer = true;
+               }
+
+               
+               if ( typeof desc.min != 'undefined' ) {
+                       fieldRules.min = desc.min;
+               }
+               if ( typeof desc.max != 'undefined' ) {
+                       fieldRules.max = desc.max;
+               }
+               
+               settings.messages = {};
+               
+               settings.messages[fieldId] = {
+                       "required": mw.msg( 'gadgets-formbuilder-required' ),
+                       "min": mw.msg( 'gadgets-formbuilder-min', desc.min ),
+                       "max": mw.msg( 'gadgets-formbuilder-max', desc.max )
+               };
+                               
+               return settings;
+       }
+       
+
        var validFields = {
                "boolean": BooleanField,
-               "string" : StringField
+               "string" : StringField,
+               "number" : NumberField
        };
 
        function buildFormBody() {
@@ -214,7 +293,7 @@
                                var     fieldSettings = 
f.getValidationSettings();
                                
                                if ( fieldSettings ) {
-                                       $.extend( settings, fieldSettings, true 
);
+                                       $.extend( true, settings, fieldSettings 
);
                                }
                                
                                fields.push( f );
@@ -254,7 +333,7 @@
                if ( methods[method] ) {
                        return methods[method].apply( this, 
Array.prototype.slice.call( arguments, 1 ));
                } else if ( typeof method === 'object' || !method ) {
-                       return buildFormBody.apply( this, arguments ); //TODO
+                       return buildFormBody.apply( this, arguments );
                } else {
                        $.error( 'Method ' +  method + ' does not exist on 
jQuery.formBuilder' );
                }


_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs

Reply via email to