Index: branches/salvatoreingala/Gadgets/ui/resources/ext.gadgets.preferences.js |
— | — | @@ -40,8 +40,8 @@ |
41 | 41 | function removeStylesheet( styleSheet ) { |
42 | 42 | var owner = |
43 | 43 | 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 |
46 | 46 | owner.parentNode.removeChild( owner ); |
47 | 47 | } |
48 | 48 | |
— | — | @@ -69,7 +69,7 @@ |
70 | 70 | //just to avoid code duplication |
71 | 71 | function error() { |
72 | 72 | //Remove "wait" cursor |
73 | | - removeStylesheet( waitCSS ) |
| 73 | + removeStylesheet( waitCSS ); |
74 | 74 | |
75 | 75 | //Warn the user |
76 | 76 | showMsg( mw.msg( 'gadgets-save-failed' ) ); |
— | — | @@ -92,7 +92,7 @@ |
93 | 93 | success: function( response ) { |
94 | 94 | if ( typeof response.error == 'undefined' ) { |
95 | 95 | //Remove "wait" cursor |
96 | | - removeStylesheet( waitCSS ) |
| 96 | + removeStylesheet( waitCSS ); |
97 | 97 | |
98 | 98 | //Notify success to user |
99 | 99 | showMsg( mw.msg( 'gadgets-save-success' ) ); |
— | — | @@ -102,7 +102,7 @@ |
103 | 103 | //update 'savedConfig' |
104 | 104 | $dialog.data( 'savedValues', config ); |
105 | 105 | } else { |
106 | | - error() |
| 106 | + error(); |
107 | 107 | } |
108 | 108 | }, |
109 | 109 | error: error |
— | — | @@ -134,16 +134,16 @@ |
135 | 135 | dataType: "json", // response type |
136 | 136 | success: function( response ) { |
137 | 137 | |
138 | | - if ( typeof response.description != 'object' |
139 | | - || typeof response.values != 'object') |
| 138 | + if ( typeof response.description != 'object' || |
| 139 | + typeof response.values != 'object') |
140 | 140 | { |
141 | | - alert( mw.msg( 'gadgets-unexpected-error' ) ) |
| 141 | + alert( mw.msg( 'gadgets-unexpected-error' ) ); |
142 | 142 | return; |
143 | 143 | } |
144 | 144 | |
145 | 145 | //Create and show dialog |
146 | 146 | |
147 | | - var prefsDescription = response.description, |
| 147 | + var prefsDescription = response.description, |
148 | 148 | values = response.values, |
149 | 149 | $dialogBody; |
150 | 150 | |
— | — | @@ -155,9 +155,9 @@ |
156 | 156 | //Hide current message, if any |
157 | 157 | showMsg( null ); |
158 | 158 | |
159 | | - var savedValues = $dialogBody.data( 'savedValues' ), |
| 159 | + var savedValues = $dialogBody.data( 'savedValues' ), |
160 | 160 | currentValues = $form.formBuilder( 'getValues' ); |
161 | | - //TODO: use a better way of comparing values... |
| 161 | + |
162 | 162 | if ( !deepEquals( currentValues, savedValues ) ) { |
163 | 163 | $( '#mw-gadgets-prefsDialog-save' ).button( 'enable' ); |
164 | 164 | } else { |
Index: branches/salvatoreingala/Gadgets/ui/resources/jquery.formBuilder.js |
— | — | @@ -4,244 +4,12 @@ |
5 | 5 | * Released under the MIT and GPL licenses. |
6 | 6 | */ |
7 | 7 | |
8 | | -(function($, mw) { |
| 8 | +( function( $, mw ) { |
9 | 9 | |
10 | 10 | //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 |
12 | 13 | |
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 | | - |
246 | 14 | /* Utility functions */ |
247 | 15 | |
248 | 16 | //Preprocesses strings end possibly replaces them with messages. |
— | — | @@ -249,7 +17,7 @@ |
250 | 18 | //a message, and the result of mw.msg is returned. |
251 | 19 | //Two "@@" at the beginning escape for a single "@". |
252 | 20 | function preproc( msgPrefix, str ) { |
253 | | - if ( str.length <= 1 || str[0] !== '@' ) { |
| 21 | + if ( str.length <= 1 || str.charAt( 0 ) !== '@' ) { |
254 | 22 | return str; |
255 | 23 | } else if ( str.substr( 0, 2 ) == '@@' ) { |
256 | 24 | return str.substr( 1 ); |
— | — | @@ -269,6 +37,7 @@ |
270 | 38 | }; |
271 | 39 | } )(); |
272 | 40 | |
| 41 | + //Pads a number with leading zeroes until length is n characters |
273 | 42 | function pad( n, len ) { |
274 | 43 | var res = '' + n; |
275 | 44 | while ( res.length < len ) { |
— | — | @@ -299,15 +68,41 @@ |
300 | 69 | return $.extend( true, {}, obj ); |
301 | 70 | } |
302 | 71 | |
| 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 | + |
303 | 101 | function deleteFieldRules( field ) { |
304 | 102 | //Remove all its validation rules |
305 | 103 | var validationSettings = field.getValidationSettings(); |
306 | 104 | if ( validationSettings.rules ) { |
307 | 105 | $.each( validationSettings.rules, function( name, value ) { |
308 | | - var $input = $( '#' + name ); |
309 | | - if ( $input.length > 0 ) { |
310 | | - $( '#' + name ).rules( 'remove' ); |
311 | | - } |
| 106 | + $( '#' + name ).rules( 'remove' ); |
312 | 107 | } ); |
313 | 108 | } |
314 | 109 | } |
— | — | @@ -319,7 +114,7 @@ |
320 | 115 | var $input = $( '#' + name ); |
321 | 116 | |
322 | 117 | //Find messages associated to this rule, if any |
323 | | - if ( typeof validationSettings.messages != 'undefined' && |
| 118 | + if ( typeof validationSettings.messages != 'undefined' && |
324 | 119 | typeof validationSettings.messages[name] != 'undefined') |
325 | 120 | { |
326 | 121 | rules.messages = validationSettings.messages[name]; |
— | — | @@ -332,7 +127,55 @@ |
333 | 128 | } |
334 | 129 | } |
335 | 130 | |
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 ) { |
337 | 180 | var self = this; |
338 | 181 | |
339 | 182 | if ( typeof params.callback != 'function' ) { |
— | — | @@ -399,10 +242,10 @@ |
400 | 243 | return; |
401 | 244 | } else { |
402 | 245 | type = params.type; |
403 | | - if ( typeof prefsDescriptionSpecifications[type] == 'undefined' ) { |
| 246 | + if ( typeof prefsSpecifications[type] == 'undefined' ) { |
404 | 247 | $.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 ) { |
407 | 250 | if ( field !== null ) { |
408 | 251 | params.callback( field ); |
409 | 252 | } |
— | — | @@ -410,10 +253,10 @@ |
411 | 254 | return; |
412 | 255 | } |
413 | 256 | |
414 | | - //typeof prefsDescriptionSpecifications[type].builder == 'object' |
| 257 | + //typeof prefsSpecifications[type].builder == 'object' |
415 | 258 | |
416 | 259 | description = { |
417 | | - fields: prefsDescriptionSpecifications[type].builder |
| 260 | + fields: prefsSpecifications[type].builder |
418 | 261 | }; |
419 | 262 | } |
420 | 263 | |
— | — | @@ -472,8 +315,8 @@ |
473 | 316 | } ); |
474 | 317 | } |
475 | 318 | |
476 | | - var FieldConstructor = validFieldTypes[type]; |
477 | | - var field; |
| 319 | + var FieldConstructor = validFieldTypes[type], |
| 320 | + field; |
478 | 321 | |
479 | 322 | try { |
480 | 323 | field = new FieldConstructor( fieldDescription, options ); |
— | — | @@ -521,13 +364,14 @@ |
522 | 365 | { |
523 | 366 | text: mw.msg( 'gadgets-formbuilder-editor-ok' ), |
524 | 367 | click: function() { |
525 | | - var fieldDesc = $( this ).formBuilder( 'getDescription' ).fields[0]; |
| 368 | + var fieldDesc = $( this ).formBuilder( 'getDescription' ).fields[0], |
526 | 369 | name = fieldDesc.name; |
527 | 370 | |
528 | 371 | delete fieldDesc.name; |
529 | 372 | |
530 | 373 | $( this ).dialog( "close" ); |
531 | 374 | |
| 375 | + var ListField = validFieldTypes.list; |
532 | 376 | callback( new ListField( { |
533 | 377 | type: 'list', |
534 | 378 | name: name, |
— | — | @@ -546,73 +390,6 @@ |
547 | 391 | } ); |
548 | 392 | } |
549 | 393 | |
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 | | - |
617 | 394 | /* Basic interface for fields */ |
618 | 395 | function Field( desc, options ) { |
619 | 396 | if ( typeof options.idPrefix == 'undefined' ) { |
— | — | @@ -645,9 +422,11 @@ |
646 | 423 | }; |
647 | 424 | }; |
648 | 425 | |
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 | + **/ |
652 | 431 | function EmptyField( desc, options ) { |
653 | 432 | Field.call( this, desc, options ); |
654 | 433 | |
— | — | @@ -660,14 +439,14 @@ |
661 | 440 | .addClass( 'formbuilder-field formbuilder-field-' + this.desc.type ) |
662 | 441 | .data( 'field', this ); |
663 | 442 | } |
| 443 | + EmptyField.prototype = Object.create( Field.prototype ); |
| 444 | + EmptyField.prototype.constructor = EmptyField; |
664 | 445 | |
665 | 446 | EmptyField.prototype.getElement = function() { |
666 | 447 | return this.$div; |
667 | 448 | }; |
668 | 449 | |
669 | 450 | /* A field with just a label */ |
670 | | - LabelField.prototype = object( EmptyField.prototype ); |
671 | | - LabelField.prototype.constructor = LabelField; |
672 | 451 | function LabelField( desc, options ) { |
673 | 452 | EmptyField.call( this, desc, options ); |
674 | 453 | |
— | — | @@ -681,13 +460,13 @@ |
682 | 461 | |
683 | 462 | this.$div.append( this.$label ); |
684 | 463 | } |
| 464 | + LabelField.prototype = Object.create( EmptyField.prototype ); |
| 465 | + LabelField.prototype.constructor = LabelField; |
685 | 466 | |
686 | | - validFieldTypes["label"] = LabelField; |
| 467 | + validFieldTypes.label = LabelField; |
687 | 468 | |
688 | 469 | /* 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 ) { |
692 | 471 | LabelField.call( this, desc, options ); |
693 | 472 | |
694 | 473 | //Validate the 'name' member |
— | — | @@ -710,6 +489,8 @@ |
711 | 490 | this.options = options; |
712 | 491 | } |
713 | 492 | } |
| 493 | + SimpleField.prototype = Object.create( LabelField.prototype ); |
| 494 | + SimpleField.prototype.constructor = SimpleField; |
714 | 495 | |
715 | 496 | SimpleField.prototype.getDesc = function( useValuesAsDefaults ) { |
716 | 497 | var desc = clone( LabelField.prototype.getDesc.call( this, useValuesAsDefaults ) ); |
— | — | @@ -724,9 +505,7 @@ |
725 | 506 | |
726 | 507 | |
727 | 508 | /* 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 ) { |
731 | 510 | SimpleField.call( this, desc, options ); |
732 | 511 | |
733 | 512 | this.$c = $( '<input/>' ).attr( { |
— | — | @@ -737,7 +516,7 @@ |
738 | 517 | |
739 | 518 | if ( options.change ) { |
740 | 519 | this.$c.change( function() { |
741 | | - options.change() |
| 520 | + options.change(); |
742 | 521 | } ); |
743 | 522 | } |
744 | 523 | |
— | — | @@ -752,21 +531,21 @@ |
753 | 532 | |
754 | 533 | this.$div.append( this.$c ); |
755 | 534 | } |
| 535 | + BooleanField.prototype = Object.create( SimpleField.prototype ); |
| 536 | + BooleanField.prototype.constructor = BooleanField; |
756 | 537 | |
757 | 538 | BooleanField.prototype.getValues = function() { |
758 | 539 | return pair( this.desc.name, this.$c.is( ':checked' ) ); |
759 | 540 | }; |
760 | 541 | |
761 | | - validFieldTypes["boolean"] = BooleanField; |
| 542 | + validFieldTypes.boolean = BooleanField; |
762 | 543 | |
763 | 544 | /* 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 ) { |
767 | 546 | SimpleField.call( this, desc, options ); |
768 | 547 | |
769 | 548 | //Validate minlength and maxlength |
770 | | - var minlength = typeof desc.minlength != 'undefined' ? desc.minlength : 0, |
| 549 | + var minlength = typeof desc.minlength != 'undefined' ? desc.minlength : 0, |
771 | 550 | maxlength = typeof desc.maxlength != 'undefined' ? desc.maxlength : 1024; |
772 | 551 | |
773 | 552 | if ( !isInteger( minlength ) || minlength < 0 ) { |
— | — | @@ -801,6 +580,8 @@ |
802 | 581 | |
803 | 582 | this.$div.append( this.$text ); |
804 | 583 | } |
| 584 | + StringField.prototype = Object.create( SimpleField.prototype ); |
| 585 | + StringField.prototype.constructor = StringField; |
805 | 586 | |
806 | 587 | StringField.prototype.getValues = function() { |
807 | 588 | return pair( this.desc.name, this.$text.val() ); |
— | — | @@ -835,21 +616,19 @@ |
836 | 617 | return settings; |
837 | 618 | }; |
838 | 619 | |
839 | | - validFieldTypes["string"] = StringField; |
| 620 | + validFieldTypes.string = StringField; |
840 | 621 | |
841 | 622 | |
842 | 623 | /* 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 ) { |
846 | 625 | SimpleField.call( this, desc, options ); |
847 | 626 | |
848 | 627 | //Validation of description |
849 | 628 | if ( desc.integer === true ) { |
850 | | - if ( typeof desc.min != 'undefined' && !isInteger( desc.min ) ){ |
| 629 | + if ( typeof desc.min != 'undefined' && !isInteger( desc.min ) ) { |
851 | 630 | $.error( "min is not an integer" ); |
852 | 631 | } |
853 | | - if ( typeof desc.max != 'undefined' && !isInteger( desc.max ) ){ |
| 632 | + if ( typeof desc.max != 'undefined' && !isInteger( desc.max ) ) { |
854 | 633 | $.error( "max is not an integer" ); |
855 | 634 | } |
856 | 635 | } |
— | — | @@ -881,6 +660,8 @@ |
882 | 661 | |
883 | 662 | this.$div.append( this.$text ); |
884 | 663 | } |
| 664 | + NumberField.prototype = Object.create( SimpleField.prototype ); |
| 665 | + NumberField.prototype.constructor = NumberField; |
885 | 666 | |
886 | 667 | NumberField.prototype.getValues = function() { |
887 | 668 | var val = parseFloat( this.$text.val() ); |
— | — | @@ -922,12 +703,10 @@ |
923 | 704 | return settings; |
924 | 705 | }; |
925 | 706 | |
926 | | - validFieldTypes["number"] = NumberField; |
| 707 | + validFieldTypes.number = NumberField; |
927 | 708 | |
928 | 709 | /* 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 ) { |
932 | 711 | SimpleField.call( this, desc, options ); |
933 | 712 | |
934 | 713 | var $select = this.$select = $( '<select/>' ).attr( { |
— | — | @@ -935,8 +714,8 @@ |
936 | 715 | name: this.options.idPrefix + this.desc.name |
937 | 716 | } ); |
938 | 717 | |
939 | | - var validValues = []; |
940 | | - var self = this; |
| 718 | + var validValues = [], |
| 719 | + self = this; |
941 | 720 | $.each( this.desc.options, function( idx, option ) { |
942 | 721 | var i = validValues.length; |
943 | 722 | $( '<option/>' ) |
— | — | @@ -967,18 +746,18 @@ |
968 | 747 | |
969 | 748 | this.$div.append( $select ); |
970 | 749 | } |
| 750 | + SelectField.prototype = Object.create( SimpleField.prototype ); |
| 751 | + SelectField.prototype.constructor = SelectField; |
971 | 752 | |
972 | 753 | SelectField.prototype.getValues = function() { |
973 | 754 | var i = parseInt( this.$select.val(), 10 ); |
974 | 755 | return pair( this.desc.name, this.validValues[i] ); |
975 | 756 | }; |
976 | 757 | |
977 | | - validFieldTypes["select"] = SelectField; |
| 758 | + validFieldTypes.select = SelectField; |
978 | 759 | |
979 | 760 | /* 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 ) { |
983 | 762 | SimpleField.call( this, desc, options ); |
984 | 763 | |
985 | 764 | //Validation |
— | — | @@ -1065,11 +844,13 @@ |
1066 | 845 | }, 1 ); |
1067 | 846 | }, |
1068 | 847 | stop: function( event, ui ) { |
| 848 | + //After a delay, hide tooltip if the handle doesn't have focus and pointer isn't over the handle. |
1069 | 849 | setTimeout( function() { |
1070 | | - if ( !$handle.is( ':focus' ) && !mouseOver) { |
| 850 | + if ( !$slider.find( '.ui-slider-handle' ).is( ':focus' ) && !mouseOver ) { |
1071 | 851 | refreshTooltip( false, $slider.find( '.ui-slider-handle' ), ui.value ); |
1072 | 852 | } |
1073 | 853 | }, 300 ); |
| 854 | + |
1074 | 855 | sliding = false; |
1075 | 856 | }, |
1076 | 857 | change: function( event, ui ) { |
— | — | @@ -1103,17 +884,17 @@ |
1104 | 885 | |
1105 | 886 | this.$div.append( $slider ); |
1106 | 887 | } |
| 888 | + RangeField.prototype = Object.create( SimpleField.prototype ); |
| 889 | + RangeField.prototype.constructor = RangeField; |
1107 | 890 | |
1108 | 891 | RangeField.prototype.getValues = function() { |
1109 | 892 | return pair( this.desc.name, this.$slider.slider( 'value' ) ); |
1110 | 893 | }; |
1111 | 894 | |
1112 | | - validFieldTypes["range"] = RangeField; |
| 895 | + validFieldTypes.range = RangeField; |
1113 | 896 | |
1114 | 897 | /* 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 ) { |
1118 | 899 | SimpleField.call( this, desc, options ); |
1119 | 900 | |
1120 | 901 | var $text = this.$text = $( '<input/>' ) |
— | — | @@ -1130,8 +911,8 @@ |
1131 | 912 | } |
1132 | 913 | } ); |
1133 | 914 | |
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; |
1136 | 917 | if ( typeof value != 'undefined' && value !== null ) { |
1137 | 918 | date = new Date( value ); |
1138 | 919 | |
— | — | @@ -1149,9 +930,11 @@ |
1150 | 931 | |
1151 | 932 | this.$div.append( this.$text ); |
1152 | 933 | } |
| 934 | + DateField.prototype = Object.create( SimpleField.prototype ); |
| 935 | + DateField.prototype.constructor = DateField; |
1153 | 936 | |
1154 | 937 | DateField.prototype.getValues = function() { |
1155 | | - var d = this.$text.datepicker( 'getDate' ), |
| 938 | + var d = this.$text.datepicker( 'getDate' ), |
1156 | 939 | res = {}; |
1157 | 940 | |
1158 | 941 | if ( d === null ) { |
— | — | @@ -1178,7 +961,7 @@ |
1179 | 962 | return settings; |
1180 | 963 | }; |
1181 | 964 | |
1182 | | - validFieldTypes["date"] = DateField; |
| 965 | + validFieldTypes.date = DateField; |
1183 | 966 | |
1184 | 967 | /* A field with color picker */ |
1185 | 968 | |
— | — | @@ -1191,16 +974,15 @@ |
1192 | 975 | //If a click happens outside the colorpicker while it is showed, remove it |
1193 | 976 | $( document ).mousedown( function( event ) { |
1194 | 977 | var $target = $( event.target ); |
1195 | | - if ( $target.parents( '#colorpicker' ).length == 0 ) { |
| 978 | + if ( $target.parents( '#colorpicker' ).length === 0 ) { |
1196 | 979 | closeColorPicker(); |
1197 | 980 | } |
1198 | 981 | } ); |
1199 | 982 | |
1200 | | - ColorField.prototype = object( SimpleField.prototype ); |
1201 | | - ColorField.prototype.constructor = ColorField; |
1202 | | - function ColorField( desc, options ){ |
| 983 | + function ColorField( desc, options ) { |
1203 | 984 | SimpleField.call( this, desc, options ); |
1204 | 985 | |
| 986 | + var value; |
1205 | 987 | if ( typeof options.values != 'undefined' && typeof options.values[this.desc.name] != 'undefined' ) { |
1206 | 988 | value = options.values[this.desc.name]; |
1207 | 989 | } else { |
— | — | @@ -1252,6 +1034,8 @@ |
1253 | 1035 | |
1254 | 1036 | this.$div.append( this.$text ); |
1255 | 1037 | } |
| 1038 | + ColorField.prototype = Object.create( SimpleField.prototype ); |
| 1039 | + ColorField.prototype.constructor = ColorField; |
1256 | 1040 | |
1257 | 1041 | ColorField.prototype.getValidationSettings = function() { |
1258 | 1042 | var settings = SimpleField.prototype.getValidationSettings.call( this ), |
— | — | @@ -1273,13 +1057,11 @@ |
1274 | 1058 | } |
1275 | 1059 | }; |
1276 | 1060 | |
1277 | | - validFieldTypes["color"] = ColorField; |
| 1061 | + validFieldTypes.color = ColorField; |
1278 | 1062 | |
1279 | 1063 | |
1280 | 1064 | /* A field that represent a section (group of fields) */ |
1281 | 1065 | |
1282 | | - SectionField.prototype = object( Field.prototype ); |
1283 | | - SectionField.prototype.constructor = SectionField; |
1284 | 1066 | function SectionField( desc, options, id ) { |
1285 | 1067 | Field.call( this, desc, options ); |
1286 | 1068 | |
— | — | @@ -1295,7 +1077,7 @@ |
1296 | 1078 | this._createSlot( 'yes' ).appendTo( this.$div ); |
1297 | 1079 | } |
1298 | 1080 | |
1299 | | - var field = this.desc.fields[i], |
| 1081 | + var field = this.desc.fields[i], |
1300 | 1082 | FieldConstructor = validFieldTypes[field.type]; |
1301 | 1083 | |
1302 | 1084 | if ( typeof FieldConstructor != 'function' ) { |
— | — | @@ -1309,7 +1091,7 @@ |
1310 | 1092 | editable = 'no'; |
1311 | 1093 | } |
1312 | 1094 | |
1313 | | - var f = new FieldConstructor( field, options ), |
| 1095 | + var f = new FieldConstructor( field, options ), |
1314 | 1096 | $slot = this._createSlot( editable, f ); |
1315 | 1097 | |
1316 | 1098 | $slot.appendTo( this.$div ); |
— | — | @@ -1320,6 +1102,8 @@ |
1321 | 1103 | this._createSlot( 'yes' ).appendTo( this.$div ); |
1322 | 1104 | } |
1323 | 1105 | } |
| 1106 | + SectionField.prototype = Object.create( Field.prototype ); |
| 1107 | + SectionField.prototype.constructor = SectionField; |
1324 | 1108 | |
1325 | 1109 | SectionField.prototype.getElement = function() { |
1326 | 1110 | return this.$div; |
— | — | @@ -1379,7 +1163,7 @@ |
1380 | 1164 | }; |
1381 | 1165 | |
1382 | 1166 | SectionField.prototype._createSlot = function( editable, field ) { |
1383 | | - var self = this, |
| 1167 | + var self = this, |
1384 | 1168 | $slot = $( '<div/>' ).addClass( 'formbuilder-slot ui-widget' ), |
1385 | 1169 | $divButtons; |
1386 | 1170 | |
— | — | @@ -1413,7 +1197,7 @@ |
1414 | 1198 | //Add the button for changing existing slots |
1415 | 1199 | var type = field.getDesc().type; |
1416 | 1200 | //TODO: using the 'builder' info is not optimal |
1417 | | - if ( typeof prefsDescriptionSpecifications[type].builder != 'function' ) { |
| 1201 | + if ( typeof prefsSpecifications[type].builder != 'function' ) { |
1418 | 1202 | $( '<a href="javascript:;" />' ) |
1419 | 1203 | .addClass( 'formbuilder-button formbuilder-editor-button-edit ui-icon ui-icon-gear' ) |
1420 | 1204 | .attr( 'title', mw.msg( 'gadgets-formbuilder-editor-edit-field' ) ) |
— | — | @@ -1425,7 +1209,7 @@ |
1426 | 1210 | callback: function( newField ) { |
1427 | 1211 | if ( newField !== null ) { |
1428 | 1212 | //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' ), |
1430 | 1214 | removedValues = field.getValues(), |
1431 | 1215 | duplicateName = null; |
1432 | 1216 | $.each( field.getValues(), function( name, val ) { |
— | — | @@ -1463,13 +1247,13 @@ |
1464 | 1248 | .addClass( 'formbuilder-button formbuilder-editor-button-delete ui-icon ui-icon-trash' ) |
1465 | 1249 | .attr( 'title', mw.msg( 'gadgets-formbuilder-editor-delete-field' ) ) |
1466 | 1250 | .click( function( event, ui ) { |
1467 | | - //Make both slots disappear, then delete them |
| 1251 | + //Make both slots disappear, then delete them |
1468 | 1252 | $.each( [$slot, $slot.prev()], function( idx, $s ) { |
1469 | 1253 | $s.slideUp( function() { |
1470 | 1254 | self._deleteSlot( $s ); |
1471 | 1255 | } ); |
1472 | 1256 | } ); |
1473 | | - } ) |
| 1257 | + } ) |
1474 | 1258 | .appendTo( $divButtons ); |
1475 | 1259 | |
1476 | 1260 | //Make this slot draggable to allow moving it |
— | — | @@ -1495,7 +1279,8 @@ |
1496 | 1280 | hoverClass: 'formbuilder-slot-can-drop', |
1497 | 1281 | tolerance: 'pointer', |
1498 | 1282 | drop: function( event, ui ) { |
1499 | | - var srcSlot = ui.draggable, dstSlot = this; |
| 1283 | + var srcSlot = ui.draggable, |
| 1284 | + dstSlot = this; |
1500 | 1285 | |
1501 | 1286 | //Remove one empty slot surrounding source |
1502 | 1287 | $( srcSlot ).prev().remove(); |
— | — | @@ -1524,7 +1309,7 @@ |
1525 | 1310 | callback: function( field ) { |
1526 | 1311 | if ( field !== null ) { |
1527 | 1312 | //check that there are no duplicate preference names |
1528 | | - var existingValues = $slot.closest( '.formbuilder' ).formBuilder( 'getValues' ), |
| 1313 | + var existingValues = $slot.closest( '.formbuilder' ).formBuilder( 'getValues' ), |
1529 | 1314 | duplicateName = null; |
1530 | 1315 | $.each( field.getValues(), function( name, val ) { |
1531 | 1316 | if ( typeof existingValues[name] != 'undefined' ) { |
— | — | @@ -1538,7 +1323,7 @@ |
1539 | 1324 | return false; |
1540 | 1325 | } |
1541 | 1326 | |
1542 | | - var $newSlot = self._createSlot( 'yes', field ).hide(), |
| 1327 | + var $newSlot = self._createSlot( 'yes', field ).hide(), |
1543 | 1328 | $newEmptySlot = self._createSlot( 'yes' ).hide(); |
1544 | 1329 | |
1545 | 1330 | $slot.after( $newSlot, $newEmptySlot ); |
— | — | @@ -1563,9 +1348,7 @@ |
1564 | 1349 | }; |
1565 | 1350 | |
1566 | 1351 | |
1567 | | - /* A field for 'bundle's */ |
1568 | | - BundleField.prototype = object( EmptyField.prototype ); |
1569 | | - BundleField.prototype.constructor = BundleField; |
| 1352 | + /* A field for 'bundle' type fields */ |
1570 | 1353 | function BundleField( desc, options ) { |
1571 | 1354 | EmptyField.call( this, desc, options ); |
1572 | 1355 | |
— | — | @@ -1583,7 +1366,7 @@ |
1584 | 1367 | tolerance: 'pointer', |
1585 | 1368 | accept: '.formbuilder-slot-nonempty', |
1586 | 1369 | drop: function( event, ui ) { |
1587 | | - var $slot = $( ui.draggable ), |
| 1370 | + var $slot = $( ui.draggable ), |
1588 | 1371 | $srcSection = $slot.parent(), |
1589 | 1372 | $dstSection = $( section ); |
1590 | 1373 | |
— | — | @@ -1622,7 +1405,7 @@ |
1623 | 1406 | .addClass( 'formbuilder-button formbuilder-editor-button-edit-section ui-icon ui-icon-gear' ) |
1624 | 1407 | .attr( 'title', mw.msg( 'gadgets-formbuilder-editor-edit-section' ) ) |
1625 | 1408 | .click( function() { |
1626 | | - var button = this, |
| 1409 | + var button = this, |
1627 | 1410 | sectionField = $( ui.panel ).data( 'field' ); |
1628 | 1411 | |
1629 | 1412 | $( { |
— | — | @@ -1673,15 +1456,15 @@ |
1674 | 1457 | } ); |
1675 | 1458 | |
1676 | 1459 | //Save for future reference |
1677 | | - this.$ui_tabs_nav = $tabs.find( '.ui-tabs-nav' ) |
| 1460 | + this.$ui_tabs_nav = $tabs.find( '.ui-tabs-nav' ); |
1678 | 1461 | |
1679 | 1462 | var self = this; |
1680 | 1463 | $.each( this.desc.sections, function( index, sectionDescription ) { |
1681 | | - var id = self.options.idPrefix + 'section-' + getIncrementalCounter(), |
| 1464 | + var id = self.options.idPrefix + 'section-' + getIncrementalCounter(), |
1682 | 1465 | sec = new SectionField( sectionDescription, options, id ); |
1683 | 1466 | |
1684 | 1467 | $tabs.append( sec.getElement() ) |
1685 | | - .tabs( 'add', '#' + id, preproc( options.msgPrefix, sectionDescription.title ) ); |
| 1468 | + .tabs( 'add', '#' + id, preproc( options.msgPrefix, sectionDescription.title ) ); |
1686 | 1469 | } ); |
1687 | 1470 | |
1688 | 1471 | if ( options.editable === true ) { |
— | — | @@ -1707,7 +1490,7 @@ |
1708 | 1491 | { |
1709 | 1492 | text: mw.msg( 'gadgets-formbuilder-editor-ok' ), |
1710 | 1493 | click: function() { |
1711 | | - var title = $( this ).formBuilder( 'getValues' ).title, |
| 1494 | + var title = $( this ).formBuilder( 'getValues' ).title, |
1712 | 1495 | id = self.options.idPrefix + 'section-' + getIncrementalCounter(), |
1713 | 1496 | newSectionDescription = { |
1714 | 1497 | title: title, |
— | — | @@ -1742,11 +1525,13 @@ |
1743 | 1526 | |
1744 | 1527 | this.$div.append( $tabs ); |
1745 | 1528 | } |
| 1529 | + BundleField.prototype = Object.create( EmptyField.prototype ); |
| 1530 | + BundleField.prototype.constructor = BundleField; |
1746 | 1531 | |
1747 | 1532 | BundleField.prototype.getValidationSettings = function() { |
1748 | 1533 | var settings = {}; |
1749 | 1534 | this.$ui_tabs_nav.find( 'a' ).each( function( idx, anchor ) { |
1750 | | - var panel = $( anchor ).data( 'panel' ), |
| 1535 | + var panel = $( anchor ).data( 'panel' ), |
1751 | 1536 | field = $( panel ).data( 'field' ); |
1752 | 1537 | |
1753 | 1538 | $.extend( true, settings, field.getValidationSettings() ); |
— | — | @@ -1758,7 +1543,7 @@ |
1759 | 1544 | var desc = clone( this.desc ); |
1760 | 1545 | desc.sections = []; |
1761 | 1546 | this.$ui_tabs_nav.find( 'a' ).each( function( idx, anchor ) { |
1762 | | - var panel = $( anchor ).data( 'panel' ), |
| 1547 | + var panel = $( anchor ).data( 'panel' ), |
1763 | 1548 | field = $( panel ).data( 'field' ); |
1764 | 1549 | |
1765 | 1550 | desc.sections.push( field.getDesc( useValuesAsDefaults ) ); |
— | — | @@ -1769,7 +1554,7 @@ |
1770 | 1555 | BundleField.prototype.getValues = function() { |
1771 | 1556 | var values = {}; |
1772 | 1557 | this.$ui_tabs_nav.find( 'a' ).each( function( idx, anchor ) { |
1773 | | - var panel = $( anchor ).data( 'panel' ), |
| 1558 | + var panel = $( anchor ).data( 'panel' ), |
1774 | 1559 | field = $( panel ).data( 'field' ); |
1775 | 1560 | |
1776 | 1561 | $.extend( values, field.getValues() ); |
— | — | @@ -1777,13 +1562,11 @@ |
1778 | 1563 | return values; |
1779 | 1564 | }; |
1780 | 1565 | |
1781 | | - validFieldTypes["bundle"] = BundleField; |
| 1566 | + validFieldTypes.bundle = BundleField; |
1782 | 1567 | |
1783 | 1568 | |
1784 | 1569 | /* A field for 'composite' fields */ |
1785 | 1570 | |
1786 | | - CompositeField.prototype = object( EmptyField.prototype ); |
1787 | | - CompositeField.prototype.constructor = CompositeField; |
1788 | 1571 | function CompositeField( desc, options ) { |
1789 | 1572 | EmptyField.call( this, desc, options ); |
1790 | 1573 | |
— | — | @@ -1811,6 +1594,8 @@ |
1812 | 1595 | this._section = new SectionField( desc, sectionOptions ); |
1813 | 1596 | this.$div.append( this._section.getElement() ); |
1814 | 1597 | } |
| 1598 | + CompositeField.prototype = Object.create( EmptyField.prototype ); |
| 1599 | + CompositeField.prototype.constructor = CompositeField; |
1815 | 1600 | |
1816 | 1601 | CompositeField.prototype.getDesc = function( useValuesAsDefaults ) { |
1817 | 1602 | var desc = clone( this.desc ); |
— | — | @@ -1826,12 +1611,10 @@ |
1827 | 1612 | return this._section.getValidationSettings(); |
1828 | 1613 | }; |
1829 | 1614 | |
1830 | | - validFieldTypes["composite"] = CompositeField; |
| 1615 | + validFieldTypes.composite = CompositeField; |
1831 | 1616 | |
1832 | 1617 | /* A field for 'composite' fields */ |
1833 | 1618 | |
1834 | | - ListField.prototype = object( EmptyField.prototype ); |
1835 | | - ListField.prototype.constructor = ListField; |
1836 | 1619 | function ListField( desc, options ) { |
1837 | 1620 | EmptyField.call( this, desc, options ); |
1838 | 1621 | |
— | — | @@ -1844,7 +1627,7 @@ |
1845 | 1628 | } |
1846 | 1629 | |
1847 | 1630 | if ( ( typeof desc.field.type != 'string' ) |
1848 | | - || prefsDescriptionSpecifications[desc.field.type].simple !== true ) |
| 1631 | + || prefsSpecifications[desc.field.type].simple !== true ) |
1849 | 1632 | { |
1850 | 1633 | $.error( "Missing or invalid field type specified in 'field' parameter." ); |
1851 | 1634 | } |
— | — | @@ -1855,8 +1638,8 @@ |
1856 | 1639 | options.values = {}; |
1857 | 1640 | } |
1858 | 1641 | |
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; |
1861 | 1644 | if ( typeof value != 'undefined' ) { |
1862 | 1645 | $.each( value, function( index, itemValue ) { |
1863 | 1646 | self._createItem( false, itemValue ); |
— | — | @@ -1880,12 +1663,14 @@ |
1881 | 1664 | } ) |
1882 | 1665 | .appendTo( this.$div ); |
1883 | 1666 | } |
| 1667 | + ListField.prototype = Object.create( EmptyField.prototype ); |
| 1668 | + ListField.prototype.constructor = ListField; |
1884 | 1669 | |
1885 | 1670 | ListField.prototype._createItem = function( animated, itemValue ) { |
1886 | | - var itemDesc = $.extend( {}, this.desc.field, { |
| 1671 | + var itemDesc = $.extend( {}, this.desc.field, { |
1887 | 1672 | "name": this.desc.name |
1888 | | - } ); |
1889 | | - var itemOptions = $.extend( {}, this.options, { |
| 1673 | + } ), |
| 1674 | + itemOptions = $.extend( {}, this.options, { |
1890 | 1675 | editable: false, |
1891 | 1676 | idPrefix: this.options.idPrefix + getIncrementalCounter() + "-" |
1892 | 1677 | } ); |
— | — | @@ -1896,15 +1681,14 @@ |
1897 | 1682 | itemOptions.values = pair( this.desc.name, this.desc.field['default'] ); |
1898 | 1683 | } |
1899 | 1684 | |
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() ); |
1909 | 1693 | |
1910 | 1694 | $( '<div/>' ) |
1911 | 1695 | .addClass( 'formbuilder-list-item-container' ) |
— | — | @@ -1974,9 +1758,244 @@ |
1975 | 1759 | return validationSettings; |
1976 | 1760 | }; |
1977 | 1761 | |
1978 | | - validFieldTypes["list"] = ListField; |
| 1762 | + validFieldTypes.list = ListField; |
1979 | 1763 | |
1980 | 1764 | |
| 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 | + |
1981 | 2000 | /* Public methods */ |
1982 | 2001 | |
1983 | 2002 | /** |
— | — | @@ -2072,5 +2091,5 @@ |
2073 | 2092 | $.error( 'Method ' + method + ' does not exist on jQuery.formBuilder' ); |
2074 | 2093 | } |
2075 | 2094 | }; |
2076 | | -})( jQuery, mediaWiki ); |
| 2095 | +} )( jQuery, mediaWiki ); |
2077 | 2096 | |