r92866 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r92865‎ | r92866 | r92867 >
Date:17:09, 22 July 2011
Author:salvatoreingala
Status:deferred
Tags:
Comment:
- Added 'bundle' preferences, shown as jQuery.UI tabs.
- Minor code cleanups.
Modified paths:
  • /branches/salvatoreingala/Gadgets/Gadgets.php (modified) (history)
  • /branches/salvatoreingala/Gadgets/Gadgets_tests.php (modified) (history)
  • /branches/salvatoreingala/Gadgets/backend/GadgetPrefs.php (modified) (history)
  • /branches/salvatoreingala/Gadgets/ui/resources/jquery.formBuilder.js (modified) (history)

Diff [purge]

Index: branches/salvatoreingala/Gadgets/Gadgets.php
@@ -86,7 +86,7 @@
8787 'styles' => array( 'jquery.formBuilder.css' ),
8888 'dependencies' => array(
8989 'jquery', 'jquery.ui.slider', 'jquery.ui.datepicker', 'jquery.ui.position',
90 - 'jquery.farbtastic', 'jquery.colorUtil', 'jquery.validate'
 90+ 'jquery.ui.tabs', 'jquery.farbtastic', 'jquery.colorUtil', 'jquery.validate'
9191 ),
9292 'messages' => array(
9393 'gadgets-formbuilder-required', 'gadgets-formbuilder-minlength', 'gadgets-formbuilder-maxlength',
Index: branches/salvatoreingala/Gadgets/Gadgets_tests.php
@@ -528,62 +528,75 @@
529529 }
530530
531531
532 - //Data provider to be able to reuse this preference description for several tests.
 532+ //Data provider to be able to reuse a complex preference description for several tests.
