r94994 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r94993‎ | r94994 | r94995 >
Date:10:54, 19 August 2011
Author:salvatoreingala
Status:deferred
Tags:
Comment:
JSHint, coding conventions, comments and minor refactoring
Modified paths:
  • /branches/salvatoreingala/Gadgets/ui/resources/ext.gadgets.preferences.js (modified) (history)
  • /branches/salvatoreingala/Gadgets/ui/resources/jquery.formBuilder.js (modified) (history)

Diff [purge]

Index: branches/salvatoreingala/Gadgets/ui/resources/ext.gadgets.preferences.js
@@ -40,8 +40,8 @@
4141 function removeStylesheet( styleSheet ) {
4242 var owner =
4343 styleSheet.ownerNode ?
44 - styleSheet.ownerNode : //not-IE or IE >= 9
45 - styleSheet.owningElement //IE < 9
 44+ styleSheet.ownerNode : //not-IE or IE >= 9
 45+ styleSheet.owningElement; //IE < 9
4646 owner.parentNode.removeChild( owner );
4747 }
4848
@@ -69,7 +69,7 @@
7070 //just to avoid code duplication
7171 function error() {
7272 //Remove "wait" cursor
73 - removeStylesheet( waitCSS )
 73+ removeStylesheet( waitCSS );
7474
7575 //Warn the user
7676 showMsg( mw.msg( 'gadgets-save-failed' ) );
@@ -92,7 +92,7 @@
9393 success: function( response ) {
9494 if ( typeof response.error == 'undefined' ) {
9595 //Remove "wait" cursor
96 - removeStylesheet( waitCSS )
 96+ removeStylesheet( waitCSS );
9797
9898 //Notify success to user
9999 showMsg( mw.msg( 'gadgets-save-success' ) );
@@ -102,7 +102,7 @@
103103 //update 'savedConfig'
104104 $dialog.data( 'savedValues', config );
105105 } else {
106 - error()
 106+ error();
107107 }
108108 },
109109 error: error
@@ -134,16 +134,16 @@
135135 dataType: "json", // response type
136136 success: function( response ) {
137137
138 - if ( typeof response.description != 'object'
139 - || typeof response.values != 'object')
 138+ if ( typeof response.description != 'object' ||
 139+ typeof response.values != 'object')
140140 {
141 - alert( mw.msg( 'gadgets-unexpected-error' ) )
 141+ alert( mw.msg( 'gadgets-unexpected-error' ) );
142142 return;
143143 }
144144
145145 //Create and show dialog
146146
147 - var prefsDescription = response.description,
 147+ var prefsDescription = response.description,
148148 values = response.values,
149149 $dialogBody;
150150
@@ -155,9 +155,9 @@
156156 //Hide current message, if any
157157 showMsg( null );
158158
159 - var savedValues = $dialogBody.data( 'savedValues' ),
 159+ var savedValues = $dialogBody.data( 'savedValues' ),
160160 currentValues = $form.formBuilder( 'getValues' );
161 - //TODO: use a better way of comparing values...
 161+
162162 if ( !deepEquals( currentValues, savedValues ) ) {
163163 $( '#mw-gadgets-prefsDialog-save' ).button( 'enable' );
164164 } else {
Index: branches/salvatoreingala/Gadgets/ui/resources/jquery.formBuilder.js
@@ -4,244 +4,12 @@
55 * Released under the MIT and GPL licenses.
66 */
77
8 -(function($, mw) {
 8+( function( $, mw ) {
99
1010 //Field types that can be referred to by preference descriptions
11 - var validFieldTypes = {};
 11+ var validFieldTypes = {}, //filled when costructors are initialized
 12+ prefsSpecifications; //defined later, declaring here to avoid references to undeclared variable
1213
13 - //Describes 'name' and 'label' field members, common to all "simple" fields
14 - var simpleFields = [
15 - {
16 - "name": "name",
17 - "type": "string",
18 - "label": "name",
19 - "required": true,
20 - "maxlength": 40,
21 - "default": ""
22 - },
23 - {
24 - "name": "label",
25 - "type": "string",
26 - "label": "label",
27 - "required": false,
28 - "default": ""
29 - }
30 - ];
31 -
32 - //Used by preference editor to build field properties dialogs
33 - //TODO: document
34 - var prefsDescriptionSpecifications = {
35 - "label": {
36 - "simple": false,
37 - "builder": [ {
38 - "name": "label",
39 - "type": "string",
40 - "label": "label",
41 - "required": false,
42 - "default": ""
43 - } ]
44 - },
45 - "boolean": {
46 - "simple": true,
47 - "builder": simpleFields
48 - },
49 - "string": {
50 - "simple": true,
51 - "builder": simpleFields.concat( [
52 - {
53 - "name": "required",
54 - "type": "boolean",
55 - "label": "required",
56 - "default": false
57 - },
58 - {
59 - "name": "minlength",
60 - "type": "number",
61 - "label": "minlength",
62 - "integer": true,
63 - "min": 0,
64 - "required": false,
65 - "default": null
66 - },
67 - {
68 - "name": "maxlength",
69 - "type": "number",
70 - "label": "maxlength",
71 - "integer": true,
72 - "min": 1,
73 - "required": false,
74 - "default": null
75 - }
76 - ] )
77 - },
78 - "number": {
79 - "simple": true,
80 - "builder": simpleFields.concat( [
81 - {
82 - "name": "required",
83 - "type": "boolean",
84 - "label": "required",
85 - "default": true
86 - },
87 - {
88 - "name": "integer",
89 - "type": "boolean",
90 - "label": "integer",
91 - "default": false
92 - },
93 - {
94 - "name": "min",
95 - "type": "number",
96 - "label": "min",
97 - "required": false,
98 - "default": null
99 - },
100 - {
101 - "name": "max",
102 - "type": "number",
103 - "label": "max",
104 - "required": false,
105 - "default": null
106 - }
107 - ] )
108 - },
109 - "range": {
110 - "simple": true,
111 - "builder": simpleFields.concat( [
112 - {
113 - "name": "min",
114 - "type": "number",
115 - "label": "min",
116 - "required": true,
117 - },
118 - {
119 - "name": "step",
120 - "type": "number",
121 - "label": "step",
122 - "required": true,
123 - "default": 1
124 - },
125 - {
126 - "name": "max",
127 - "type": "number",
128 - "label": "max",
129 - "required": true,
130 - }
131 - ] )
132 - },
133 - "date": {
134 - "simple": true,
135 - "builder": simpleFields
136 - },
137 - "color": {
138 - "simple": true,
139 - "builder": simpleFields
140 - },
141 - "bundle": {
142 - "simple": false,
143 - "builder": function( options, callback ) {
144 - callback(
145 - new BundleField( {
146 - "type": "bundle",
147 - "sections": [
148 - {
149 - "title": "Section 1",
150 - "fields": []
151 - },
152 - {
153 - "title": "Section 2",
154 - "fields": []
155 - }
156 - ]
157 - }, options )
158 - );
159 - }
160 - },
161 - "composite": {
162 - "simple": true,
163 - "builder": [ {
164 - "name": "name",
165 - "type": "string",
166 - "label": "name",
167 - "required": true,
168 - "maxlength": 40,
169 - "default": ""
170 - } ]
171 - },
172 - "list": {
173 - "simple": true,
174 - "builder": function( options, callback ) {
175 -
176 - //Create list of "simple" types
177 - var selectOptions = [];
178 - $.each( prefsDescriptionSpecifications, function( type, typeInfo ) {
179 - if ( typeInfo.simple === true ) {
180 - selectOptions.push( { "name": type, "value": type } );
181 - }
182 - } );
183 -
184 - //Create the dialog to chose the field type
185 - var $form = $( {
186 - fields: [ {
187 - "name": "name",
188 - "type": "string",
189 - "label": "name",
190 - "required": true,
191 - "maxlength": 40,
192 - "default": ""
193 - },
194 - {
195 - "name": "type",
196 - "type": "select",
197 - "label": "type",
198 - "options": selectOptions
199 - } ]
200 - } ).formBuilder( { idPrefix: 'list-chose-type-' } )
201 - .submit( function() {
202 - return false; //prevent form submission
203 - } );
204 -
205 - $form.dialog( {
206 - width: 450,
207 - modal: true,
208 - resizable: false,
209 - title: mw.msg( 'gadgets-formbuilder-editor-create-field-title', 'list' ),
210 - close: function() {
211 - $( this ).remove();
212 - },
213 - buttons: [
214 - {
215 - text: mw.msg( 'gadgets-formbuilder-editor-ok' ),
216 - click: function() {
217 - var values = $( this ).formBuilder( 'getValues' );
218 - $( this ).dialog( "close" );
219 -
220 - var dialog = this;
221 - createFieldDialog( {
222 - type: values.type,
223 - values: {
224 - "name": values.name
225 - },
226 - callback: function( field ) {
227 - $( dialog ).dialog( 'close' );
228 - showEditFieldDialog( field.getDesc(), options, callback );
229 - return true;
230 - }
231 - }, { editable: true } );
232 - }
233 - },
234 - {
235 - text: mw.msg( 'gadgets-formbuilder-editor-cancel' ),
236 - click: function() {
237 - $( this ).dialog( "close" );
238 - }
239 - }
240 - ]
241 - } );
242 - }
243 - }
244 - };
245 -
24614 /* Utility functions */
24715
24816 //Preprocesses strings end possibly replaces them with messages.
@@ -249,7 +17,7 @@
25018 //a message, and the result of mw.msg is returned.
25119 //Two "@@" at the beginning escape for a single "@".
25220 function preproc( msgPrefix, str ) {
253 - if ( str.length <= 1 || str[0] !== '@' ) {
 21+ if ( str.length <= 1 || str.charAt( 0 ) !== '@' ) {
25422 return str;
25523 } else if ( str.substr( 0, 2 ) == '@@' ) {
25624 return str.substr( 1 );
@@ -269,6 +37,7 @@
27038 };
27139 } )();
27240
 41+ //Pads a number with leading zeroes until length is n characters
27342 function pad( n, len ) {
27443 var res = '' + n;
27544 while ( res.length < len ) {
@@ -299,15 +68,41 @@
30069 return $.extend( true, {}, obj );
30170 }
30271
 72+ //EcmaScript 5 standard function, emulate for older browsers
 73+ //From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create
 74+ if ( !Object.create ) {
 75+ Object.create = function ( o ) {
 76+ if ( arguments.length > 1 ) {
 77+ $.error('Object.create implementation only accepts the first parameter.');
 78+ }
 79+ function F() {}
 80+ F.prototype = o;
 81+ return new F();
 82+ };
 83+ }
 84+
 85+ //Add a "smart" listener to watch for changes to an <input /> element
 86+ //This binds to several events, but calls the callback only if the value actually changed
 87+ function addSmartChangeListener( $input, callback ) {
 88+ var oldValue = $input.val();
 89+ //bind all events that may change the value of the field (some are brower-specific)
 90+ $input.bind( 'keyup change propertychange input paste', function() {
 91+ var newValue = $input.val();
 92+ if ( oldValue !== newValue ) {
 93+ oldValue = newValue;
 94+ callback();
 95+ }
 96+ } );
 97+ }
 98+
 99+ /* Validator plugin utility functions and methods */
 100+
303101 function deleteFieldRules( field ) {
304102 //Remove all its validation rules
305103 var validationSettings = field.getValidationSettings();
306104 if ( validationSettings.rules ) {
307105 $.each( validationSettings.rules, function( name, value ) {
308 - var $input = $( '#' + name );
309 - if ( $input.length > 0 ) {
310 - $( '#' + name ).rules( 'remove' );
311 - }
 106+ $( '#' + name ).rules( 'remove' );
312107 } );
313108 }
314109 }
@@ -319,7 +114,7 @@
320115 var $input = $( '#' + name );
321116
322117 //Find messages associated to this rule, if any
323 - if ( typeof validationSettings.messages != 'undefined' &&
 118+ if ( typeof validationSettings.messages != 'undefined' &&
324119 typeof validationSettings.messages[name] != 'undefined')
325120 {
326121 rules.messages = validationSettings.messages[name];
@@ -332,7 +127,55 @@
333128 }
334129 }
335130
336 - function createFieldDialog( params, options ) {
 131+
 132+ function testOptional( value, element ) {
 133+ var rules = $( element ).rules();
 134+ if ( typeof rules.required == 'undefined' || rules.required === false ) {
 135+ if ( value.length === 0 ) {
 136+ return true;
 137+ }
 138+ }
 139+ return false;
 140+ }
 141+
 142+ //validator for "required" fields (without trimming whitespaces)
 143+ $.validator.addMethod( "requiredStrict", function( value, element ) {
 144+ return value.length > 0;
 145+ }, mw.msg( 'gadgets-formbuilder-required' ) );
 146+
 147+ //validator for "minlength" fields (without trimming whitespaces)
 148+ $.validator.addMethod( "minlengthStrict", function( value, element, param ) {
 149+ return testOptional( value, element ) || value.length >= param;
 150+ } );
 151+
 152+ //validator for "maxlength" fields (without trimming whitespaces)
 153+ $.validator.addMethod( "maxlengthStrict", function( value, element, param ) {
 154+ return testOptional( value, element ) || value.length <= param;
 155+ } );
 156+
 157+ //validator for integer fields
 158+ $.validator.addMethod( "integer", function( value, element ) {
 159+ return testOptional( value, element ) || /^-?\d+$/.test(value);
 160+ }, mw.msg( 'gadgets-formbuilder-integer' ) );
 161+
 162+ //validator for datepicker fields
 163+ $.validator.addMethod( "datePicker", function( value, element ) {
 164+ var format = $( element ).datepicker( 'option', 'dateFormat' );
 165+ try {
 166+ var date = $.datepicker.parseDate( format, value );
 167+ return true;
 168+ } catch ( e ) {
 169+ return false;
 170+ }
 171+ }, mw.msg( 'gadgets-formbuilder-date' ) );
 172+
 173+ //validator for colorpicker fields
 174+ $.validator.addMethod( "color", function( value, element ) {
 175+ return $.colorUtil.getRGB( value ) !== undefined;
 176+ }, mw.msg( 'gadgets-formbuilder-color' ) );
 177+
 178+ /* Functions used by the preferences editor */
 179+ function createFieldDialog( params, options ) {
337180 var self = this;
338181
339182 if ( typeof params.callback != 'function' ) {
@@ -399,10 +242,10 @@
400243 return;
401244 } else {
402245 type = params.type;
403 - if ( typeof prefsDescriptionSpecifications[type] == 'undefined' ) {
 246+ if ( typeof prefsSpecifications[type] == 'undefined' ) {
404247 $.error( 'createFieldDialog: invalid type: ' + type );
405 - } else if ( typeof prefsDescriptionSpecifications[type].builder == 'function' ) {
406 - prefsDescriptionSpecifications[type].builder( options, function( field ) {
 248+ } else if ( typeof prefsSpecifications[type].builder == 'function' ) {
 249+ prefsSpecifications[type].builder( options, function( field ) {
407250 if ( field !== null ) {
408251 params.callback( field );
409252 }
@@ -410,10 +253,10 @@
411254 return;
412255 }
413256
414 - //typeof prefsDescriptionSpecifications[type].builder == 'object'
 257+ //typeof prefsSpecifications[type].builder == 'object'
415258
416259 description = {
417 - fields: prefsDescriptionSpecifications[type].builder
 260+ fields: prefsSpecifications[type].builder
418261 };
419262 }
420263
@@ -472,8 +315,8 @@
473316 } );
474317 }
475318
476 - var FieldConstructor = validFieldTypes[type];
477 - var field;
 319+ var FieldConstructor = validFieldTypes[type],
 320+ field;
478321
479322 try {
480323 field = new FieldConstructor( fieldDescription, options );
@@ -521,13 +364,14 @@
522365 {
523366 text: mw.msg( 'gadgets-formbuilder-editor-ok' ),
524367 click: function() {
525 - var fieldDesc = $( this ).formBuilder( 'getDescription' ).fields[0];
 368+ var fieldDesc = $( this ).formBuilder( 'getDescription' ).fields[0],
526369 name = fieldDesc.name;
527370
528371 delete fieldDesc.name;
529372
530373 $( this ).dialog( "close" );
531374
 375+ var ListField = validFieldTypes.list;
532376 callback( new ListField( {
533377 type: 'list',
534378 name: name,
@@ -546,73 +390,6 @@
547391 } );
548392 }
549393
550 - function testOptional( value, element ) {
551 - var rules = $( element ).rules();
552 - if ( typeof rules.required == 'undefined' || rules.required === false ) {
553 - if ( value.length == 0 ) {
554 - return true;
555 - }
556 - }
557 - return false;
558 - }
559 -
560 - //validator for "required" fields (without trimming whitespaces)
561 - $.validator.addMethod( "requiredStrict", function( value, element ) {
562 - return value.length > 0;
563 - }, mw.msg( 'gadgets-formbuilder-required' ) );
564 -
565 - //validator for "minlength" fields (without trimming whitespaces)
566 - $.validator.addMethod( "minlengthStrict", function( value, element, param ) {
567 - return testOptional( value, element ) || value.length >= param;
568 - } );
569 -
570 - //validator for "maxlength" fields (without trimming whitespaces)
571 - $.validator.addMethod( "maxlengthStrict", function( value, element, param ) {
572 - return testOptional( value, element ) || value.length <= param;
573 - } );
574 -
575 - //validator for integer fields
576 - $.validator.addMethod( "integer", function( value, element ) {
577 - return testOptional( value, element ) || /^-?\d+$/.test(value);
578 - }, mw.msg( 'gadgets-formbuilder-integer' ) );
579 -
580 - //validator for datepicker fields
581 - $.validator.addMethod( "datePicker", function( value, element ) {
582 - var format = $( element ).datepicker( 'option', 'dateFormat' );
583 - try {
584 - var date = $.datepicker.parseDate( format, value );
585 - return true;
586 - } catch ( e ) {
587 - return false;
588 - }
589 - }, mw.msg( 'gadgets-formbuilder-date' ) );
590 -
591 - //validator for colorpicker fields
592 - $.validator.addMethod( "color", function( value, element ) {
593 - return $.colorUtil.getRGB( value ) !== undefined;
594 - }, mw.msg( 'gadgets-formbuilder-color' ) );
595 -
596 - //Helper function for inheritance, see http://javascript.crockford.com/prototypal.html
597 - function object(o) {
598 - function F() {}
599 - F.prototype = o;
600 - return new F();
601 - }
602 -
603 - //Add a "smart" listener to watch for changes to an <input /> element
604 - //This binds to several events, but calls the callback only if the value actually changed
605 - function addSmartChangeListener( $input, callback ) {
606 - var oldValue = $input.val();
607 - //bind all events that may change the value of the field (some are brower-specific)
608 - $input.bind( 'keyup change propertychange input paste', function() {
609 - var newValue = $input.val();
610 - if ( oldValue !== newValue ) {
611 - oldValue = newValue;
612 - callback();
613 - }
614 - } );
615 - }
616 -
617394 /* Basic interface for fields */
618395 function Field( desc, options ) {
619396 if ( typeof options.idPrefix == 'undefined' ) {
@@ -645,9 +422,11 @@
646423 };
647424 };
648425
649 - /* A field with no content, generating an empty container */
650 - EmptyField.prototype = object( Field.prototype );
651 - EmptyField.prototype.constructor = EmptyField;
 426+ /*
 427+ * A field with no content, generating an empty container
 428+ * and checking existence and type of the 'type' member of description.
 429+ *
 430+ **/
652431 function EmptyField( desc, options ) {
653432 Field.call( this, desc, options );
654433
@@ -660,14 +439,14 @@
661440 .addClass( 'formbuilder-field formbuilder-field-' + this.desc.type )
662441 .data( 'field', this );
663442 }
 443+ EmptyField.prototype = Object.create( Field.prototype );
 444+ EmptyField.prototype.constructor = EmptyField;
664445
665446 EmptyField.prototype.getElement = function() {
666447 return this.$div;
667448 };
668449
669450 /* A field with just a label */
670 - LabelField.prototype = object( EmptyField.prototype );
671 - LabelField.prototype.constructor = LabelField;
672451 function LabelField( desc, options ) {
673452 EmptyField.call( this, desc, options );
674453
@@ -681,13 +460,13 @@
682461
683462 this.$div.append( this.$label );
684463 }
 464+ LabelField.prototype = Object.create( EmptyField.prototype );
 465+ LabelField.prototype.constructor = LabelField;
685466
686 - validFieldTypes["label"] = LabelField;
 467+ validFieldTypes.label = LabelField;
687468
688469 /* Abstract base class for all "simple" fields. Should not be instantiated. */
689 - SimpleField.prototype = object( LabelField.prototype );
690 - SimpleField.prototype.constructor = SimpleField;
691 - function SimpleField( desc, options ){
 470+ function SimpleField( desc, options ) {
692471 LabelField.call( this, desc, options );
693472
694473 //Validate the 'name' member
@@ -710,6 +489,8 @@
711490 this.options = options;
712491 }
713492 }
 493+ SimpleField.prototype = Object.create( LabelField.prototype );
 494+ SimpleField.prototype.constructor = SimpleField;
714495
715496 SimpleField.prototype.getDesc = function( useValuesAsDefaults ) {
716497 var desc = clone( LabelField.prototype.getDesc.call( this, useValuesAsDefaults ) );
@@ -724,9 +505,7 @@
725506
726507
727508 /* A field with a label and a checkbox */
728 - BooleanField.prototype = object( SimpleField.prototype );
729 - BooleanField.prototype.constructor = BooleanField;
730 - function BooleanField( desc, options ){
 509+ function BooleanField( desc, options ) {
731510 SimpleField.call( this, desc, options );
732511
733512 this.$c = $( '<input/>' ).attr( {
@@ -737,7 +516,7 @@
738517
739518 if ( options.change ) {
740519 this.$c.change( function() {
741 - options.change()
 520+ options.change();
742521 } );
743522 }
744523
@@ -752,21 +531,21 @@
753532
754533 this.$div.append( this.$c );
755534 }
 535+ BooleanField.prototype = Object.create( SimpleField.prototype );
 536+ BooleanField.prototype.constructor = BooleanField;
756537
757538 BooleanField.prototype.getValues = function() {
758539 return pair( this.desc.name, this.$c.is( ':checked' ) );
759540 };
760541
761 - validFieldTypes["boolean"] = BooleanField;
 542+ validFieldTypes.boolean = BooleanField;
762543
763544 /* A field with a textbox accepting string values */
764 - StringField.prototype = object( SimpleField.prototype );
765 - StringField.prototype.constructor = StringField;
766 - function StringField( desc, options ){
 545+ function StringField( desc, options ) {
767546 SimpleField.call( this, desc, options );
768547
769548 //Validate minlength and maxlength
770 - var minlength = typeof desc.minlength != 'undefined' ? desc.minlength : 0,
 549+ var minlength = typeof desc.minlength != 'undefined' ? desc.minlength : 0,
771550 maxlength = typeof desc.maxlength != 'undefined' ? desc.maxlength : 1024;
772551
773552 if ( !isInteger( minlength ) || minlength < 0 ) {
@@ -801,6 +580,8 @@
802581
803582 this.$div.append( this.$text );
804583 }
 584+ StringField.prototype = Object.create( SimpleField.prototype );
 585+ StringField.prototype.constructor = StringField;
805586
806587 StringField.prototype.getValues = function() {
807588 return pair( this.desc.name, this.$text.val() );
@@ -835,21 +616,19 @@
836617 return settings;
837618 };
838619
839 - validFieldTypes["string"] = StringField;
 620+ validFieldTypes.string = StringField;
840621
841622
842623 /* A field with a textbox accepting numeric values */
843 - NumberField.prototype = object( SimpleField.prototype );
844 - NumberField.prototype.constructor = NumberField;
845 - function NumberField( desc, options ){
 624+ function NumberField( desc, options ) {
846625 SimpleField.call( this, desc, options );
847626
848627 //Validation of description
849628 if ( desc.integer === true ) {
850 - if ( typeof desc.min != 'undefined' && !isInteger( desc.min ) ){
 629+ if ( typeof desc.min != 'undefined' && !isInteger( desc.min ) ) {
851630 $.error( "min is not an integer" );
852631 }
853 - if ( typeof desc.max != 'undefined' && !isInteger( desc.max ) ){
 632+ if ( typeof desc.max != 'undefined' && !isInteger( desc.max ) ) {
854633 $.error( "max is not an integer" );
855634 }
856635 }
@@ -881,6 +660,8 @@
882661
883662 this.$div.append( this.$text );
884663 }
 664+ NumberField.prototype = Object.create( SimpleField.prototype );
 665+ NumberField.prototype.constructor = NumberField;
885666
886667 NumberField.prototype.getValues = function() {
887668 var val = parseFloat( this.$text.val() );
@@ -922,12 +703,10 @@
923704 return settings;
924705 };
925706
926 - validFieldTypes["number"] = NumberField;
 707+ validFieldTypes.number = NumberField;
927708
928709 /* A field with a drop-down list */
929 - SelectField.prototype = object( SimpleField.prototype );
930 - SelectField.prototype.constructor = SelectField;
931 - function SelectField( desc, options ){
 710+ function SelectField( desc, options ) {
932711 SimpleField.call( this, desc, options );
933712
934713 var $select = this.$select = $( '<select/>' ).attr( {
@@ -935,8 +714,8 @@
936715 name: this.options.idPrefix + this.desc.name
937716 } );
938717
939 - var validValues = [];
940 - var self = this;
 718+ var validValues = [],
 719+ self = this;
941720 $.each( this.desc.options, function( idx, option ) {
942721 var i = validValues.length;
943722 $( '<option/>' )
@@ -967,18 +746,18 @@
968747
969748 this.$div.append( $select );
970749 }
 750+ SelectField.prototype = Object.create( SimpleField.prototype );
 751+ SelectField.prototype.constructor = SelectField;
971752
972753 SelectField.prototype.getValues = function() {
973754 var i = parseInt( this.$select.val(), 10 );
974755 return pair( this.desc.name, this.validValues[i] );
975756 };
976757
977 - validFieldTypes["select"] = SelectField;
 758+ validFieldTypes.select = SelectField;
978759
979760 /* A field with a slider, representing ranges of numbers */
980 - RangeField.prototype = object( SimpleField.prototype );
981 - RangeField.prototype.constructor = RangeField;
982 - function RangeField( desc, options ){
 761+ function RangeField( desc, options ) {
983762 SimpleField.call( this, desc, options );
984763
985764 //Validation
@@ -1065,11 +844,13 @@
1066845 }, 1 );
1067846 },
1068847 stop: function( event, ui ) {
 848+ //After a delay, hide tooltip if the handle doesn't have focus and pointer isn't over the handle.
1069849 setTimeout( function() {
1070 - if ( !$handle.is( ':focus' ) && !mouseOver) {
 850+ if ( !$slider.find( '.ui-slider-handle' ).is( ':focus' ) && !mouseOver ) {
1071851 refreshTooltip( false, $slider.find( '.ui-slider-handle' ), ui.value );
1072852 }
1073853 }, 300 );
 854+
1074855 sliding = false;
1075856 },
1076857 change: function( event, ui ) {
@@ -1103,17 +884,17 @@
1104885
1105886 this.$div.append( $slider );
1106887 }
 888+ RangeField.prototype = Object.create( SimpleField.prototype );
 889+ RangeField.prototype.constructor = RangeField;
1107890
1108891 RangeField.prototype.getValues = function() {
1109892 return pair( this.desc.name, this.$slider.slider( 'value' ) );
1110893 };
1111894
1112 - validFieldTypes["range"] = RangeField;
 895+ validFieldTypes.range = RangeField;
1113896
1114897 /* A field with a textbox with a datepicker */
1115 - DateField.prototype = object( SimpleField.prototype );
1116 - DateField.prototype.constructor = DateField;
1117 - function DateField( desc, options ){
 898+ function DateField( desc, options ) {
1118899 SimpleField.call( this, desc, options );
1119900
1120901 var $text = this.$text = $( '<input/>' )
@@ -1130,8 +911,8 @@
1131912 }
1132913 } );
1133914
1134 - var value = options.values && options.values[this.desc.name];
1135 - var date;
 915+ var value = options.values && options.values[this.desc.name],
 916+ date;
1136917 if ( typeof value != 'undefined' && value !== null ) {
1137918 date = new Date( value );
1138919
@@ -1149,9 +930,11 @@
1150931
1151932 this.$div.append( this.$text );
1152933 }
 934+ DateField.prototype = Object.create( SimpleField.prototype );
 935+ DateField.prototype.constructor = DateField;
1153936
1154937 DateField.prototype.getValues = function() {
1155 - var d = this.$text.datepicker( 'getDate' ),
 938+ var d = this.$text.datepicker( 'getDate' ),
1156939 res = {};
1157940
1158941 if ( d === null ) {
@@ -1178,7 +961,7 @@
1179962 return settings;
1180963 };
1181964
1182 - validFieldTypes["date"] = DateField;
 965+ validFieldTypes.date = DateField;
1183966
1184967 /* A field with color picker */
1185968
@@ -1191,16 +974,15 @@
1192975 //If a click happens outside the colorpicker while it is showed, remove it
1193976 $( document ).mousedown( function( event ) {
1194977 var $target = $( event.target );
1195 - if ( $target.parents( '#colorpicker' ).length == 0 ) {
 978+ if ( $target.parents( '#colorpicker' ).length === 0 ) {
1196979 closeColorPicker();
1197980 }
1198981 } );
1199982
1200 - ColorField.prototype = object( SimpleField.prototype );
1201 - ColorField.prototype.constructor = ColorField;
1202 - function ColorField( desc, options ){
 983+ function ColorField( desc, options ) {
1203984 SimpleField.call( this, desc, options );
1204985
 986+ var value;
1205987 if ( typeof options.values != 'undefined' && typeof options.values[this.desc.name] != 'undefined' ) {
1206988 value = options.values[this.desc.name];
1207989 } else {
@@ -1252,6 +1034,8 @@
12531035
12541036 this.$div.append( this.$text );
12551037 }
 1038+ ColorField.prototype = Object.create( SimpleField.prototype );
 1039+ ColorField.prototype.constructor = ColorField;
12561040
12571041 ColorField.prototype.getValidationSettings = function() {
12581042 var settings = SimpleField.prototype.getValidationSettings.call( this ),
@@ -1273,13 +1057,11 @@
12741058 }
12751059 };
12761060
1277 - validFieldTypes["color"] = ColorField;
 1061+ validFieldTypes.color = ColorField;
12781062
12791063
12801064 /* A field that represent a section (group of fields) */
12811065
1282 - SectionField.prototype = object( Field.prototype );
1283 - SectionField.prototype.constructor = SectionField;
12841066 function SectionField( desc, options, id ) {
12851067 Field.call( this, desc, options );
12861068
@@ -1295,7 +1077,7 @@
12961078 this._createSlot( 'yes' ).appendTo( this.$div );
12971079 }
12981080
1299 - var field = this.desc.fields[i],
 1081+ var field = this.desc.fields[i],
13001082 FieldConstructor = validFieldTypes[field.type];
13011083
13021084 if ( typeof FieldConstructor != 'function' ) {
@@ -1309,7 +1091,7 @@
13101092 editable = 'no';
13111093 }
13121094
1313 - var f = new FieldConstructor( field, options ),
 1095+ var f = new FieldConstructor( field, options ),
13141096 $slot = this._createSlot( editable, f );
13151097
13161098 $slot.appendTo( this.$div );
@@ -1320,6 +1102,8 @@
13211103 this._createSlot( 'yes' ).appendTo( this.$div );
13221104 }
13231105 }
 1106+ SectionField.prototype = Object.create( Field.prototype );
 1107+ SectionField.prototype.constructor = SectionField;
13241108
13251109 SectionField.prototype.getElement = function() {
13261110 return this.$div;
@@ -1379,7 +1163,7 @@
13801164 };
13811165
13821166 SectionField.prototype._createSlot = function( editable, field ) {
1383 - var self = this,
 1167+ var self = this,
13841168 $slot = $( '<div/>' ).addClass( 'formbuilder-slot ui-widget' ),
13851169 $divButtons;
13861170
@@ -1413,7 +1197,7 @@
14141198 //Add the button for changing existing slots
14151199 var type = field.getDesc().type;
14161200 //TODO: using the 'builder' info is not optimal
1417 - if ( typeof prefsDescriptionSpecifications[type].builder != 'function' ) {
 1201+ if ( typeof prefsSpecifications[type].builder != 'function' ) {
14181202 $( '<a href="javascript:;" />' )
14191203 .addClass( 'formbuilder-button formbuilder-editor-button-edit ui-icon ui-icon-gear' )
14201204 .attr( 'title', mw.msg( 'gadgets-formbuilder-editor-edit-field' ) )
@@ -1425,7 +1209,7 @@
14261210 callback: function( newField ) {
14271211 if ( newField !== null ) {
14281212 //check that there are no duplicate preference names
1429 - var existingValues = self.$div.closest( '.formbuilder' ).formBuilder( 'getValues' ),
 1213+ var existingValues = self.$div.closest( '.formbuilder' ).formBuilder( 'getValues' ),
14301214 removedValues = field.getValues(),
14311215 duplicateName = null;
14321216 $.each( field.getValues(), function( name, val ) {
@@ -1463,13 +1247,13 @@
14641248 .addClass( 'formbuilder-button formbuilder-editor-button-delete ui-icon ui-icon-trash' )
14651249 .attr( 'title', mw.msg( 'gadgets-formbuilder-editor-delete-field' ) )
14661250 .click( function( event, ui ) {
1467 - //Make both slots disappear, then delete them
 1251+ //Make both slots disappear, then delete them
14681252 $.each( [$slot, $slot.prev()], function( idx, $s ) {
14691253 $s.slideUp( function() {
14701254 self._deleteSlot( $s );
14711255 } );
14721256 } );
1473 - } )
 1257+ } )
14741258 .appendTo( $divButtons );
14751259
14761260 //Make this slot draggable to allow moving it
@@ -1495,7 +1279,8 @@
14961280 hoverClass: 'formbuilder-slot-can-drop',
14971281 tolerance: 'pointer',
14981282 drop: function( event, ui ) {
1499 - var srcSlot = ui.draggable, dstSlot = this;
 1283+ var srcSlot = ui.draggable,
 1284+ dstSlot = this;
15001285
15011286 //Remove one empty slot surrounding source
15021287 $( srcSlot ).prev().remove();
@@ -1524,7 +1309,7 @@
15251310 callback: function( field ) {
15261311 if ( field !== null ) {
15271312 //check that there are no duplicate preference names
1528 - var existingValues = $slot.closest( '.formbuilder' ).formBuilder( 'getValues' ),
 1313+ var existingValues = $slot.closest( '.formbuilder' ).formBuilder( 'getValues' ),
15291314 duplicateName = null;
15301315 $.each( field.getValues(), function( name, val ) {
15311316 if ( typeof existingValues[name] != 'undefined' ) {
@@ -1538,7 +1323,7 @@
15391324 return false;
15401325 }
15411326
1542 - var $newSlot = self._createSlot( 'yes', field ).hide(),
 1327+ var $newSlot = self._createSlot( 'yes', field ).hide(),
15431328 $newEmptySlot = self._createSlot( 'yes' ).hide();
15441329
15451330 $slot.after( $newSlot, $newEmptySlot );
@@ -1563,9 +1348,7 @@
15641349 };
15651350
15661351
1567 - /* A field for 'bundle's */
1568 - BundleField.prototype = object( EmptyField.prototype );
1569 - BundleField.prototype.constructor = BundleField;
 1352+ /* A field for 'bundle' type fields */
15701353 function BundleField( desc, options ) {
15711354 EmptyField.call( this, desc, options );
15721355
@@ -1583,7 +1366,7 @@
15841367 tolerance: 'pointer',
15851368 accept: '.formbuilder-slot-nonempty',
15861369 drop: function( event, ui ) {
1587 - var $slot = $( ui.draggable ),
 1370+ var $slot = $( ui.draggable ),
15881371 $srcSection = $slot.parent(),
15891372 $dstSection = $( section );
15901373
@@ -1622,7 +1405,7 @@
16231406 .addClass( 'formbuilder-button formbuilder-editor-button-edit-section ui-icon ui-icon-gear' )
16241407 .attr( 'title', mw.msg( 'gadgets-formbuilder-editor-edit-section' ) )
16251408 .click( function() {
1626 - var button = this,
 1409+ var button = this,
16271410 sectionField = $( ui.panel ).data( 'field' );
16281411
16291412 $( {
@@ -1673,15 +1456,15 @@
16741457 } );
16751458
16761459 //Save for future reference
1677 - this.$ui_tabs_nav = $tabs.find( '.ui-tabs-nav' )
 1460+ this.$ui_tabs_nav = $tabs.find( '.ui-tabs-nav' );
16781461
16791462 var self = this;
16801463 $.each( this.desc.sections, function( index, sectionDescription ) {
1681 - var id = self.options.idPrefix + 'section-' + getIncrementalCounter(),
 1464+ var id = self.options.idPrefix + 'section-' + getIncrementalCounter(),
16821465 sec = new SectionField( sectionDescription, options, id );
16831466
16841467 $tabs.append( sec.getElement() )
1685 - .tabs( 'add', '#' + id, preproc( options.msgPrefix, sectionDescription.title ) );
 1468+ .tabs( 'add', '#' + id, preproc( options.msgPrefix, sectionDescription.title ) );
16861469 } );
16871470
16881471 if ( options.editable === true ) {
@@ -1707,7 +1490,7 @@
17081491 {
17091492 text: mw.msg( 'gadgets-formbuilder-editor-ok' ),
17101493 click: function() {
1711 - var title = $( this ).formBuilder( 'getValues' ).title,
 1494+ var title = $( this ).formBuilder( 'getValues' ).title,
17121495 id = self.options.idPrefix + 'section-' + getIncrementalCounter(),
17131496 newSectionDescription = {
17141497 title: title,
@@ -1742,11 +1525,13 @@
17431526
17441527 this.$div.append( $tabs );
17451528 }
 1529+ BundleField.prototype = Object.create( EmptyField.prototype );
 1530+ BundleField.prototype.constructor = BundleField;
17461531
17471532 BundleField.prototype.getValidationSettings = function() {
17481533 var settings = {};
17491534 this.$ui_tabs_nav.find( 'a' ).each( function( idx, anchor ) {
1750 - var panel = $( anchor ).data( 'panel' ),
 1535+ var panel = $( anchor ).data( 'panel' ),
17511536 field = $( panel ).data( 'field' );
17521537
17531538 $.extend( true, settings, field.getValidationSettings() );
@@ -1758,7 +1543,7 @@
17591544 var desc = clone( this.desc );
17601545 desc.sections = [];
17611546 this.$ui_tabs_nav.find( 'a' ).each( function( idx, anchor ) {
1762 - var panel = $( anchor ).data( 'panel' ),
 1547+ var panel = $( anchor ).data( 'panel' ),
17631548 field = $( panel ).data( 'field' );
17641549
17651550 desc.sections.push( field.getDesc( useValuesAsDefaults ) );
@@ -1769,7 +1554,7 @@
17701555 BundleField.prototype.getValues = function() {
17711556 var values = {};
17721557 this.$ui_tabs_nav.find( 'a' ).each( function( idx, anchor ) {
1773 - var panel = $( anchor ).data( 'panel' ),
 1558+ var panel = $( anchor ).data( 'panel' ),
17741559 field = $( panel ).data( 'field' );
17751560
17761561 $.extend( values, field.getValues() );
@@ -1777,13 +1562,11 @@
17781563 return values;
17791564 };
17801565
1781 - validFieldTypes["bundle"] = BundleField;
 1566+ validFieldTypes.bundle = BundleField;
17821567
17831568
17841569 /* A field for 'composite' fields */
17851570
1786 - CompositeField.prototype = object( EmptyField.prototype );
1787 - CompositeField.prototype.constructor = CompositeField;
17881571 function CompositeField( desc, options ) {
17891572 EmptyField.call( this, desc, options );
17901573
@@ -1811,6 +1594,8 @@
18121595 this._section = new SectionField( desc, sectionOptions );
18131596 this.$div.append( this._section.getElement() );
18141597 }
 1598+ CompositeField.prototype = Object.create( EmptyField.prototype );
 1599+ CompositeField.prototype.constructor = CompositeField;
18151600
18161601 CompositeField.prototype.getDesc = function( useValuesAsDefaults ) {
18171602 var desc = clone( this.desc );
@@ -1826,12 +1611,10 @@
18271612 return this._section.getValidationSettings();
18281613 };
18291614
1830 - validFieldTypes["composite"] = CompositeField;
 1615+ validFieldTypes.composite = CompositeField;
18311616
18321617 /* A field for 'composite' fields */
18331618
1834 - ListField.prototype = object( EmptyField.prototype );
1835 - ListField.prototype.constructor = ListField;
18361619 function ListField( desc, options ) {
18371620 EmptyField.call( this, desc, options );
18381621
@@ -1844,7 +1627,7 @@
18451628 }
18461629
18471630 if ( ( typeof desc.field.type != 'string' )
1848 - || prefsDescriptionSpecifications[desc.field.type].simple !== true )
 1631+ || prefsSpecifications[desc.field.type].simple !== true )
18491632 {
18501633 $.error( "Missing or invalid field type specified in 'field' parameter." );
18511634 }
@@ -1855,8 +1638,8 @@
18561639 options.values = {};
18571640 }
18581641
1859 - var value = ( typeof options.values[desc.name] != 'undefined' ) ? options.values[desc.name] : desc['default'];
1860 - var self = this;
 1642+ var value = ( typeof options.values[desc.name] != 'undefined' ) ? options.values[desc.name] : desc['default'],
 1643+ self = this;
18611644 if ( typeof value != 'undefined' ) {
18621645 $.each( value, function( index, itemValue ) {
18631646 self._createItem( false, itemValue );
@@ -1880,12 +1663,14 @@
18811664 } )
18821665 .appendTo( this.$div );
18831666 }
 1667+ ListField.prototype = Object.create( EmptyField.prototype );
 1668+ ListField.prototype.constructor = ListField;
18841669
18851670 ListField.prototype._createItem = function( animated, itemValue ) {
1886 - var itemDesc = $.extend( {}, this.desc.field, {
 1671+ var itemDesc = $.extend( {}, this.desc.field, {
18871672 "name": this.desc.name
1888 - } );
1889 - var itemOptions = $.extend( {}, this.options, {
 1673+ } ),
 1674+ itemOptions = $.extend( {}, this.options, {
18901675 editable: false,
18911676 idPrefix: this.options.idPrefix + getIncrementalCounter() + "-"
18921677 } );
@@ -1896,15 +1681,14 @@
18971682 itemOptions.values = pair( this.desc.name, this.desc.field['default'] );
18981683 }
18991684
1900 - var FieldConstructor = validFieldTypes[this.desc.field.type];
1901 - var itemField = new FieldConstructor( itemDesc, itemOptions );
1902 - var $itemDiv = $( '<div/>' )
1903 - .addClass( 'formbuilder-list-item' )
1904 - .data( 'field', itemField );
1905 -
1906 - var $itemContent = $( '<div/>' )
1907 - .addClass( 'formbuilder-list-item-content' )
1908 - .append( itemField.getElement() );
 1685+ var FieldConstructor = validFieldTypes[this.desc.field.type],
 1686+ itemField = new FieldConstructor( itemDesc, itemOptions ),
 1687+ $itemDiv = $( '<div/>' )
 1688+ .addClass( 'formbuilder-list-item' )
 1689+ .data( 'field', itemField ),
 1690+ $itemContent = $( '<div/>' )
 1691+ .addClass( 'formbuilder-list-item-content' )
 1692+ .append( itemField.getElement() );
19091693
19101694 $( '<div/>' )
19111695 .addClass( 'formbuilder-list-item-container' )
@@ -1974,9 +1758,244 @@
19751759 return validationSettings;
19761760 };
19771761
1978 - validFieldTypes["list"] = ListField;
 1762+ validFieldTypes.list = ListField;
19791763
19801764
 1765+ /* Specifications of preferences descriptions syntax and field types */
 1766+
 1767+ //Describes 'name' and 'label' field members, common to all "simple" fields
 1768+ var simpleFields = [
 1769+ {
 1770+ "name": "name",
 1771+ "type": "string",
 1772+ "label": "name",
 1773+ "required": true,
 1774+ "maxlength": 40,
 1775+ "default": ""
 1776+ },
 1777+ {
 1778+ "name": "label",
 1779+ "type": "string",
 1780+ "label": "label",
 1781+ "required": false,
 1782+ "default": ""
 1783+ }
 1784+ ];
 1785+
 1786+ //Used by preference editor to build field properties dialogs
 1787+ //TODO: document
 1788+ prefsSpecifications = {
 1789+ "label": {
 1790+ "simple": false,
 1791+ "builder": [ {
 1792+ "name": "label",
 1793+ "type": "string",
 1794+ "label": "label",
 1795+ "required": false,
 1796+ "default": ""
 1797+ } ]
 1798+ },
 1799+ "boolean": {
 1800+ "simple": true,
 1801+ "builder": simpleFields
 1802+ },
 1803+ "string": {
 1804+ "simple": true,
 1805+ "builder": simpleFields.concat( [
 1806+ {
 1807+ "name": "required",
 1808+ "type": "boolean",
 1809+ "label": "required",
 1810+ "default": false
 1811+ },
 1812+ {
 1813+ "name": "minlength",
 1814+ "type": "number",
 1815+ "label": "minlength",
 1816+ "integer": true,
 1817+ "min": 0,
 1818+ "required": false,
 1819+ "default": null
 1820+ },
 1821+ {
 1822+ "name": "maxlength",
 1823+ "type": "number",
 1824+ "label": "maxlength",
 1825+ "integer": true,
 1826+ "min": 1,
 1827+ "required": false,
 1828+ "default": null
 1829+ }
 1830+ ] )
 1831+ },
 1832+ "number": {
 1833+ "simple": true,
 1834+ "builder": simpleFields.concat( [
 1835+ {
 1836+ "name": "required",
 1837+ "type": "boolean",
 1838+ "label": "required",
 1839+ "default": true
 1840+ },
 1841+ {
 1842+ "name": "integer",
 1843+ "type": "boolean",
 1844+ "label": "integer",
 1845+ "default": false
 1846+ },
 1847+ {
 1848+ "name": "min",
 1849+ "type": "number",
 1850+ "label": "min",
 1851+ "required": false,
 1852+ "default": null
 1853+ },
 1854+ {
 1855+ "name": "max",
 1856+ "type": "number",
 1857+ "label": "max",
 1858+ "required": false,
 1859+ "default": null
 1860+ }
 1861+ ] )
 1862+ },
 1863+ "range": {
 1864+ "simple": true,
 1865+ "builder": simpleFields.concat( [
 1866+ {
 1867+ "name": "min",
 1868+ "type": "number",
 1869+ "label": "min",
 1870+ "required": true
 1871+ },
 1872+ {
 1873+ "name": "step",
 1874+ "type": "number",
 1875+ "label": "step",
 1876+ "required": true,
 1877+ "default": 1
 1878+ },
 1879+ {
 1880+ "name": "max",
 1881+ "type": "number",
 1882+ "label": "max",
 1883+ "required": true
 1884+ }
 1885+ ] )
 1886+ },
 1887+ "date": {
 1888+ "simple": true,
 1889+ "builder": simpleFields
 1890+ },
 1891+ "color": {
 1892+ "simple": true,
 1893+ "builder": simpleFields
 1894+ },
 1895+ "bundle": {
 1896+ "simple": false,
 1897+ "builder": function( options, callback ) {
 1898+ callback(
 1899+ new BundleField( {
 1900+ "type": "bundle",
 1901+ "sections": [
 1902+ {
 1903+ "title": "Section 1",
 1904+ "fields": []
 1905+ },
 1906+ {
 1907+ "title": "Section 2",
 1908+ "fields": []
 1909+ }
 1910+ ]
 1911+ }, options )
 1912+ );
 1913+ }
 1914+ },
 1915+ "composite": {
 1916+ "simple": true,
 1917+ "builder": [ {
 1918+ "name": "name",
 1919+ "type": "string",
 1920+ "label": "name",
 1921+ "required": true,
 1922+ "maxlength": 40,
 1923+ "default": ""
 1924+ } ]
 1925+ },
 1926+ "list": {
 1927+ "simple": true,
 1928+ "builder": function( options, callback ) {
 1929+
 1930+ //Create list of "simple" types
 1931+ var selectOptions = [];
 1932+ $.each( prefsSpecifications, function( type, typeInfo ) {
 1933+ if ( typeInfo.simple === true ) {
 1934+ selectOptions.push( { "name": type, "value": type } );
 1935+ }
 1936+ } );
 1937+
 1938+ //Create the dialog to chose the field type
 1939+ var $form = $( {
 1940+ fields: [ {
 1941+ "name": "name",
 1942+ "type": "string",
 1943+ "label": "name",
 1944+ "required": true,
 1945+ "maxlength": 40,
 1946+ "default": ""
 1947+ },
 1948+ {
 1949+ "name": "type",
 1950+ "type": "select",
 1951+ "label": "type",
 1952+ "options": selectOptions
 1953+ } ]
 1954+ } ).formBuilder( { idPrefix: 'list-chose-type-' } )
 1955+ .submit( function() {
 1956+ return false; //prevent form submission
 1957+ } );
 1958+
 1959+ $form.dialog( {
 1960+ width: 450,
 1961+ modal: true,
 1962+ resizable: false,
 1963+ title: mw.msg( 'gadgets-formbuilder-editor-create-field-title', 'list' ),
 1964+ close: function() {
 1965+ $( this ).remove();
 1966+ },
 1967+ buttons: [
 1968+ {
 1969+ text: mw.msg( 'gadgets-formbuilder-editor-ok' ),
 1970+ click: function() {
 1971+ var values = $( this ).formBuilder( 'getValues' );
 1972+ $( this ).dialog( "close" );
 1973+
 1974+ var $dialog = $( this );
 1975+ createFieldDialog( {
 1976+ type: values.type,
 1977+ values: {
 1978+ "name": values.name
 1979+ },
 1980+ callback: function( field ) {
 1981+ $dialog.dialog( 'close' );
 1982+ showEditFieldDialog( field.getDesc(), options, callback );
 1983+ return true;
 1984+ }
 1985+ }, { editable: true } );
 1986+ }
 1987+ },
 1988+ {
 1989+ text: mw.msg( 'gadgets-formbuilder-editor-cancel' ),
 1990+ click: function() {
 1991+ $( this ).dialog( "close" );
 1992+ }
 1993+ }
 1994+ ]
 1995+ } );
 1996+ }
 1997+ }
 1998+ };
 1999+
19812000 /* Public methods */
19822001
19832002 /**
@@ -2072,5 +2091,5 @@
20732092 $.error( 'Method ' + method + ' does not exist on jQuery.formBuilder' );
20742093 }
20752094 };
2076 -})( jQuery, mediaWiki );
 2095+} )( jQuery, mediaWiki );
20772096

Status & tagging log