Index: branches/salvatoreingala/Gadgets/Gadgets.php |
— | — | @@ -74,7 +74,7 @@ |
75 | 75 | |
76 | 76 | $wgResourceModules['jquery.formBuilder'] = array( |
77 | 77 | 'scripts' => array( 'jquery.formBuilder.js' ), |
78 | | - 'dependencies' => array( 'jquery', 'jquery.ui.slider', 'jquery.validate' ), |
| 78 | + 'dependencies' => array( 'jquery', 'jquery.ui.slider', 'jquery.ui.datepicker', 'jquery.validate' ), |
79 | 79 | 'messages' => array( |
80 | 80 | 'gadgets-formbuilder-required', 'gadgets-formbuilder-minlength', 'gadgets-formbuilder-maxlength', |
81 | 81 | 'gadgets-formbuilder-min', 'gadgets-formbuilder-max', 'gadgets-formbuilder-integer' |
Index: branches/salvatoreingala/Gadgets/Gadgets_tests.php |
— | — | @@ -379,6 +379,55 @@ |
380 | 380 | } |
381 | 381 | } |
382 | 382 | |
| 383 | + //Tests for 'date' type preferences |
| 384 | + function testPrefsDescriptionsDate() { |
| 385 | + $correct = array( |
| 386 | + 'fields' => array( |
| 387 | + 'testDate' => array( |
| 388 | + 'type' => 'date', |
| 389 | + 'label' => 'some label', |
| 390 | + 'default' => null |
| 391 | + ) |
| 392 | + ) |
| 393 | + ); |
| 394 | + |
| 395 | + //Tests with correct default values |
| 396 | + $correct2 = $correct; |
| 397 | + foreach ( array( |
| 398 | + null, |
| 399 | + '2011-07-05T15:00:00Z', |
| 400 | + '2011-01-01T00:00:00Z', |
| 401 | + '2011-12-31T23:59:59Z', |
| 402 | + ) as $def ) |
| 403 | + { |
| 404 | + $correct2['fields']['testDate']['default'] = $def; |
| 405 | + $this->assertTrue( GadgetPrefs::isPrefsDescriptionValid( $correct2 ) ); |
| 406 | + } |
| 407 | + |
| 408 | + //Tests with wrong default values |
| 409 | + $wrong = $correct; |
| 410 | + foreach ( array( |
| 411 | + '', true, false, array(), 0, |
| 412 | + '2011-07-05T15:00:00', |
| 413 | + '2011-07-05T15:00:61Z', |
| 414 | + '2011-07-05T15:61:00Z', |
| 415 | + '2011-07-05T25:00:00Z', |
| 416 | + '2011-07-32T15:00:00Z', |
| 417 | + '2011-07-5T15:00:00Z', |
| 418 | + '2011-7-05T15:00:00Z', |
| 419 | + '2011-13-05T15:00:00Z', |
| 420 | + '2011-07-05T15:00-00Z', |
| 421 | + '2011-07-05T15-00:00Z', |
| 422 | + '2011-07-05S15:00:00Z', |
| 423 | + '2011-07:05T15:00:00Z', |
| 424 | + '2011:07-05T15:00:00Z' |
| 425 | + ) as $def ) |
| 426 | + { |
| 427 | + $wrong['fields']['testDate']['default'] = $def; |
| 428 | + $this->assertFalse( GadgetPrefs::isPrefsDescriptionValid( $wrong ) ); |
| 429 | + } |
| 430 | + } |
| 431 | + |
383 | 432 | //Data provider to be able to reuse this preference description for several tests. |
384 | 433 | function prefsDescProvider() { |
385 | 434 | return array( array( |
Index: branches/salvatoreingala/Gadgets/backend/GadgetPrefs.php |
— | — | @@ -104,6 +104,15 @@ |
105 | 105 | 'isMandatory' => false, |
106 | 106 | 'checker' => 'GadgetPrefs::isFloatOrInt' |
107 | 107 | ) |
| 108 | + ), |
| 109 | + 'date' => array( |
| 110 | + 'default' => array( |
| 111 | + 'isMandatory' => true |
| 112 | + ), |
| 113 | + 'label' => array( |
| 114 | + 'isMandatory' => true, |
| 115 | + 'checker' => 'is_string' |
| 116 | + ) |
108 | 117 | ) |
109 | 118 | ); |
110 | 119 | |
— | — | @@ -112,7 +121,7 @@ |
113 | 122 | 'string' => 'GadgetPrefs::checkStringOptionDefinition', |
114 | 123 | 'number' => 'GadgetPrefs::checkNumberOptionDefinition', |
115 | 124 | 'select' => 'GadgetPrefs::checkSelectOptionDefinition', |
116 | | - 'range' => 'GadgetPrefs::checkRangeOptionDefinition', |
| 125 | + 'range' => 'GadgetPrefs::checkRangeOptionDefinition' |
117 | 126 | ); |
118 | 127 | |
119 | 128 | //Further checks for 'string' options |
— | — | @@ -233,7 +242,7 @@ |
234 | 243 | } |
235 | 244 | |
236 | 245 | $type = $optionDefinition['type']; |
237 | | - |
| 246 | + |
238 | 247 | if ( !isset( self::$prefsDescriptionSpecifications[$type] ) ) { |
239 | 248 | return false; |
240 | 249 | } |
— | — | @@ -403,6 +412,20 @@ |
404 | 413 | } |
405 | 414 | |
406 | 415 | return true; |
| 416 | + case 'date': |
| 417 | + if ( $pref === null ) { |
| 418 | + return true; |
| 419 | + } |
| 420 | + |
| 421 | + //Basic syntactic checks |
| 422 | + if ( !is_string( $pref ) || |
| 423 | + !preg_match( '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/', $pref ) ) |
| 424 | + { |
| 425 | + return false; |
| 426 | + } |
| 427 | + |
| 428 | + //Full parsing |
| 429 | + return date_create( $pref ) !== false; |
407 | 430 | default: |
408 | 431 | return false; //unexisting type |
409 | 432 | } |
Index: branches/salvatoreingala/Gadgets/ui/resources/jquery.formBuilder.js |
— | — | @@ -138,7 +138,7 @@ |
139 | 139 | return this.$c.is( ':checked' ); |
140 | 140 | }; |
141 | 141 | |
142 | | - //A field with a textbox |
| 142 | + //A field with a textbox accepting string values |
143 | 143 | |
144 | 144 | StringField.prototype = object( LabelField.prototype ); |
145 | 145 | StringField.prototype.constructor = StringField; |
— | — | @@ -191,7 +191,7 @@ |
192 | 192 | return settings; |
193 | 193 | }; |
194 | 194 | |
195 | | - |
| 195 | + //A field with a textbox accepting numeric values |
196 | 196 | NumberField.prototype = object( LabelField.prototype ); |
197 | 197 | NumberField.prototype.constructor = NumberField; |
198 | 198 | function NumberField( $form, name, desc ){ |
— | — | @@ -250,7 +250,7 @@ |
251 | 251 | return settings; |
252 | 252 | }; |
253 | 253 | |
254 | | - |
| 254 | + //A field with a drop-down list |
255 | 255 | SelectField.prototype = object( LabelField.prototype ); |
256 | 256 | SelectField.prototype.constructor = SelectField; |
257 | 257 | function SelectField( $form, name, desc ){ |
— | — | @@ -289,6 +289,7 @@ |
290 | 290 | }; |
291 | 291 | |
292 | 292 | |
| 293 | + //A field with a slider, representing ranges of numbers |
293 | 294 | RangeField.prototype = object( LabelField.prototype ); |
294 | 295 | RangeField.prototype.constructor = RangeField; |
295 | 296 | function RangeField( $form, name, desc ){ |
— | — | @@ -336,13 +337,68 @@ |
337 | 338 | return this.$slider.slider( 'value' ); |
338 | 339 | }; |
339 | 340 | |
| 341 | + |
| 342 | + //A field with a textbox with a datepicker |
| 343 | + DateField.prototype = object( LabelField.prototype ); |
| 344 | + DateField.prototype.constructor = DateField; |
| 345 | + function DateField( $form, name, desc ){ |
| 346 | + LabelField.call( this, $form, name, desc ); |
340 | 347 | |
| 348 | + if ( typeof desc.value == 'undefined' ) { |
| 349 | + $.error( "desc.value is invalid" ); |
| 350 | + } |
| 351 | + |
| 352 | + var date; |
| 353 | + if ( desc.value !== null ) { |
| 354 | + date = new Date( desc.value ); |
| 355 | + |
| 356 | + if ( !isFinite( date ) ) { |
| 357 | + $.error( "desc.value is invalid" ); |
| 358 | + } |
| 359 | + } |
| 360 | + |
| 361 | + this.$text = $( '<input/>' ) |
| 362 | + .attr( 'type', 'text' ) |
| 363 | + .attr( 'id', idPrefix + this.name ) |
| 364 | + .attr( 'name', idPrefix + this.name ) |
| 365 | + .datepicker(); |
| 366 | + |
| 367 | + if ( desc.value !== null ) { |
| 368 | + this.$text.datepicker( 'setDate', date ); |
| 369 | + } |
| 370 | + |
| 371 | + this.$p.append( this.$text ); |
| 372 | + } |
| 373 | + |
| 374 | + DateField.prototype.getValue = function() { |
| 375 | + function pad( n ) { |
| 376 | + return n < 10 ? '0' + n : n; |
| 377 | + } |
| 378 | + |
| 379 | + var d = this.$text.datepicker( 'getDate' ); |
| 380 | + |
| 381 | + if ( d === null ) { |
| 382 | + return null; |
| 383 | + } |
| 384 | + |
| 385 | + //UTC date in ISO 8601 format [YYYY]-[MM]-[DD]T[hh]:[mm]:[ss]Z |
| 386 | + return '' + d.getUTCFullYear() + '-' + |
| 387 | + pad( d.getUTCMonth() + 1 ) + '-' + |
| 388 | + pad( d.getUTCDate() ) + 'T' + |
| 389 | + pad( d.getUTCHours() ) + ':' + |
| 390 | + pad( d.getUTCMinutes() ) + ':' + |
| 391 | + pad( d.getUTCSeconds() ) + 'Z'; |
| 392 | + }; |
| 393 | + |
| 394 | + |
| 395 | + |
341 | 396 | var validFieldTypes = { |
342 | 397 | "boolean": BooleanField, |
343 | 398 | "string" : StringField, |
344 | 399 | "number" : NumberField, |
345 | 400 | "select" : SelectField, |
346 | | - "range" : RangeField |
| 401 | + "range" : RangeField, |
| 402 | + "date" : DateField |
347 | 403 | }; |
348 | 404 | |
349 | 405 | /* Public methods */ |