533533 function prefsDescProvider() {
534534 return array( array(
535535 array(
536536 'fields' => array(
537537 array(
538 - 'name' => 'testBoolean',
539 - 'type' => 'boolean',
540 - 'label' => '@foo',
541 - 'default' => true
542 - ),
543 - array(
544 - 'name' => 'testBoolean2',
545 - 'type' => 'boolean',
546 - 'label' => '@@foo2',
547 - 'default' => true
548 - ),
549 - array(
550 - 'name' => 'testNumber',
551 - 'type' => 'number',
552 - 'label' => '@foo3',
553 - 'min' => 2.3,
554 - 'max' => 13.94,
555 - 'default' => 7
556 - ),
557 - array(
558 - 'name' => 'testNumber2',
559 - 'type' => 'number',
560 - 'label' => 'foo4',
561 - 'min' => 2.3,
562 - 'max' => 13.94,
563 - 'default' => 7
564 - ),
565 - array(
566 - 'name' => 'testSelect',
567 - 'type' => 'select',
568 - 'label' => 'foo',
569 - 'default' => 3,
570 - 'options' => array(
571 - '@opt1' => null,
572 - '@opt2' => true,
573 - 'opt3' => 3,
574 - '@opt4' => 'opt4value'
 538+ 'type' => 'bundle',
 539+ 'sections' => array(
 540+ '@section1' => array(
 541+ 'fields' => array (
 542+ array(
 543+ 'name' => 'testBoolean',
 544+ 'type' => 'boolean',
 545+ 'label' => '@foo',
 546+ 'default' => true
 547+ ),
 548+ array(
 549+ 'name' => 'testBoolean2',
 550+ 'type' => 'boolean',
 551+ 'label' => '@@foo2',
 552+ 'default' => true
 553+ ),
 554+ array(
 555+ 'name' => 'testNumber',
 556+ 'type' => 'number',
 557+ 'label' => '@foo3',
 558+ 'min' => 2.3,
 559+ 'max' => 13.94,
 560+ 'default' => 7
 561+ )
 562+ )
 563+ ),
 564+ 'Section2' => array(
 565+ 'fields' => array(
 566+ array(
 567+ 'name' => 'testNumber2',
 568+ 'type' => 'number',
 569+ 'label' => 'foo4',
 570+ 'min' => 2.3,
 571+ 'max' => 13.94,
 572+ 'default' => 7
 573+ ),
 574+ array(
 575+ 'name' => 'testSelect',
 576+ 'type' => 'select',
 577+ 'label' => 'foo',
 578+ 'default' => 3,
 579+ 'options' => array(
 580+ '@opt1' => null,
 581+ '@opt2' => true,
 582+ 'opt3' => 3,
 583+ '@opt4' => 'opt4value'
 584+ )
 585+ ),
 586+ array(
 587+ 'name' => 'testSelect2',
 588+ 'type' => 'select',
 589+ 'label' => 'foo',
 590+ 'default' => 3,
 591+ 'options' => array(
 592+ '@opt1' => null,
 593+ 'opt2' => true,
 594+ 'opt3' => 3,
 595+ 'opt4' => 'opt4value'
 596+ )
 597+ )
 598+ )
 599+ )
575600 )
576 - ),
577 - array(
578 - 'name' => 'testSelect2',
579 - 'type' => 'select',
580 - 'label' => 'foo',
581 - 'default' => 3,
582 - 'options' => array(
583 - '@opt1' => null,
584 - 'opt2' => true,
585 - 'opt3' => 3,
586 - 'opt4' => 'opt4value'
587 - )
588601 )
589602 )
590603 )
@@ -636,9 +649,10 @@
637650 $this->assertEquals( $prefs2['testNumber'], $prefs['testNumber'] );
638651 $this->assertEquals( $prefs2['testSelect'], $prefs['testSelect'] );
639652
640 - $this->assertEquals( $prefs2['testBoolean2'], $prefsDescription['fields'][1]['default'] );
641 - $this->assertEquals( $prefs2['testNumber2'], $prefsDescription['fields'][3]['default'] );
642 - $this->assertEquals( $prefs2['testSelect2'], $prefsDescription['fields'][5]['default'] );
 653+ $defaults = GadgetPrefs::getDefaults( $prefsDescription );
 654+ $this->assertEquals( $prefs2['testBoolean2'], $defaults['testBoolean2'] );
 655+ $this->assertEquals( $prefs2['testNumber2'], $defaults['testNumber2'] );
 656+ $this->assertEquals( $prefs2['testSelect2'], $defaults['testSelect2'] );
643657
644658 $g = $this->create( '*foo[ResourceLoader]| foo.css|foo.js|foo.bar' );
645659 $g->setPrefsDescription( $prefsDescription );
@@ -682,8 +696,9 @@
683697 */
684698 function testGetMessages( $prefsDescription ) {
685699 $msgs = GadgetPrefs::getMessages( $prefsDescription );
 700+ sort( $msgs );
686701 $this->assertEquals( $msgs, array(
687 - 'foo', 'foo3', 'opt1', 'opt2', 'opt4'
 702+ 'foo', 'foo3', 'opt1', 'opt2', 'opt4', 'section1'
688703 ) );
689704 }
690705 }
Index: branches/salvatoreingala/Gadgets/backend/GadgetPrefs.php
@@ -14,6 +14,7 @@
1515 * Syntax specifications of preference description language.
1616 * Each element describes a field; a "simple" field encodes exactly one gadget preference, but some fields
1717 * may encode for 0 or multiple gadget preferences.
 18+ * "Simple" field always have the 'name', the 'label' and the 'default' members.
1819 * Each field has a 'description' and may have a 'validator', a 'flattener', and a 'checker'.
1920 * - 'description' is an array that describes all the members of that fields. Each member description has this shape:
2021 * - 'isMandatory' is a boolean that specifies if that member is mandatory for the field;
@@ -193,6 +194,16 @@
194195 )
195196 ),
196197 'checker' => 'GadgetPrefs::checkColorPref'
 198+ ),
 199+ 'bundle' => array(
 200+ 'description' => array(
 201+ 'sections' => array(
 202+ 'isMandatory' => true,
 203+ 'checker' => 'GadgetPrefs::validateBundleSectionsDefinition'
 204+ )
 205+ ),
 206+ 'getMessages' => 'GadgetPrefs::getBundleMessages',
 207+ 'flattener' => 'GadgetPrefs::flattenBundleDefinition'
197208 )
198209 );
199210
@@ -234,6 +245,17 @@
235246 return array( $fieldDescription['name'] => $fieldDescription );
236247 }
237248
 249+ //flattener for 'bundle' fields
 250+ private static function flattenBundleDefinition( $fieldDescription ) {
 251+ $flattenedPrefs = array();
 252+ foreach ( $fieldDescription['sections'] as $sectionName => $sectionDescription ) {
 253+ //Each section behaves like a full description of preferences
 254+ $flt = self::flattenPrefsDescription( $sectionDescription );
 255+ $flattenedPrefs = array_merge( $flattenedPrefs, $flt );
 256+ }
 257+ return $flattenedPrefs;
 258+ }
 259+
238260 //Further checks for 'number' options
239261 private static function validateNumberOptionDefinition( $option ) {
240262 if ( isset( $option['integer'] ) && $option['integer'] === true ) {
@@ -297,10 +319,9 @@
298320 //Flattens a simple field, by calling its field-specific flattener if there is any,
299321 //or the default flattener otherwise.
300322 private static function flattenFieldDescription( $fieldDescription ) {
301 - $typeSpec = self::$prefsDescriptionSpecifications[$fieldDescription['type']];
302 - $typeDescription = $typeSpec['description'];
303 - if ( isset( $typeSpec['flattener'] ) ) {
304 - $flattener = $typeSpec['flattener'];
 323+ $fieldSpec = self::$prefsDescriptionSpecifications[$fieldDescription['type']];
 324+ if ( isset( $fieldSpec['flattener'] ) ) {
 325+ $flattener = $fieldSpec['flattener'];
305326 } else {
306327 $flattener = 'GadgetPrefs::flattenSimpleField';
307328 }
@@ -316,6 +337,7 @@
317338 $flt = self::flattenFieldDescription( $fieldDescription );
318339 $flattenedPrefsDescription = array_merge( $flattenedPrefsDescription, $flt );
319340 }
 341+
320342 return $flattenedPrefsDescription;
321343 }
322344
@@ -415,8 +437,8 @@
416438 return false;
417439 }
418440
419 - $prefs = array( 'dummy' => $optionDefinition['default'] );
420 - if ( !self::checkSinglePref( $optionDefinition, $prefs, 'dummy' ) ) {
 441+ $prefs = array( 'dummy' => $prefDescription['default'] );
 442+ if ( !self::checkSinglePref( $prefDescription, $prefs, 'dummy' ) ) {
421443 return false;
422444 }
423445 }
@@ -431,6 +453,30 @@
432454 return true;
433455 }
434456
 457+ //validates the 'sections' member of a 'bundle' field
 458+ private static function validateBundleSectionsDefinition( $sections ) {
 459+ //validate each section, then ensure that preference names
 460+ //of each section are disjoint
 461+
 462+ $prefs = array(); //names of preferences
 463+
 464+ foreach ( $sections as $section ) {
 465+ if ( !self::validateSectionDefinition( $section ) ) {
 466+ return false;
 467+ }
 468+
 469+ $flt = self::flattenPrefsDescription( $section );
 470+ $newPrefs = array_keys( $flt );
 471+ if ( array_intersect( $prefs, $newPrefs ) ) {
 472+ return false;
 473+ }
 474+
 475+ $prefs = array_merge( $prefs, $newPrefs );
 476+ }
 477+
 478+ return true;
 479+ }
 480+
435481 //Checks if the given description of the preferences is valid
436482 public static function isPrefsDescriptionValid( $prefsDescription ) {
437483 return self::validateSectionDefinition( $prefsDescription );
@@ -721,6 +767,19 @@
722768 $msgs[] = substr( $optName, 1 );
723769 }
724770 }
725 - return $msgs;
 771+ return array_unique( $msgs );
726772 }
 773+
 774+ //Returns the messages for a 'bundle' field description
 775+ private static function getBundleMessages( $prefDescription ) {
 776+ //returns the union of all messages of all sections, plus section names
 777+ $msgs = array();
 778+ foreach ( $prefDescription['sections'] as $sectionName => $sectionDescription ) {
 779+ $msgs = array_merge( $msgs, self::getMessages( $sectionDescription ) );
 780+ if ( self::isMessage( $sectionName ) ) {
 781+ $msgs[] = substr( $sectionName, 1 );
 782+ }
 783+ }
 784+ return array_unique( $msgs );
 785+ }
727786 }
Index: branches/salvatoreingala/Gadgets/ui/resources/jquery.formBuilder.js
@@ -18,11 +18,17 @@
1919 } else if ( str.substr( 0, 2 ) == '@@' ) {
2020 return str.substr( 1 );
2121 } else {
22 - //TODO: better validation
2322 return mw.message( $form.data( 'formBuilder' ).prefix + str.substring( 1 ) ).plain();
2423 }
2524 }
2625
 26+ //Commodity function to avoid id conflicts
 27+ var getIncrementalCounter = ( function() {
 28+ var cnt = 0;
 29+ return function() {
 30+ return cnt++;
 31+ };
 32+ } )();
2733
2834 function pad( n, len ) {
2935 var res = '' + n;
@@ -86,46 +92,64 @@
8793 return new F();
8894 }
8995
90 - //A field with no content
91 - function EmptyField( $form, desc, values ) {
92 - //Check existence of compulsory fields
93 - if ( !desc.type || !desc.label ) {
94 - $.error( "Missing arguments" );
95 - }
96 -
 96+ /* Basic interface for fields */
 97+ function Field( $form, desc, values ) {
9798 this.$form = $form;
98 -
99 - this.$p = $( '<p/>' );
100 -
10199 this.desc = desc;
102100 }
103101
104 - EmptyField.prototype.getDesc = function() {
 102+ Field.prototype.getDesc = function() {
105103 return this.desc;
106104 };
107105
108106 //Override expected
109 - EmptyField.prototype.getValues = function() {
 107+ Field.prototype.getValues = function() {
110108 return {};
111109 };
112110
113 - EmptyField.prototype.getElement = function() {
114 - return this.$p;
 111+ //Override expected
 112+ Field.prototype.getElement = function() {
 113+ return null;
115114 };
116115
117 - EmptyField.prototype.getValidationSettings = function() {
 116+ //Override expected
 117+ Field.prototype.getValidationSettings = function() {
118118 return {
119119 rules: {},
120120 messages: {}
121121 };
122122 };
123123
124 - //A field with just a label
 124+
 125+ /* A field with no content, generating an empty container */
 126+ EmptyField.prototype = object( Field.prototype );
 127+ EmptyField.prototype.constructor = EmptyField;
 128+ function EmptyField( $form, desc, values ) {
 129+ Field.call( this, $form, desc, values );
 130+
 131+ //Check existence and type of the "type" field
 132+ if ( !desc.type || typeof desc.type != 'string' ) {
 133+ $.error( "Missing 'type' parameter" );
 134+ }
 135+
 136+ this.$p = $( '<p/>' );
 137+ }
 138+
 139+ EmptyField.prototype.getElement = function() {
 140+ return this.$p;
 141+ };
 142+
 143+ /* A field with just a label */
125144 LabelField.prototype = object( EmptyField.prototype );
126145 LabelField.prototype.constructor = LabelField;
127146 function LabelField( $form, desc, values ) {
128147 EmptyField.call( this, $form, desc, values );
129148
 149+ //Check existence and type of the "label" field
 150+ if ( !desc.label || typeof desc.label != 'string' ) {
 151+ $.error( "Missing 'label' parameter" );
 152+ }
 153+
130154 var $label = $( '<label/>' )
131155 .text( preproc( this.$form, this.desc.label ) )
132156 .attr('for', idPrefix + this.desc.name );
@@ -133,7 +157,7 @@
134158 this.$p.append( $label );
135159 }
136160
137 - //A field with a label and a checkbox
 161+ /* A field with a label and a checkbox */
138162 BooleanField.prototype = object( LabelField.prototype );
139163 BooleanField.prototype.constructor = BooleanField;
140164 function BooleanField( $form, desc, values ){
@@ -159,8 +183,7 @@
160184 return res;
161185 };
162186
163 - //A field with a textbox accepting string values
164 -
 187+ /* A field with a textbox accepting string values */
165188 StringField.prototype = object( LabelField.prototype );
166189 StringField.prototype.constructor = StringField;
167190 function StringField( $form, desc, values ){
@@ -215,7 +238,7 @@
216239 return settings;
217240 };
218241
219 - //A field with a textbox accepting numeric values
 242+ /* A field with a textbox accepting numeric values */
220243 NumberField.prototype = object( LabelField.prototype );
221244 NumberField.prototype.constructor = NumberField;
222245 function NumberField( $form, desc, values ){
@@ -277,7 +300,7 @@
278301 return settings;
279302 };
280303
281 - //A field with a drop-down list
 304+ /* A field with a drop-down list */
282305 SelectField.prototype = object( LabelField.prototype );
283306 SelectField.prototype.constructor = SelectField;
284307 function SelectField( $form, desc, values ){
@@ -319,7 +342,7 @@
320343 };
321344
322345
323 - //A field with a slider, representing ranges of numbers
 346+ /* A field with a slider, representing ranges of numbers */
324347 RangeField.prototype = object( LabelField.prototype );
325348 RangeField.prototype.constructor = RangeField;
326349 function RangeField( $form, desc, values ){
@@ -371,7 +394,7 @@
372395 };
373396
374397
375 - //A field with a textbox with a datepicker
 398+ /* A field with a textbox with a datepicker */
376399 DateField.prototype = object( LabelField.prototype );
377400 DateField.prototype.constructor = DateField;
378401 function DateField( $form, desc, values ){
@@ -437,15 +460,24 @@
438461 "datePicker": true
439462 };
440463 return settings;
441 - }
 464+ };
442465
443 - //A field with color picker
 466+ /* A field with color picker */
444467
445468 function closeColorPicker() {
446469 $( '#colorpicker' ).fadeOut( 'fast', function() {
447 - $( this ).remove()
 470+ $( this ).remove();
448471 } );
449472 }
 473+
 474+
 475+ //If a click happens outside the colorpicker while it is showed, remove it
 476+ $( document ).mousedown( function( event ) {
 477+ var $target = $( event.target );
 478+ if ( $target.parents( '#colorpicker' ).length == 0 ) {
 479+ closeColorPicker();
 480+ }
 481+ } );
450482
451483 ColorField.prototype = object( LabelField.prototype );
452484 ColorField.prototype.constructor = ColorField;
@@ -504,25 +536,119 @@
505537 "color": true
506538 };
507539 return settings;
508 - }
 540+ };
509541
510542 ColorField.prototype.getValues = function() {
511543 var color = $.colorUtil.getRGB( this.$text.val() ),
512 - res = {}
 544+ res = {};
513545 res[this.desc.name] = '#' + pad( color[0].toString( 16 ), 2 ) +
514546 pad( color[1].toString( 16 ), 2 ) + pad( color[2].toString( 16 ), 2 );
515547 return res;
516548 };
 549+
 550+ /* A field that represent a section (group of fields) */
 551+ SectionField.prototype = object( Field.prototype );
 552+ SectionField.prototype.constructor = SectionField;
 553+ function SectionField( $form, desc, values, id ) {
 554+ Field.call( this, $form, desc, values );
 555+
 556+ this.$p = $( '<p/>' );
 557+
 558+ if ( id !== undefined ) {
 559+ this.$p.attr( 'id', id );
 560+ }
 561+
 562+ var fields = [],
 563+ settings = {}; //validator settings
517564
518 - //If a click happens outside the colorpicker while it is showed, remove it
519 - $( document ).mousedown( function( event ) {
520 - var $target = $( event.target );
521 - if ( $target.parents( '#colorpicker' ).length == 0 ) {
522 - closeColorPicker();
 565+ for ( var i = 0; i < desc.fields.length; i++ ) {
 566+ //TODO: validate fieldName
 567+ var field = desc.fields[i],
 568+ FieldConstructor = validFieldTypes[field.type];
 569+
 570+ if ( typeof FieldConstructor != 'function' ) {
 571+ $.error( "field with invalid type: " + field.type );
 572+ }
 573+
 574+ var f = new FieldConstructor( $form, field, values );
 575+
 576+ this.$p.append( f.getElement() );
 577+
 578+ //If this field has validation rules, add them to settings
 579+ var fieldSettings = f.getValidationSettings();
 580+
 581+ if ( fieldSettings ) {
 582+ $.extend( true, settings, fieldSettings );
 583+ }
 584+
 585+ fields.push( f );
523586 }
524 - } );
 587+
 588+ this.settings = settings;
 589+ this.fields = fields;
 590+ }
525591
 592+ SectionField.prototype.getElement = function() {
 593+ return this.$p;
 594+ };
526595
 596+ SectionField.prototype.getValues = function() {
 597+ var values = {};
 598+ for ( var i = 0; i < this.fields.length; i++ ) {
 599+ $.extend( values, this.fields[i].getValues() );
 600+ }
 601+ return values;
 602+ };
 603+
 604+ SectionField.prototype.getValidationSettings = function() {
 605+ return this.settings;
 606+ };
 607+
 608+ /* A field for 'bundle's */
 609+ BundleField.prototype = object( EmptyField.prototype );
 610+ BundleField.prototype.constructor = BundleField;
 611+ function BundleField( $form, desc, values ) {
 612+ EmptyField.call( this, $form, desc, values );
 613+
 614+ //Create tabs
 615+ var $tabs = this.$tabs = $( '<div><ul></ul></div>' )
 616+ .attr( 'id', idPrefix + 'tab-' + getIncrementalCounter() )
 617+ .tabs();
 618+
 619+ this.sections = [];
 620+
 621+ var self = this;
 622+ $.each( desc.sections, function( sectionName, sectionDescription ) {
 623+ var id = idPrefix + 'section-' + getIncrementalCounter(),
 624+ sec = new SectionField( $form, sectionDescription, values, id );
 625+
 626+ self.sections.push( sec );
 627+
 628+ $tabs.append( sec.getElement() )
 629+ .tabs( 'add', '#' + id, preproc( $form, sectionName ) );
 630+ } );
 631+
 632+ this.$p.append( $tabs );
 633+ }
 634+
 635+ BundleField.prototype.getValidationSettings = function() {
 636+ var settings = {};
 637+ $.each( this.sections, function( idx, section ) {
 638+ $.extend( true, settings, section.getValidationSettings() );
 639+ } );
 640+ return settings;
 641+ };
 642+
 643+ BundleField.prototype.getValues = function() {
 644+ var values = {};
 645+ $.each( this.sections, function( idx, section ) {
 646+ $.extend( values, section.getValues() );
 647+ } );
 648+ return values;
 649+ };
 650+
 651+
 652+ //Field types that can be referred to by preference descriptions
527653 var validFieldTypes = {
528654 "boolean": BooleanField,
529655 "string" : StringField,
@@ -530,9 +656,11 @@
531657 "select" : SelectField,
532658 "range" : RangeField,
533659 "date" : DateField,
534 - "color" : ColorField
 660+ "color" : ColorField,
 661+ "bundle" : BundleField
535662 };
536663
 664+
537665 /* Public methods */
538666
539667 /**
@@ -552,7 +680,7 @@
553681 var $form = $( '<form/>' ).addClass( 'formbuilder' );
554682 var prefix = options.gadget === undefined ? '' : ( 'Gadget-' + options.gadget + '-' );
555683 $form.data( 'formBuilder', {
556 - prefix: prefix, //prefix for messages
 684+ prefix: prefix //prefix for messages
557685 } );
558686
559687 //If there is an "intro", adds it to the form as a label
@@ -568,45 +696,15 @@
569697 return null;
570698 }
571699
572 - var fields = [];
 700+ var section = new SectionField( $form, description, options.values );
 701+
 702+ section.getElement().appendTo( $form );
573703
574 - var settings = {}; //validator settings
 704+ var validator = $form.validate( section.getValidationSettings() );
575705
576 - for ( var i = 0; i < description.fields.length; i++ ) {
577 - //TODO: validate fieldName
578 - var field = description.fields[i],
579 - FieldConstructor = validFieldTypes[field.type];
580 -
581 - if ( typeof FieldConstructor != 'function' ) {
582 - mw.log( "field with invalid type: " + field.type );
583 - return null;
584 - }
585 -
586 - var f;
587 - try {
588 - f = new FieldConstructor( $form, field, options.values );
589 - } catch ( e ) {
590 - mw.log( e );
591 - return null; //constructor failed, wrong syntax in field description
592 - }
593 -
594 - $form.append( f.getElement() );
595 -
596 - //If this field has validation rules, add them to settings
597 - var fieldSettings = f.getValidationSettings();
598 -
599 - if ( fieldSettings ) {
600 - $.extend( true, settings, fieldSettings );
601 - }
602 -
603 - fields.push( f );
604 - }
605 -
606 - var validator = $form.validate( settings );
607 -
608706 var data = $form.data( 'formBuilder' );
609 - data.fields = fields,
610 - data.validator = validator
 707+ data.mainSection = section;
 708+ data.validator = validator;
611709
612710 return $form;
613711 }
@@ -620,15 +718,8 @@
621719 * @return {Object}
622720 */
623721 getValues: function() {
624 - var data = this.data( 'formBuilder' ),
625 - result = {};
626 -
627 - for ( var i = 0; i < data.fields.length; i++ ) {
628 - var f = data.fields[i];
629 - $.extend( result, f.getValues() );
630 - }
631 -
632 - return result;
 722+ var data = this.data( 'formBuilder' );
 723+ return data.mainSection.getValues();
633724 },
634725
635726 /**

Status & tagging log